Example #1
0
 /**
  * @constructor
  *
  * @param {array}  $rules Redirect rules
  * @param {callable|string} $rules[][source] Regex, plain string startsWith() or callback matcher func,
  * @param {string} $rules[][target] String for redirection, can use backreference on regex,
  * @param {?int}   $rules[][options] Redirection $options, or internal by default,
  * @param {?string} $options[source] Base path to match against requests, defaults to root.
  * @param {string|callable} $options[target] Redirects to a static target, or function($request) returns a string;
  */
 public function __construct($rules)
 {
     // rewrite all URLs
     if (is_string($rules)) {
         $rules = array('*' => $rules);
     }
     $rules = util::wrapAssoc($rules);
     $this->rules = array_reduce($rules, function ($result, $rule) {
         $rule = array_select($rule, array('source', 'target', 'options'));
         // note: make sure source is callback
         if (is_string($rule['source'])) {
             // regex
             if (@preg_match($rule['source'], null) !== false) {
                 $rule['source'] = matches($rule['source']);
                 if (is_string($rule['target'])) {
                     $rule['target'] = compose(invokes('uri', array('path')), replaces($rule['source'], $rule['target']));
                 }
             } else {
                 if (!is_callable($rule['source'])) {
                     $rule['source'] = startsWith($rule['source']);
                     if (is_string($rule['target'])) {
                         $rule['target'] = compose(invokes('uri', array('path')), replaces('/^' . preg_quote($rule['source']) . '/', $rule['target']));
                     }
                 }
             }
         }
         if (!is_callable($rule['source'])) {
             throw new InvalidArgumentException('Source must be string, regex or callable.');
         }
         $result[] = $rule;
         return $result;
     }, array());
 }
Example #2
0
 /**
  * @protected
  *
  * Delete all relations.
  */
 function afterDelete()
 {
     // Delete jobs
     array_map(invokes('delete'), $this->getInstances());
     return parent::afterDelete();
 }
Example #3
0
 /**
  * Process next task with POST data.
  */
 public function process()
 {
     // note: Some tasks can work without post data, but request method must be POST.
     if (!$this->__isSuperUser && $this->__request->method() != 'post') {
         $this->__response->status(405);
         // Method not allowed
         return;
     }
     // WorkInstance
     if (!$this->identity()) {
         $this->__response->status(404);
         // WorkInstance not found
         return;
     }
     // TaskInstance
     $instance = $this->nextTask();
     if (!$instance) {
         $this->__response->status(404);
         // TaskInstance not foudn
         return;
     }
     // release mutable lock for work instance initialization.
     $this->_immutable = false;
     // remove tasks to prevent unwanted change.
     $tasks = $this->tasks;
     unset($this->tasks);
     // creates $this->dataStore if not yet.
     if (empty($this->dataStore)) {
         $this->dataStore = array();
     }
     unset($this->lastError);
     // immutable marker to prevent direct modifications to the internal data.
     $this->_immutable = true;
     // note: Send bayeux message to groups with permission to this task.
     $userGroups = $instance->userGroups();
     try {
         // Note: Since $this->dataStore is an array, it is mutable itself.
         $promise = $instance->process();
     } catch (\Exception $e) {
         Log::warning('Task process exception.', array_filter(array('message' => $e->getMessage(), 'code' => $e->getCode(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'trace' => $e->getTrace())));
         $lastError = array('message' => $this->__response->__($e->getMessage()), 'code' => $e->getCode());
         // note: Failure on Headless tasks will revert to previous task.
         if (@$instance->type == 'Headless') {
             $deferred = new Deferred();
             $deferred->reject($lastError['message'], $lastError['code']);
             $promise = $deferred->promise();
             unset($deferred);
         } else {
             $this->_immutable = false;
             $this->lastError = $lastError;
         }
         unset($lastError);
     }
     $this->_immutable = false;
     $result = array();
     $saveFunc = function () use(&$result) {
         unset($this->timestamp);
         $this->save($result);
     };
     if (isset($promise)) {
         // note: rejection here means revert to previous task
         $promise->fail(function ($error, $code = null) use($instance, $tasks) {
             $this->lastError = array_filter(array('message' => $error, 'code' => $code));
             // revert to previous task
             $prevTask = array_search($instance->identity(), array_map(invokes('identity'), $tasks));
             $prevTask = @$tasks[$prevTask - 1];
             // fallback to the first task
             if (!$prevTask) {
                 $prevTask = reset($tasks);
             }
             $this->nextTask = util::packUuid($prevTask->identity());
         });
         // note: resolution always advances to next task
         $promise->done(function () use($instance, $tasks) {
             $nextTask = array_search($instance->identity(), array_map(invokes('identity'), $tasks));
             $nextTask = @$tasks[$nextTask + 1];
             if ($nextTask) {
                 $this->nextTask = util::packUuid($nextTask->identity());
             } else {
                 $this->state = static::STATE_CLOSE;
                 $this->nextTask = null;
             }
         });
         // note: controller script must call resolve() or reject() to make this happen.
         $promise->always($saveFunc);
     } else {
         $saveFunc();
     }
     unset($saveFunc);
     // note: Merge user groups before and after task processing
     if ($this->nextTask) {
         $userGroups = array_unique(array_merge($userGroups, $this->nextTask()->userGroups()));
     }
     foreach ($userGroups as $userGroup) {
         Bayeux::sendMessage("/group/{$userGroup}", array('action' => 'update', '@collection' => 'WorkInstance', 'timestamp' => $this->timestamp));
     }
     if (@$result['error']) {
         $this->__response->status(500);
         return $result;
     } else {
         // note; User might no longer has access to the updated work instance.
         if ($this->data()) {
             $this->__response->status(200);
             return $this;
         } else {
             $this->__response->status(204);
         }
     }
 }