public function testIfWillRecognizeAnnotationAfterDynamicallyAddingNamespace() { $model = new ModelWithTwoNsAnnotations(); $options = new MetaOptions(); $options->namespaces[] = NamespacedAnnotation::Ns; $meta = Meta::create($model, $options)->title; $this->assertTrue($meta->namespaced); // Not added second namespace $this->assertNull($meta->second); $this->assertNull($meta->third); // Second ns $options->namespaces[] = SecondNsAnnotation::Ns; $metaContainer2 = Meta::create($model, $options); $this->assertNotNull($metaContainer2); $meta2 = $metaContainer2->title; $this->assertTrue($meta2->namespaced); // Added second namespace $this->assertTrue($meta2->second, 'That namespace added via options id detected'); // Third ns Addendum::fly()->addNamespace(ThirdNsAnnotation::Ns); $meta3 = Meta::create($model, $options)->title; $this->assertTrue($meta3->namespaced); $this->assertTrue($meta3->second); // Added second namespace $this->assertTrue($meta3->third, 'That namespace added via Addendum::addNamespace is detected'); }
public function testIfWillProperlyCacheNamespacesForDifferentMetaContainers() { $path = (new ConfigDetector())->getRuntimePath(); if (!is_dir($path)) { mkdir($path); } // Simulate different meta container classes by creating different paths $path1 = sprintf('%s/path1', $path); $path2 = sprintf('%s/path2', $path); $path3 = sprintf('%s/path3', $path); if (!is_dir($path1)) { mkdir($path1); } if (!is_dir($path2)) { mkdir($path2); } if (!is_dir($path3)) { mkdir($path3); } $ns1 = new NsCache($path1, Addendum::fly(), new CacheOptionsOne()); $ns1->set(); codecept_debug($ns1->get()); $this->assertTrue($ns1->valid()); $ns2 = new NsCache($path2, Addendum::fly(), new CacheOptionsTwo()); $ns2->set(); codecept_debug($ns2->get()); $this->assertTrue($ns1->valid()); $this->assertTrue($ns2->valid()); $ns3 = new NsCache($path3, Addendum::fly(), new CacheOptionsOne()); $ns3->set(); codecept_debug($ns3->get()); $this->assertTrue($ns1->valid()); $this->assertTrue($ns2->valid()); $this->assertTrue($ns3->valid()); }
public function testBefore(TestEvent $e) { // Clear cache if env var is not set or is set to true if (false === getenv('ADDENDUM_CACHE_CLEAR') || getenv('ADDENDUM_CACHE_CLEAR')) { Addendum::cacheClear(); exec('rm -rf vendor/addendum/*'); } }
public function testRawMatcher() { $model = new ModelWithConstantValue(); $reflection = new ReflectionAnnotatedClass($model); $matcher = new AnnotationsMatcher(); $matcher->setPlugins(new MatcherConfig(['addendum' => new Addendum(), 'reflection' => new ReflectionClass($this)])); $matches = []; $matcher->matches(Addendum::getDocComment($reflection), $matches); }
/** * Get all annotations with optional restriction to $restriction annotation name * @param string $restriction * @return AnnotationInterface[] */ public function getAllAnnotations($restriction = false) { $restriction = Addendum::resolveClassName($restriction); $result = []; foreach ($this->annotations as $class => $instances) { if (!$restriction || $restriction == $class) { $result = array_merge($result, $instances); } } return $result; }
/** * * @param string $metaClass * @param AnnotatedInterface|object|string $component * @param MetaOptions|Addendum $options */ public function __construct($metaClass = null, $component = null, $options = null) { if (null === self::$runtimePath) { self::$runtimePath = (new ConfigDetector())->getRuntimePath(); } $this->path = self::$runtimePath . '/addendum'; $this->metaClass = $metaClass; $this->component = $component; if (empty($options)) { $this->instanceId = Addendum::DefaultInstanceId; } elseif ($options instanceof Addendum) { $this->instanceId = $options->getInstanceId(); } elseif ($options instanceof MetaOptions) { $this->instanceId = $options->instanceId; } else { throw new UnexpectedValueException('Unknown options'); } $this->prepare(); $this->addendum = Addendum::fly($this->instanceId); $this->nsCache = new NsCache(dirname($this->getFilename()), $this->addendum); }
public function testIfWillExtractTopValues() { $model = new ModelWithTopValues(); // Raw matcher for debug $reflection = new ReflectionAnnotatedProperty($model, 'straight'); $matcher = new AnnotationsMatcher(); $matcher->setPlugins(new MatcherConfig(['addendum' => new Addendum(), 'reflection' => $reflection])); $data = []; $comment = Addendum::getDocComment($reflection); $matcher->matches($comment, $data); $meta = Meta::create($model); // All fields have same annotation foreach ($meta->fields() as $fieldMeta) { $title = sprintf('Annotation is defined on %s', $fieldMeta->name); $this->assertSame(ModelWithTopValues::ClassValue, $fieldMeta->class); $this->assertSame(ModelWithTopValues::UpdatableValue, $fieldMeta->updatable); } }
/** * @param string|object|AnnotatedInterface $model * @param MetaOptions $options * @throws Exception */ protected function __construct($model = null, MetaOptions $options = null) { // For internal use if (null === $model) { return; } if (null === $options) { $options = new MetaOptions(); } // TODO Use adapter here // ?TODO Abstract from component meta, so other kinds of meta extractors could be used // For example, for development annotation based extractor could be used, which could compile // Metadata to arrays, and for production environment, compiled arrays could be used $annotations = []; $mes = []; // Get reflection data $ad = Addendum::fly($options->instanceId); $ad->addNamespaces($options->namespaces); $info = $ad->annotate($model); // Class name of working component $className = is_object($model) ? get_class($model) : $model; if (!$info instanceof ReflectionAnnotatedClass) { throw new Exception(sprintf('Could not annotate `%s`', $className)); } $properties = $info->getProperties(ReflectionProperty::IS_PUBLIC); $defaults = $info->getDefaultProperties(); $methods = $info->getMethods(ReflectionMethod::IS_PUBLIC); // Setup type /** * @todo Fix it: $this->_meta->{$this->name}->... * ^-- _meta __get and __set is only for fields AND use _fields field, * for class OR methods it should use different fields * for class should be _main * for methods should be _methods * __get and __set should distinguish it somehow... - maybe by field type EComponentMetaProperty for fieltds etc. * Currently disabled * OR add function to Annotation to setEntity, which should point to _field, _main or _method? */ // Setup class annotations $this->_type = new $options->typeClass($info); foreach ($info->getAllAnnotations() as $annotation) { if (!$annotation instanceof MetaAnnotationInterface) { continue; } $annotation->setName($info->name); $annotation->setEntity($this->_type); $annotation->setMeta($this); $annotation->init(); $annotations[] = $annotation; } // Setup methods foreach ($methods as $method) { if (!$method instanceof ReflectionAnnotatedMethod) { throw new Exception(sprintf('Could not annotate `%s::%s()`', $className, $method->name)); } // Ignore magic methods if (preg_match('~^__~', $method->name)) { continue; } // Ignore @Ignored marked methods if (IgnoredChecker::check($method)) { continue; } // Create method holder class based on options $methodMeta = new $options->methodClass($method); foreach ($method->getAllAnnotations() as $annotation) { if (!$annotation instanceof MetaAnnotationInterface) { continue; } $annotation->setName($method->name); $annotation->setEntity($methodMeta); $annotation->setMeta($this); $annotation->init(); $annotations[] = $annotation; } // Put it to metadata object $this->_methods[$method->name] = $methodMeta; // Get getters and setters for properties setup if (preg_match('~^[gs]et~', $method->name) && !$method->isStatic()) { $mes[$method->name] = true; } } // Setup properties foreach ($properties as $property) { if (!$property instanceof ReflectionAnnotatedProperty) { throw new Exception(sprintf('Could not annotate `%s::%s`', $className, $property->name)); } if (IgnoredChecker::check($property)) { continue; } $name = $property->name; /* @var $property ReflectionAnnotatedProperty */ $field = new $options->propertyClass($property); // Access options $field->callGet = isset($mes[$field->methodGet]) && $mes[$field->methodGet]; $field->callSet = isset($mes[$field->methodSet]) && $mes[$field->methodSet]; $field->direct = !($field->callGet || $field->callSet); $field->isStatic = $property->isStatic(); // Other if (array_key_exists($name, $defaults)) { $field->default = $defaults[$name]; } // Put it to metadata object $this->_fields[$field->name] = $field; foreach ($property->getAllAnnotations() as $annotation) { if (!$annotation instanceof MetaAnnotationInterface) { continue; } $annotation->setName($field->name); $annotation->setEntity($field); $annotation->setMeta($this); $annotation->init(); $annotations[] = $annotation; } } foreach ($annotations as $annotation) { $annotation->afterInit(); } }
<?php use Maslosoft\Addendum\Addendum; use Maslosoft\Signals\Signal; use Maslosoft\Signals\Utility; date_default_timezone_set('Europe/Paris'); define('VENDOR_DIR', __DIR__ . '/../../..'); define('YII_DIR', VENDOR_DIR . '/yiisoft/yii/framework/'); require VENDOR_DIR . '/autoload.php'; // Invoker stub for windows if (defined('PHP_WINDOWS_VERSION_MAJOR')) { require __DIR__ . '/../misc/Invoker.php'; } $config = (require __DIR__ . '/../config.php'); define('RUNTIME_PATH', __DIR__ . '/../runtime'); define('MODELS_PATH', __DIR__ . '/../models'); define('SIGNALS_PATH', __DIR__ . '/../signals'); $addendum = new Addendum(); $addendum->namespaces[] = 'Maslosoft\\Signals'; $addendum->init(); $signal = new Signal(); $signal->runtimePath = RUNTIME_PATH; $signal->paths = [MODELS_PATH]; $signal->init(); (new Utility($signal))->generate(); $signal->resetCache();
/** * Add annotation namespace * @param string $namespace */ public function addNamespace($namespace) { $this->addendum->addNamespace($namespace); }
/** * Get doc comment * @param ReflectionAnnotatedClass|ReflectionAnnotatedMethod|ReflectionAnnotatedProperty $reflection * @return mixed[] */ protected function getDocComment($reflection) { return Addendum::getDocComment($reflection); }
public function _after() { Addendum::cacheClear(); }