Ubiquity  2.0.3
php rapid development framework
ControllerParser.php
Go to the documentation of this file.
1 <?php
2 
4 
9 
12  private $mainRouteClass;
13  private $routesMethods=[ ];
14  private $rest=false;
15  private static $excludeds=[ "__construct","isValid","initialize","finalize","onInvalidControl","loadView","forward","redirectToRoute" ];
16 
17  public function parse($controllerClass) {
18  $automated=false;
19  $inherited=false;
20  $this->controllerClass=$controllerClass;
21  $reflect=new \ReflectionClass($controllerClass);
22  if (!$reflect->isAbstract() && $reflect->isSubclassOf("Ubiquity\controllers\Controller")) {
23  $instance=new $controllerClass();
24  $annotsClass=Reflexion::getAnnotationClass($controllerClass, "@route");
25  $restAnnotsClass=Reflexion::getAnnotationClass($controllerClass, "@rest");
26  $this->rest=\sizeof($restAnnotsClass) > 0;
27  if (\sizeof($annotsClass) > 0) {
28  $this->mainRouteClass=$annotsClass[0];
29  $inherited=$this->mainRouteClass->inherited;
30  $automated=$this->mainRouteClass->automated;
31  }
32  $methods=Reflexion::getMethods($instance, \ReflectionMethod::IS_PUBLIC);
33  foreach ( $methods as $method ) {
34  if ($method->getDeclaringClass()->getName() === $controllerClass || $inherited) {
35  $annots=Reflexion::getAnnotationsMethod($controllerClass, $method->name, "@route");
36  if ($annots !== false) {
37  foreach ( $annots as $annot ) {
38  if (UString::isNull($annot->path)) {
39  $newAnnot=$this->generateRouteAnnotationFromMethod($method);
40  $annot->path=$newAnnot[0]->path;
41  }
42  }
43  $this->routesMethods[$method->name]=[ "annotations" => $annots,"method" => $method ];
44  } else {
45  if ($automated) {
46  if ($method->class !== 'Ubiquity\\controllers\\Controller' && \array_search($method->name, self::$excludeds) === false && !UString::startswith($method->name, "_"))
47  $this->routesMethods[$method->name]=[ "annotations" => $this->generateRouteAnnotationFromMethod($method),"method" => $method ];
48  }
49  }
50  }
51  }
52  }
53  }
54 
55  private function generateRouteAnnotationFromMethod(\ReflectionMethod $method) {
56  $annot=new RouteAnnotation();
57  $annot->path=self::getPathFromMethod($method);
58  return [ $annot ];
59  }
60 
61  private static function getPathFromMethod(\ReflectionMethod $method) {
62  $methodName=$method->getName();
63  if ($methodName === "index") {
64  $pathParts=[ "(index/)?" ];
65  } else {
66  $pathParts=[ $methodName ];
67  }
68  $parameters=$method->getParameters();
69  foreach ( $parameters as $parameter ) {
70  if ($parameter->isVariadic()) {
71  $pathParts[]='{...' . $parameter->getName() . '}';
72  return "/" . \implode("/", $pathParts);
73  }
74  if (!$parameter->isOptional()) {
75  $pathParts[]='{' . $parameter->getName() . '}';
76  } else {
77  $pathParts[\sizeof($pathParts) - 1].='{~' . $parameter->getName() . '}';
78  }
79  }
80  return "/" . \implode("/", $pathParts);
81  }
82 
83  private static function cleanpath($prefix, $path="") {
84  if (!UString::endswith($prefix, "/"))
85  $prefix=$prefix . "/";
86  if ($path !== "" && UString::startswith($path, "/"))
87  $path=\substr($path, 1);
88  $path=$prefix . $path;
89  if (!UString::endswith($path, "/") && !UString::endswith($path, '(.*?)') && !UString::endswith($path, "(index/)?"))
90  $path=$path . "/";
91  return $path;
92  }
93 
94  public function asArray() {
95  $result=[ ];
96  $prefix="";
97  $httpMethods=false;
98  if ($this->mainRouteClass) {
99  if (isset($this->mainRouteClass->path))
100  $prefix=$this->mainRouteClass->path;
101  if (isset($this->mainRouteClass->methods)) {
102  $httpMethods=$this->mainRouteClass->methods;
103  if ($httpMethods !== null) {
104  if (\is_string($httpMethods))
105  $httpMethods=[ $httpMethods ];
106  }
107  }
108  }
109  foreach ( $this->routesMethods as $method => $arrayAnnotsMethod ) {
110  $routeAnnotations=$arrayAnnotsMethod["annotations"];
111 
112  foreach ( $routeAnnotations as $routeAnnotation ) {
113  $params=[ "path" => $routeAnnotation->path,"methods" => $routeAnnotation->methods,"name" => $routeAnnotation->name,"cache" => $routeAnnotation->cache,"duration" => $routeAnnotation->duration,"requirements" => $routeAnnotation->requirements ];
114  self::parseRouteArray($result, $this->controllerClass, $params, $arrayAnnotsMethod["method"], $method, $prefix, $httpMethods);
115  }
116  }
117  return $result;
118  }
119 
120  public static function parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix="", $httpMethods=NULL) {
121  if (!isset($routeArray["path"])) {
122  $routeArray["path"]=self::getPathFromMethod($method);
123  }
124  $pathParameters=self::addParamsPath($routeArray["path"], $method, $routeArray["requirements"]);
125  $name=$routeArray["name"];
126  if (!isset($name)) {
128  }
129  $cache=$routeArray["cache"];
130  $duration=$routeArray["duration"];
131  $path=$pathParameters["path"];
132  $parameters=$pathParameters["parameters"];
133  $path=self::cleanpath($prefix, $path);
134  if (isset($routeArray["methods"]) && \is_array($routeArray["methods"])) {
135  self::createRouteMethod($result, $controllerClass, $path, $routeArray["methods"], $methodName, $parameters, $name, $cache, $duration);
136  } elseif (\is_array($httpMethods)) {
137  self::createRouteMethod($result, $controllerClass, $path, $httpMethods, $methodName, $parameters, $name, $cache, $duration);
138  } else {
139  $result[$path]=[ "controller" => $controllerClass,"action" => $methodName,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration];
140  }
141  }
142 
143  public static function addParamsPath($path, \ReflectionMethod $method, $requirements) {
144  $parameters=[ ];
145  $hasOptional=false;
146  preg_match_all('@\{(\.\.\.|\~)?(.+?)\}@s', $path, $matches);
147  if (isset($matches[2]) && \sizeof($matches[2]) > 0) {
148  $path=\preg_quote($path);
149  $params=Reflexion::getMethodParameters($method);
150  $index=0;
151  foreach ( $matches[2] as $paramMatch ) {
152  $find=\array_search($paramMatch, $params);
153  if ($find !== false) {
154  $requirement='.+?';
155  if (isset($requirements[$paramMatch])) {
156  $requirement=$requirements[$paramMatch];
157  }
158  self::scanParam($parameters, $hasOptional, $matches, $index, $paramMatch, $find, $path, $requirement);
159  } else {
160  throw new \Exception("{$paramMatch} is not a parameter of the method " . $method->name);
161  }
162  $index++;
163  }
164  }
165  if ($hasOptional)
166  $path.="/(.*?)";
167  return [ "path" => $path,"parameters" => $parameters ];
168  }
169 
170  private static function scanParam(&$parameters, &$hasOptional, $matches, $index, $paramMatch, $find, &$path, $requirement) {
171  if (isset($matches[1][$index])) {
172  if ($matches[1][$index] === "...") {
173  $parameters[]="*";
174  $path=\str_replace("\{\.\.\." . $paramMatch . "\}", "(.*?)", $path);
175  } elseif ($matches[1][$index] === "~") {
176  $parameters[]="~" . $find;
177  $path=\str_replace("\{~" . $paramMatch . "\}", "", $path);
178  $hasOptional=true;
179  } else {
180  $parameters[]=$find;
181  $path=\str_replace("\{" . $paramMatch . "\}", "({$requirement})", $path);
182  }
183  } else {
184  $parameters[]=$find;
185  $path=\str_replace("\{" . $paramMatch . "\}", "({$requirement})", $path);
186  }
187  }
188 
189  private static function createRouteMethod(&$result, $controllerClass, $path, $httpMethods, $method, $parameters, $name, $cache, $duration) {
190  foreach ( $httpMethods as $httpMethod ) {
191  $result[$path][$httpMethod]=[ "controller" => $controllerClass,"action" => $method,"parameters" => $parameters,"name" => $name,"cache" => $cache,"duration" => $duration ];
192  }
193  }
194 
195  public function isRest() {
196  return $this->rest;
197  }
198 }
static addParamsPath($path, \ReflectionMethod $method, $requirements)
static getAnnotationsMethod($class, $method, $annotation)
Definition: Reflexion.php:88
static getPathFromMethod(\ReflectionMethod $method)
static getMethodParameters(\ReflectionMethod $method)
Definition: Reflexion.php:173
(&#39;method&#39;=>true,&#39;class&#39;=>true,&#39;multiple&#39;=>true, &#39;inherited&#39;=>true)
static createRouteMethod(&$result, $controllerClass, $path, $httpMethods, $method, $parameters, $name, $cache, $duration)
static scanParam(&$parameters, &$hasOptional, $matches, $index, $paramMatch, $find, &$path, $requirement)
generateRouteAnnotationFromMethod(\ReflectionMethod $method)
static getAnnotationClass($class, $annotation)
Definition: Reflexion.php:76
static cleanAttribute($attr, $replacement="_")
Definition: UString.php:99
static getMethods($instance, $filter=null)
Definition: Reflexion.php:24
static parseRouteArray(&$result, $controllerClass, $routeArray, \ReflectionMethod $method, $methodName, $prefix="", $httpMethods=NULL)
static endswith($hay, $needle)
Definition: UString.php:16
static getClassSimpleName($classnameWithNamespace)
Definition: ClassUtils.php:135
static startswith($hay, $needle)
Definition: UString.php:12