Example #1
0
 /**
  * Builds a new child and returns it.
  *
  * The child will have all the before functions from its parent.
  * It will also inherit of the prefix from its parent.
  *
  * @return RoutesCollection
  */
 public function newChild($prefix = '')
 {
     $c = new RoutesCollection($prefix);
     $c->before(function ($scope) {
         foreach ($this->globalBefores as $b) {
             $scope->call($b);
             if ($scope->isRightResource === false) {
                 return;
             }
             if ($scope->stopRoute === true) {
                 return;
             }
         }
     });
     $this->children[] = $c;
     $c->parent = $this;
     return $c;
 }
Example #2
0
 /**
  * Parses a class and registers all resources defined in it.
  *
  * This function will analyse the comments of each method of the class and create the appropriate routes.
  * The routes are created in a child RoutesCollection that is returned by this function.
  *
  * Recognized tokens are:
  *  - @before (both) See description below
  *  - @disabled (route only) This route is not created
  *  - @method (route only) Pattern of the method to match
  *  - @name (route only) Name of the route
  *  - @pattern (route only) Sets the regex pattern of the part of a URL
  *  - @prefix (class only) Sets the prefix of the RoutesCollection ; can be overwritten by calling RoutesCollection->prefix()
  *  - @static (class only) Adds a path of static resources ; path is relative to the class location
  *  - @url (route only) Pattern of the URL to match, see register()
  *  - @uri (route only) Alias of @url
  *
  * The first before function of the new route collection will create an instance of the class and put it in $scope->this.
  * 
  * The @before token has several possible syntaxes:
  *  - @before {global_function}
  *		where {global_function} is the name of a global function to be called before the handler
  *  - @before {method}
  *		where {method} is the name of a method of the current class to be called before the handler
  *  - @before {class}
  *		where {class} is a class name
  *		the before function will simply invoke the given class and do nothing
  *  - @before {class}::{method} {params}
  *		where {class} is a class name, {method} is the name of a method of the class, and {params} can be eval'd as a PHP array
  *		the before function will try to find in the scope an object whose type is the class, and call the method on it
  *  - @before function({params}) { {php code} }
  *		the function and code will be evaled as a PHP closure
  *  - @before onlyif {anything}
  *		where {anything} can be any of the other syntaxes above, and {code} is a status code
  *		if the "anything part" returns false, then the route is considered not to match and another route will be tried (isRightResource is set to false)
  *  - @before validate {code} {anything}
  *		where {anything} can be any of the other syntaxes above, and {code} is a status code
  *		if the "anything part" returns false, then the route is stopped and the status code is set to the response (stopRoute is set to true)
  *  - @before ${varName} = {anything}
  *		where {anything} can be any of the other syntaxes above, and {varName} is a status code
  *		the variable $varName of the scope will be set to the return value of the "anything part"
  *
  * @param ReflectionClass 	$reflectionClass 		The class to parse
  * @param RoutesCollection 	$parent 				The parent of the collection that will be created
  * @return RoutesCollection
  */
 public function parseClass(\ReflectionClass $reflectionClass, RoutesCollection $parent)
 {
     // building the new collection
     $newCollection = $parent->newChild();
     $newCollection->before(function (Scope $scope) use($reflectionClass) {
         $scope->this = $scope->call($reflectionClass);
     });
     // analyzing the doccomment of the class
     $classDocComment = self::parseDocComment($reflectionClass->getDocComment());
     // handling @before
     if (isset($classDocComment['before'])) {
         foreach ($classDocComment['before'] as $before) {
             $newCollection->before(self::buildBeforeFunction($reflectionClass, $before));
         }
     }
     // handling @prefix
     if (isset($classDocComment['prefix'])) {
         $newCollection->prefix(implode($classDocComment['prefix']));
     }
     // handling @static
     if (isset($classDocComment['static'])) {
         foreach ($classDocComment['static'] as $path) {
             $newCollection->registerStaticDirectory(dirname($reflectionClass->getFileName()) . DIRECTORY_SEPARATOR . $path)->name($reflectionClass->getName());
         }
     }
     // looping through each method of the class
     foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $methodReflection) {
         if (!($comment = $methodReflection->getDocComment())) {
             continue;
         }
         $parameters = self::parseDocComment($comment);
         // now analyzing parameters
         if (isset($parameters['url']) || isset($parameters['name'])) {
             if (isset($parameters['disabled'])) {
                 continue;
             }
             // building the route
             if (isset($parameters['url'])) {
                 $route = $newCollection->register($parameters['url']);
             } else {
                 $route = $newCollection->register();
             }
             // setting name of the route
             if (isset($parameters['name'])) {
                 if (count($parameters['name']) > 1) {
                     throw new \LogicException('A route cannot have multiple names');
                 }
                 $route->name($parameters['name'][0]);
             } else {
                 $route->name($reflectionClass->getName() . '::' . $methodReflection->getName());
             }
             // setting the method
             if (isset($parameters['method'])) {
                 $route->method($parameters['method'][0]);
             }
             // setting the pattern of the URL parts
             if (isset($parameters['pattern'])) {
                 foreach ($parameters['pattern'] as $p => $value) {
                     list($part, $val) = explode(' ', $value, 2);
                     $route->pattern($part, $val);
                 }
             }
             // setting the handler
             $route->handler(function (Scope $scope) use($methodReflection, $reflectionClass) {
                 return $scope->call($methodReflection->getClosure($scope->this));
             });
             // setting the before functions
             if (isset($parameters['before'])) {
                 foreach ($parameters['before'] as $before) {
                     $route->before(self::buildBeforeFunction($reflectionClass, $before));
                 }
             }
         }
     }
     return $newCollection;
 }