示例#1
0
 /**
  * Resolve class alias
  * @param Reflector $reflection
  * @param string $className
  * @return string
  */
 public static function resolve(Reflector $reflection, $className)
 {
     if ($reflection instanceof ReflectionProperty || $reflection instanceof ReflectionMethod) {
         $reflection = $reflection->getDeclaringClass();
     }
     $docs = (new DocComment())->forClass($reflection);
     $use = $docs['use'];
     $ns = $docs['namespace'];
     $aliases = $docs['useAliases'];
     // Resolve to itself with keywords
     if ($className === 'self' || $className === 'static') {
         $fqn = $ns . '\\' . $docs['className'];
         return $fqn;
     }
     // This is for same namespaced class as current class
     $aliases[$ns . '\\' . $className] = $className;
     if (in_array($className, $use)) {
         return $className;
     }
     foreach ($use as $useClause) {
         $patternClass = preg_quote($className);
         $pattern = "~\\\\{$patternClass}\$~";
         if (preg_match($pattern, $useClause)) {
             return $useClause;
         }
     }
     foreach ($aliases as $useClause => $alias) {
         if ($className == $alias) {
             NameNormalizer::normalize($useClause, false);
             return $useClause;
         }
     }
     return $className;
 }
 public function testNameNormalizerWithTrailingSlash()
 {
     $test = ['\\' => '\\', 'Maslosoft\\Addendum\\Annotations' => '\\Maslosoft\\Addendum\\Annotations', 'Maslosoft\\AddendumTest\\Annotations' => '\\Maslosoft\\AddendumTest\\Annotations', '\\Maslosoft\\AddendumTest\\Annotations\\SignaledNs' => '\\Maslosoft\\AddendumTest\\Annotations\\SignaledNs'];
     foreach ($test as $actual => $expected) {
         NameNormalizer::normalize($actual, true);
         $this->assertSame($actual, $expected);
     }
 }
 /**
  * TODO Move to addendum project
  */
 public function testIfWillNormalizeClassName()
 {
     $config = ['Some\\Namespace\\' => '\\Some\\Namespace', '\\Some\\Namespace' => '\\Some\\Namespace', '\\Some\\\\Namespace' => '\\Some\\Namespace', 'GlobalNamespace' => '\\GlobalNamespace', '\\GlobalNamespace' => '\\GlobalNamespace', '\\GlobalNamespace\\' => '\\GlobalNamespace'];
     foreach ($config as $src => $dest) {
         $title = sprintf('Namespace `%s` should be `%s`', $src, $dest);
         $this->specify($title, function () use($src, $dest) {
             NameNormalizer::normalize($src);
             $this->assertSame($dest, $src);
         });
     }
 }
示例#4
0
 public function init()
 {
     $data = ParamsExpander::expand($this, ['class']);
     $class = '';
     if (isset($data['class'])) {
         $class = $data['class'];
     }
     // Log only, as it is designed as soft-fail
     if (empty($class) || !ClassChecker::exists($class)) {
         (new Signal())->getLogger()->warning(sprintf('Class not found for SignalFor annotation on model `%s`', $this->getMeta()->type()->name));
         return;
     }
     NameNormalizer::normalize($class);
     $this->getEntity()->signalFor[] = $class;
 }
示例#5
0
 /**
  * Call for signals from slot
  * @param object $slot
  * @param string $interface Interface or class name which must be implemented, instanceof or sub class of to get into slot
  */
 public function gather($slot, $interface = null)
 {
     $name = get_class($slot);
     NameNormalizer::normalize($name);
     if (!empty($interface)) {
         NameNormalizer::normalize($interface);
     }
     if (empty(self::$config)) {
         $this->init();
     }
     if (!isset(self::$config[self::Slots][$name])) {
         self::$config[self::Slots][$name] = [];
         $this->loggerInstance->debug('No signals found for slot `{name}`, skipping', ['name' => $name]);
     }
     $result = [];
     foreach ((array) self::$config[self::Slots][$name] as $fqn => $emit) {
         if (false === $emit) {
             continue;
         }
         if (!PreFilter::filter($this, $fqn, $slot)) {
             continue;
         }
         // Check if class exists and log if doesn't
         if (!ClassChecker::exists($fqn)) {
             $this->loggerInstance->debug(sprintf("Class `%s` not found while gathering slot `%s`", $fqn, get_class($slot)));
             continue;
         }
         if (null === $interface) {
             $injected = new $fqn();
             if (!PostFilter::filter($this, $injected, $slot)) {
                 continue;
             }
             $result[] = $injected;
             continue;
         }
         // Check if it's same as interface
         if ($fqn === $interface) {
             $injected = new $fqn();
             if (!PostFilter::filter($this, $injected, $slot)) {
                 continue;
             }
             $result[] = $injected;
             continue;
         }
         $info = new ReflectionClass($fqn);
         // Check if class is instance of base class
         if ($info->isSubclassOf($interface)) {
             $injected = new $fqn();
             if (!PostFilter::filter($this, $injected, $slot)) {
                 continue;
             }
             $result[] = $injected;
             continue;
         }
         $interfaceInfo = new ReflectionClass($interface);
         // Check if class implements interface
         if ($interfaceInfo->isInterface() && $info->implementsInterface($interface)) {
             $injected = new $fqn();
             if (!PostFilter::filter($this, $injected, $slot)) {
                 continue;
             }
             $result[] = $injected;
             continue;
         }
     }
     return $result;
 }
示例#6
0
 /**
  * @param string $file
  */
 public function processFile($file, $contents)
 {
     $file = realpath($file);
     $this->paths[] = $file;
     // Remove initial `\` from namespace
     try {
         $annotated = AnnotationUtility::rawAnnotate($file);
     } catch (ParseException $e) {
         $this->log($e, $file);
         return;
     } catch (UnexpectedValueException $e) {
         $this->log($e, $file);
         return;
     }
     $namespace = preg_replace('~^\\\\+~', '', $annotated['namespace']);
     $className = $annotated['className'];
     // Use fully qualified name, class must autoload
     $fqn = $namespace . '\\' . $className;
     NameNormalizer::normalize($fqn);
     try {
         $info = new ReflectionClass($fqn);
     } catch (ReflectionException $e) {
         $this->log($e, $file);
         return;
     }
     $isAnnotated = $info->implementsInterface(AnnotatedInterface::class);
     $hasSignals = $this->hasSignals($contents);
     $isAbstract = $info->isAbstract() || $info->isInterface();
     // Old classes must now implement interface
     // Brake BC!
     if ($hasSignals && !$isAnnotated && !$isAbstract) {
         throw new UnexpectedValueException(sprintf('Class %s must implement %s to use signals', $fqn, AnnotatedInterface::class));
     }
     // Skip not annotated class
     if (!$isAnnotated) {
         return;
     }
     // Skip abstract classes
     if ($isAbstract) {
         return;
     }
     $meta = @SignalsMeta::create($fqn);
     /* @var $typeMeta DocumentTypeMeta */
     $typeMeta = $meta->type();
     // Signals
     foreach ($typeMeta->signalFor as $slot) {
         $this->data[Signal::Slots][$slot][$fqn] = true;
     }
     // Slots
     // For constructor injection
     foreach ($typeMeta->slotFor as $slot) {
         $key = implode('@', [$fqn, '__construct', '()']);
         $this->data[Signal::Signals][$slot][$fqn][$key] = true;
     }
     // For method injection
     foreach ($meta->methods() as $methodName => $method) {
         /* @var $method DocumentMethodMeta */
         foreach ($method->slotFor as $slot) {
             $key = implode('@', [$fqn, $methodName, '()']);
             $this->data[Signal::Signals][$slot][$fqn][$key] = sprintf('%s()', $methodName);
         }
     }
     // For property injection
     foreach ($meta->fields() as $fieldName => $field) {
         /* @var $field DocumentPropertyMeta */
         foreach ($field->slotFor as $slot) {
             $key = implode('@', [$fqn, $fieldName]);
             $this->data[Signal::Signals][$slot][$fqn][$key] = sprintf('%s', $fieldName);
         }
     }
 }
示例#7
0
 /**
  * Add annotations namespace.
  * Every added namespace will be included in annotation name resolving for current instance.
  *
  * @param string $ns
  * @renturn Addendum
  */
 public function addNamespace($ns)
 {
     NameNormalizer::normalize($ns, false);
     if (!in_array($ns, $this->namespaces)) {
         $before = count($this->namespaces);
         $this->namespaces[] = $ns;
         $this->namespaces = array_unique($this->namespaces);
         $after = count($this->namespaces);
         if ($after !== $before) {
             $this->nameKeys = array_flip($this->namespaces);
             Cache\NsCache::$addeNs = true;
         }
         $this->di->store($this, [], true);
         // Reconfigure flyweight instances if present
         if (!empty(self::$addendums[$this->instanceId])) {
             self::$addendums[$this->instanceId]->di->configure(self::$addendums[$this->instanceId]);
         }
     }
     return $this;
 }
示例#8
0
 /**
  * Normalize class name and namespace to proper fully qualified name
  * @param string $ns
  * @param string $class
  * @return string
  */
 private function normalizeFqn($ns, $class)
 {
     $fqn = "\\{$ns}\\{$class}";
     NameNormalizer::normalize($fqn);
     return $fqn;
 }