/** * @param string $dir Directory to search in * @return array Array of listener class names */ protected function searchListeners($dir) { $files = (new Finder())->files()->in($dir)->path($this->searchPathPattern)->name('*Listener.php'); $listeners = []; foreach ($files as $file) { $listeners[] = key(AnnotationsParser::parsePhp(\file_get_contents($file->getRealpath()))); } return $listeners; }
/** * Create ProcessSet from given files, optionally filtering by given $groups and $excludeGroups * * @param Finder $files * @param array $groups Groups to be run * @param array $excludeGroups Groups to be excluded * @param string $filter filter test cases by name * @return ProcessSet */ public function createFromFiles(Finder $files, array $groups = null, array $excludeGroups = null, $filter = null) { $files->sortByName(); $processSet = $this->getProcessSet(); if ($groups || $excludeGroups || $filter) { $this->output->writeln('Filtering testcases:'); } if ($groups) { $this->output->writeln(sprintf(' - by group(s): %s', implode(', ', $groups))); } if ($excludeGroups) { $this->output->writeln(sprintf(' - excluding group(s): %s', implode(', ', $excludeGroups))); } if ($filter) { $this->output->writeln(sprintf(' - by testcase/test name: %s', $filter)); } $testCasesNum = 0; foreach ($files as $file) { $fileName = $file->getRealpath(); // Parse classes from the testcase file $classes = AnnotationsParser::parsePhp(\file_get_contents($fileName)); // Get annotations for the first class in testcase (one file = one class) $annotations = AnnotationsParser::getAll(new \ReflectionClass(key($classes))); // Filter out test-cases having any of excluded groups if ($excludeGroups && array_key_exists('group', $annotations) && count($excludingGroups = array_intersect($excludeGroups, $annotations['group']))) { if ($this->output->isDebug()) { $this->output->writeln(sprintf('Excluding testcase file %s with group %s', $fileName, implode(', ', $excludingGroups))); } continue; } // Filter out test-cases without any matching group if ($groups) { if (!array_key_exists('group', $annotations) || !count($matchingGroups = array_intersect($groups, $annotations['group']))) { continue; } if ($this->output->isDebug()) { $this->output->writeln(sprintf('Found testcase file #%d in group %s: %s', ++$testCasesNum, implode(', ', $matchingGroups), $fileName)); } } else { if ($this->output->isDebug()) { $this->output->writeln(sprintf('Found testcase file #%d: %s', ++$testCasesNum, $fileName)); } } $phpunitArgs = ['--log-junit=logs/' . Strings::webalize(key($classes), null, $lower = false) . '.xml', '--configuration=' . realpath(__DIR__ . '/../phpunit.xml')]; if ($filter) { $phpunitArgs[] = '--filter=' . $filter; } // If ANSI output is enabled, turn on colors in PHPUnit if ($this->output->isDecorated()) { $phpunitArgs[] = '--colors=always'; } $processSet->add($this->buildProcess($fileName, $phpunitArgs), key($classes), $delayAfter = !empty($annotations['delayAfter']) ? current($annotations['delayAfter']) : '', $delayMinutes = !empty($annotations['delayMinutes']) ? current($annotations['delayMinutes']) : null); } return $processSet; }
/** * Registers repositories from annotations */ private function registerAnnotations() { $ref = Nette\Reflection\ClassType::from($this); $annotations = $ref->getAnnotations(); if (isset($annotations['property-read'])) { $c = get_called_class(); $namespace = substr($c, 0, strrpos($c, '\\')); foreach ($annotations['property-read'] as $value) { if (preg_match('#^([\\\\\\w]+Repository)\\s+\\$(\\w+)$#', $value, $m)) { $class = '\\' . Reflection\AnnotationsParser::expandClassName($m[1], $ref); $this->register($m[2], $class); $this->aliases[$m[2]] = $class; } } } }
/** * @param ServiceDefinition * @return string|null */ protected static function detectClass(ServiceDefinition $def) { if ($def->getClass()) { return $def->getClass(); } elseif ($interface = $def->getImplement()) { $rc = Reflection\ClassType::from($interface); $method = $rc->hasMethod('create') ? 'create' : ($rc->hasMethod('get') ? 'get' : NULL); if ($method === NULL) { return NULL; } if (!($returnType = $rc->getMethod($method)->getAnnotation('return'))) { return NULL; } return Reflection\AnnotationsParser::expandClassName(preg_replace('#[|\\s].*#', '', $returnType), $rc); } return NULL; }
protected function getRepositoryList($modelClass) { $modelReflection = new ClassType($modelClass); $builder = $this->getContainerBuilder(); $builder->addDependency($modelReflection->getFileName()); $repositories = []; foreach ($modelReflection->getAnnotations() as $key => $annotations) { if ($key !== 'property-read') { continue; } foreach ($annotations as $annotation) { list($class, $name) = preg_split('#\\s+#', $annotation); $class = AnnotationsParser::expandClassName($class, $modelReflection); if (!class_exists($class)) { throw new RuntimeException("Repository '{$class}' does not exist."); } $repositories[ltrim($name, '$')] = $class; } } return $repositories; }
protected function getRepositoryList($modelClass) { $modelReflection = new ClassType($modelClass); $builder = $this->getContainerBuilder(); $builder->addDependency($modelReflection->getFileName()); $repositories = []; foreach ($modelReflection->getAnnotations() as $key => $annotations) { if ($key !== 'property-read') { continue; } foreach ($annotations as $annotation) { list($class, $name) = preg_split('#\\s+#', $annotation); $class = AnnotationsParser::expandClassName($class, $modelReflection); if (!class_exists($class)) { throw new RuntimeException("Class repository '{$class}' does not exist."); } $repositories[] = ['name' => ltrim($name, '$'), 'serviceName' => $this->prefix('repositories.' . ltrim($name, '$')), 'class' => $class, 'entities' => call_user_func([$class, 'getEntityClassNames'])]; } } return $repositories; }
public function beforeCompile() { $builder = $this->getContainerBuilder(); $config = $this->getConfig($this->defaults); foreach ($builder->getDefinitions() as $def) { /** @var $def ServiceDefinition */ $class = $def->class ?: ($def->factory ? $def->factory->entity : NULL); if (!$class || !class_exists($class)) { continue; } $classes = class_parents($class) + array('@self' => $class); foreach ($classes as $class) { $rc = ClassType::from($class); foreach ($rc->getProperties() as $rp) { if (!$rp->hasAnnotation($config['annotationName'])) { continue; } $fullPropName = $rp->getDeclaringClass()->getName() . '::$' . $rp->getName(); if ($rp->isStatic()) { trigger_error('Injects are not supported on static properties, found on ' . $fullPropName . '.', E_USER_WARNING); continue; } $var = (string) $rp->getAnnotation('var'); if (!$var) { throw new CompileException('@var annotation on ' . $fullPropName . ' is missing or empty.'); } $m = Strings::match(trim($var), '~ (?<name>\\\\?[a-z][a-z0-9_]*(?:\\\\[a-z][a-z0-9_]*)*) # class name (?<multiple>(?:\\[\\])?) # array of types \\z ~Aix'); if (!$m) { throw new CompileException('@var annotation on ' . $fullPropName . ' contains invalid value.'); } $type = AnnotationsParser::expandClassName($m['name'], $rp->getDeclaringClass()); $def->addSetup(__NAMESPACE__ . '\\Helpers::writeProperty(?, ?, ?, ' . (!empty($m['multiple']) ? __NAMESPACE__ . '\\Helpers::findServicesOfType(?, $this)' : '$this->getByType(?)') . ')', array('@self', $rp->getDeclaringClass()->getName(), $rp->getName(), $type)); } } } }
public function startTest(\PHPUnit_Framework_Test $test) { if ($test instanceof \PHPUnit_Framework_Warning) { return; } if (!$test instanceof AbstractTestCase) { throw new \InvalidArgumentException('Test case must be descendant of Lmc\\Steward\\Test\\AbstractTestCase'); } $config = ConfigProvider::getInstance(); // Initialize NullWebDriver if self::NO_BROWSER_ANNOTATION is used on testcase class or test method $testCaseAnnotations = AnnotationsParser::getAll(new \ReflectionClass($test)); $testAnnotations = AnnotationsParser::getAll(new \ReflectionMethod($test, $test->getName(false))); if (isset($testCaseAnnotations[self::NO_BROWSER_ANNOTATION]) || isset($testAnnotations[self::NO_BROWSER_ANNOTATION])) { $test->wd = new NullWebDriver(); $test->log('Initializing Null WebDriver for "%s::%s" (@%s annotation used %s)', get_class($test), $test->getName(), self::NO_BROWSER_ANNOTATION, isset($testCaseAnnotations[self::NO_BROWSER_ANNOTATION]) ? 'on class' : 'on method'); return; } // Initialize real WebDriver otherwise $test->log('Initializing "%s" WebDriver for "%s::%s"', $config->browserName, get_class($test), $test->getName()); $capabilities = new \DesiredCapabilities([\WebDriverCapabilityType::BROWSER_NAME => $config->browserName, \WebDriverCapabilityType::PLATFORM => \WebDriverPlatform::ANY]); $this->createWebDriver($test, $config->serverUrl . '/wd/hub', $this->setupCustomCapabilities($capabilities, $config->browserName), $connectTimeoutMs = 2 * 60 * 1000, $requestTimeoutMs = 60 * 60 * 1000); }
/** * Expands class name into FQN. * @param string * @return string fully qualified class name * @throws Nette\InvalidArgumentException */ public static function expandClassName($name, \ReflectionClass $reflector) { if (empty($name)) { throw new Nette\InvalidArgumentException('Class name must not be empty.'); } elseif ($name === 'self') { return $reflector->getName(); } elseif ($name[0] === '\\') { // already fully qualified return ltrim($name, '\\'); } $filename = $reflector->getFileName(); $parsed = static::getCache()->load($filename, function (& $dp) use ($filename) { if (AnnotationsParser::$autoRefresh) { $dp[Nette\Caching\Cache::FILES] = $filename; } return AnnotationsParser::parsePhp(file_get_contents($filename)); }); $uses = array_change_key_case((array) $tmp = & $parsed[$reflector->getName()]['use']); $parts = explode('\\', $name, 2); $parts[0] = strtolower($parts[0]); if (isset($uses[$parts[0]])) { $parts[0] = $uses[$parts[0]]; return implode('\\', $parts); } elseif ($reflector->inNamespace()) { return $reflector->getNamespaceName() . '\\' . $name; } else { return $name; } }
private function processKeyword($value, ReflectionClass $reflectionClass) { if (strcasecmp($value, 'true') === 0) { return TRUE; } elseif (strcasecmp($value, 'false') === 0) { return FALSE; } elseif (strcasecmp($value, 'null') === 0) { return NULL; } elseif (is_numeric($value)) { return $value * 1; } elseif (preg_match('#^[a-z0-9_\\\\]+::[a-z0-9_]+(\\*)?$#i', $value)) { list($className, $const) = explode('::', $value, 2); if ($className === 'self' || $className === 'static') { $reflection = $reflectionClass; } else { $className = AnnotationsParser::expandClassName($className, $reflectionClass); $reflection = new ReflectionClass($className); } $enum = []; $constants = $reflection->getConstants(); if (strpos($const, '*') !== FALSE) { $prefix = rtrim($const, '*'); $prefixLength = strlen($prefix); $count = 0; foreach ($constants as $name => $value) { if (substr($name, 0, $prefixLength) === $prefix) { $enum[$value] = $value; $count += 1; } } if ($count === 0) { throw new InvalidModifierDefinitionException("No constant matches {$reflection->name}::{$const} pattern."); } } else { if (!array_key_exists($const, $constants)) { throw new InvalidModifierDefinitionException("Constant {$reflection->name}::{$const} does not exist."); } $value = $reflection->getConstant($const); $enum[$value] = $value; } return array_values($enum); } else { return $value; } }
protected function makeFQN($name) { return AnnotationsParser::expandClassName($name, $this->currentReflection); }
private function resolveAnnotationClass(\Reflector $prop, $annotationValue, $annotationName) { /** @var Property|Method $prop */ if (!($type = ltrim($annotationValue, '\\'))) { throw new InvalidStateException("Missing annotation @{$annotationName} with typehint on {$prop}.", $prop); } if (!class_exists($type) && !interface_exists($type)) { if (substr(func_get_arg(1), 0, 1) === '\\') { throw new MissingClassException("Class \"{$type}\" was not found, please check the typehint on {$prop} in annotation @{$annotationName}.", $prop); } $expandedType = NULL; if (method_exists('Nette\\Reflection\\AnnotationsParser', 'expandClassName')) { $expandedType = Nette\Reflection\AnnotationsParser::expandClassName($annotationValue, $prop instanceof \ReflectionProperty ? Nette\Reflection\Helpers::getDeclaringClass($prop) : $prop->getDeclaringClass()); } if ($expandedType && (class_exists($expandedType) || interface_exists($expandedType))) { $type = $expandedType; } elseif (!class_exists($type = $prop->getDeclaringClass()->getNamespaceName() . '\\' . $type) && !interface_exists($type)) { throw new MissingClassException("Neither class \"" . func_get_arg(1) . "\" or \"{$type}\" was found, please check the typehint on {$prop} in annotation @{$annotationName}.", $prop); } } return ClassType::from($type)->getName(); }
/** * Generates $dependencies, $classes and normalizes class names. * @return array */ public function prepareClassList() { $this->classes = FALSE; // prepare generated factories foreach ($this->definitions as $name => $def) { if (!$def->implement) { continue; } if (!interface_exists($def->implement)) { throw new ServiceCreationException("Interface {$def->implement} has not been found."); } $rc = Reflection\ClassType::from($def->implement); $method = $rc->hasMethod('create') ? $rc->getMethod('create') : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL); if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) { throw new ServiceCreationException("Interface {$def->implement} must have just one non-static method create() or get()."); } $def->implement = $rc->getName(); $def->implementType = $rc->hasMethod('create') ? 'create' : 'get'; if (!$def->class && empty($def->factory->entity)) { $returnType = $method->getAnnotation('return'); if (!$returnType) { throw new ServiceCreationException("Method {$method} has not @return annotation."); } $returnType = Reflection\AnnotationsParser::expandClassName($returnType, $rc); if (!class_exists($returnType)) { throw new ServiceCreationException("Please check a @return annotation of the {$method} method. Class '{$returnType}' cannot be found."); } $def->setClass($returnType); } if ($method->getName() === 'get') { if ($method->getParameters()) { throw new ServiceCreationException("Method {$method} must have no arguments."); } if (empty($def->factory->entity)) { $def->setFactory('@\\' . ltrim($def->class, '\\')); } elseif (!$this->getServiceName($def->factory->entity)) { throw new ServiceCreationException("Invalid factory in service '{$name}' definition."); } } if (!$def->parameters) { foreach ($method->getParameters() as $param) { $paramDef = ($param->isArray() ? 'array' : $param->getClassName()) . ' ' . $param->getName(); if ($param->isOptional()) { $def->parameters[$paramDef] = $param->getDefaultValue(); } else { $def->parameters[] = $paramDef; } } } } // complete class-factory pairs foreach ($this->definitions as $name => $def) { if (!$def->factory) { if (!$def->class) { throw new ServiceCreationException("Class and factory are missing in service '{$name}' definition."); } $def->factory = new Statement($def->class); } } // check if services are instantiable foreach ($this->definitions as $name => $def) { $factory = $def->factory->entity = $this->normalizeEntity($def->factory->entity); if (is_string($factory) && preg_match('#^[\\w\\\\]+\\z#', $factory) && $factory !== self::THIS_SERVICE) { if (!class_exists($factory) || !Reflection\ClassType::from($factory)->isInstantiable()) { throw new ServiceCreationException("Class {$factory} used in service '{$name}' has not been found or is not instantiable."); } } } // complete classes foreach ($this->definitions as $name => $def) { $this->resolveClass($name); if (!$def->class) { continue; } elseif (!class_exists($def->class) && !interface_exists($def->class)) { throw new ServiceCreationException("Class or interface {$def->class} used in service '{$name}' has not been found."); } else { $def->class = Reflection\ClassType::from($def->class)->getName(); } } // build auto-wiring list $this->classes = array(); foreach ($this->definitions as $name => $def) { $class = $def->implement ?: $def->class; if ($def->autowired && $class) { foreach (class_parents($class) + class_implements($class) + array($class) as $parent) { $this->classes[strtolower($parent)][] = (string) $name; } } } foreach ($this->classes as $class => $foo) { $this->addDependency(Reflection\ClassType::from($class)->getFileName()); } }
/** @return string */ protected final function getEntityClass() { if ($this->entity === NULL) { $ref = static::getReflection(); if (($annotation = $ref->getAnnotation('entity')) === NULL) { throw new Exception\InvalidStateException('Entity class not set.'); } $this->entity = AnnotationsParser::expandClassName($annotation, $ref); } return $this->entity; }
/** * @param MetaData $metaData * @param string $string * @param string $mode ::READWRITE|MetaData::READ|MetaData::WRITE * @param string $class * @param ReflectionClass $r */ private function addProperty(MetaData $metaData, $string, $mode, $class, ReflectionClass $r) { if ($mode === MetaData::READWRITE) { if (preg_match('#^(-read|-write)?\\s?(.*)$#si', $string, $match)) { $mode = $match[1]; $mode = ((!$mode or $mode === '-read') ? MetaData::READ : 0) | ((!$mode or $mode === '-write') ? MetaData::WRITE : 0); $string = $match[2]; } } if (preg_match('#^([a-z0-9_\\[\\]\\|\\\\]+)\\s+\\$([a-z0-9_]+)($|\\s(.*)$)#si', $string, $match)) { $property = $match[2]; $type = $match[1]; $string = $match[3]; } else { if (preg_match('#^\\$([a-z0-9_]+)\\s+([a-z0-9_\\|\\\\]+)($|\\s(.*)$)#si', $string, $match)) { $property = $match[1]; $type = $match[2]; $string = $match[3]; } else { if (preg_match('#^\\$([a-z0-9_]+)($|\\s(.*)$)#si', $string, $match)) { $property = $match[1]; $type = 'mixed'; $string = $match[2]; } else { $tmp = $mode === MetaData::READ ? '-read' : ''; throw new AnnotationMetaDataException("Invalid annotation format '@property{$tmp} {$string}' in {$class}"); } } } if (strpos(strToLower($string), '{ignore}') !== FALSE) { return; } $propertyName = $property; // Support for simplified FQN '@property Foo' instead of '@property \App\Foo' $parts = explode('|', $type); foreach ($parts as &$part) { $fqn = NetteAnnotationsParser::expandClassName($part, $r); if (class_exists($fqn)) { $part = $fqn; } if ($part === Orm\OneToMany::class) { // Support for '@property OtM|Foo[]' instead of '@property Orm\OneToMany' $parts = [Orm\OneToMany::class]; break; } else { if ($part === Orm\ManyToMany::class) { // Support for '@property MtM|Foo[]' instead of '@property Orm\ManyToMany' $parts = [Orm\ManyToMany::class]; break; } else { if (substr($part, -2) === '[]') { $part = 'array'; } } } } $type = implode('|', $parts); $property = $metaData->addProperty($propertyName, $type, $mode, $class); $this->property = [$propertyName, $property]; $string = preg_replace_callback('#\\{\\s*([^\\s\\}\\{]+)(?:\\s+([^\\}\\{]*))?\\s*\\}#si', [$this, 'callOnMacro'], $string); $this->property = NULL; if (preg_match('#\\{|\\}#', $string)) { $string = trim($string); throw new AnnotationMetaDataException("Invalid annotation format, extra curly bracket '{$string}' in {$class}::\${$propertyName}"); } }
/** * Returns an annotation value. * * @param string * * @return IAnnotation */ public function getAnnotation($name) { $res = AnnotationsParser::getAll($this); return isset($res[$name]) ? end($res[$name]) : null; }
/** * Generates list of properties with annotation @inject. * @return array */ public static function getInjectProperties(Nette\Reflection\ClassType $class) { $res = array(); foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { $type = $property->getAnnotation('var'); if (!$property->getAnnotation('inject')) { continue; } elseif (!$type) { throw new Nette\InvalidStateException("Property {$property} has not @var annotation."); } $type = Nette\Reflection\AnnotationsParser::expandClassName($type, $property->getDeclaringClass()); if (!class_exists($type) && !interface_exists($type)) { throw new Nette\InvalidStateException("Class or interface '{$type}' used in @var annotation at {$property} not found."); } $res[$property->getName()] = $type; } return $res; }
/** * Scan discoverable paths and get actions * * @return array */ public function mapClasses() { $paths = $this->config->getDiscovererPaths(); $files = $classMap = []; foreach ($paths as $path) { $files = array_merge($files, $this->loadDir($path)); } foreach ($files as $file) { $fileContent = file_get_contents($file); $classes = array_keys(AnnotationsParser::parsePhp($fileContent)); Config::includeFile($file); foreach ($classes as $className) { $class = new \ReflectionClass($className); if (!$class->isInstantiable()) { continue; } $classAnnotations = AnnotationsParser::getAll($class); if (!isset($classAnnotations['ExtDirect'])) { continue; } $methods = $this->getMethods($class); $classAlias = null; if (isset($classAnnotations['ExtDirect\\Alias'])) { if (is_array($classAnnotations['ExtDirect\\Alias']) && is_string($classAnnotations['ExtDirect\\Alias'][0])) { $classAlias = $classAnnotations['ExtDirect\\Alias'][0]; } } $actionName = $classAlias ?: $className; $classMap[$actionName]['action'] = $actionName; $classMap[$actionName]['class'] = $className; $classMap[$actionName]['file'] = $file; $classMap[$actionName]['methods'] = $methods; } } return $classMap; }
/** * Returns array of properties needed to be injected. * Keys of array are property names, values are service types. * * Name must match with InjectionCompilerExtension::IIS_GET_INJECTION_PROPS_METHOD * * @return array */ public static function InjectableTrait_getInjectionByTypeProperties() { $injectionProperties = []; $properties = static::InjectableTrait_getReflection()->getProperties(); foreach ($properties as $property) { if ($property->hasAnnotation(AService::INJECT_SERVICE_ANNOTATION)) { $serviceName = $property->getAnnotation(AService::INJECT_SERVICE_ANNOTATION); $type = $property->getAnnotation(AService::TYPE_ANNOTATION); if (($serviceName === true || strlen($serviceName) === 0) && $type !== null) { $type = AnnotationsParser::expandClassName($type, $property->getDeclaringClass()); $injectionProperties[$property->name] = $type; } } } return $injectionProperties; }
isset($res[$name])?end($res[$name]):NULL;}function getAnnotations(){return AnnotationsParser::getAll($this);}function
/** * @param string $class * @return void */ private static function loadAnnotationProperties($class) { if (!isset(self::$annProps[$class])) { self::$annProps[$class] = []; $ref = $class::getReflection(); foreach ($ref->getAnnotations() as $ann => $values) { if ($ann === 'property' || $ann === 'property-read') { foreach ($values as $tmp) { $matches = NStrings::match($tmp, '#^[ \\t]*(?P<type>\\\\?[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?:\\\\[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)*(?:\\|\\\\?[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?:\\\\[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)*)?)[ \\t]+(?P<property>\\$[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)(?:[ \\t]+->[ \\t]+(?P<column>[a-zA-Z0-9_-]+))?[ \\t]*(?P<description>.*)\\z#'); if ($matches === NULL) { throw new YetORM\Exception\InvalidStateException('Invalid property definition - "@' . $ann . ' ' . $tmp . '" does not match "@property[-read] <type> $<property> [-> <column>][ <description>]" pattern.'); } $nullable = FALSE; $type = $matches['type']; $types = explode('|', $type, 2); if (count($types) === 2) { if (strcasecmp($types[0], 'NULL') === 0) { $nullable = TRUE; $type = $types[1]; } if (strcasecmp($types[1], 'NULL') === 0) { if ($nullable) { throw new YetORM\Exception\InvalidStateException('Invalid property type (double NULL).'); } $nullable = TRUE; $type = $types[0]; } if (!$nullable) { throw new YetORM\Exception\InvalidStateException('Invalid property type (multiple non-NULL types detected).'); } } if ($type === 'bool') { $type = 'boolean'; } elseif ($type === 'int') { $type = 'integer'; } if (!EntityProperty::isNativeType($type)) { $type = AnnotationsParser::expandClassName($type, $ref); } $readonly = $ann === 'property-read'; $name = substr($matches['property'], 1); $column = strlen($matches['column']) ? $matches['column'] : $name; $description = strlen($matches['description']) ? $matches['description'] : NULL; self::$annProps[$class][$name] = new AnnotationProperty($ref, $name, $readonly, $type, $column, $nullable, $description); } } } } }
/** * Returns all annotations. * @return IAnnotation[][] */ public function getAnnotations() { return AnnotationsParser::getAll($this); }
private function resolveClass($name, $recursive = array()) { if (isset($recursive[$name])) { throw new ServiceCreationException('Circular reference detected for services: ' . implode(', ', array_keys($recursive)) . '.'); } $recursive[$name] = TRUE; $def = $this->definitions[$name]; $factory = $def->factory->entity; if ($def->class) { return $def->class; } elseif (is_array($factory)) { // method calling if ($service = $this->getServiceName($factory[0])) { if (Strings::contains($service, '\\')) { // @\Class $factory[0] = $service; } else { $factory[0] = $this->resolveClass($service, $recursive); if (!$factory[0]) { return; } if ($this->definitions[$service]->implement && $factory[1] === 'create') { return $def->class = $factory[0]; } } } if (!is_callable($factory)) { throw new ServiceCreationException("Factory '" . Nette\Utils\Callback::toString($factory) . "' is not callable."); } try { $reflection = Nette\Utils\Callback::toReflection($factory); } catch (\ReflectionException $e) { throw new ServiceCreationException("Missing factory '" . Nette\Utils\Callback::toString($factory) . "'."); } $def->class = preg_replace('#[|\\s].*#', '', $reflection->getAnnotation('return')); if ($def->class && $reflection instanceof \ReflectionMethod) { $def->class = Reflection\AnnotationsParser::expandClassName($def->class, $reflection->getDeclaringClass()); } } elseif ($service = $this->getServiceName($factory)) { // alias or factory if (!$def->implement) { $def->autowired = FALSE; } if (Strings::contains($service, '\\')) { // @\Class return $def->class = $service; } if ($this->definitions[$service]->implement) { $def->autowired = FALSE; } return $def->class = $this->definitions[$service]->implement ?: $this->resolveClass($service, $recursive); } else { return $def->class = $factory; // class name } }
private function resolveClass($name, $recursive = array()) { if (isset($recursive[$name])) { throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive)))); } $recursive[$name] = TRUE; $def = $this->definitions[$name]; $factory = $def->factory->entity; if ($def->class) { return $def->class; } elseif (is_array($factory)) { // method calling if ($service = $this->getServiceName($factory[0])) { if (Strings::contains($service, '\\')) { // @\Class $factory[0] = $service; } else { $factory[0] = $this->resolveClass($service, $recursive); if (!$factory[0]) { return; } if ($this->definitions[$service]->implement && $factory[1] === 'create') { return $def->class = $factory[0]; } } } try { $reflection = Nette\Utils\Callback::toReflection($factory); } catch (\ReflectionException $e) { } if (isset($e) || !is_callable($factory)) { throw new ServiceCreationException(sprintf("Factory '%s' used in service '%s' is not callable.", Nette\Utils\Callback::toString($factory), $name)); } $def->class = preg_replace('#[|\\s].*#', '', $reflection->getAnnotation('return')); if ($def->class && $reflection instanceof \ReflectionMethod) { $def->class = Reflection\AnnotationsParser::expandClassName($tmp = $def->class, $reflection->getDeclaringClass()); if ($tmp !== $def->class && $tmp[0] !== '\\' && class_exists($tmp)) { $def->class = $tmp; trigger_error("You should use @return \\{$tmp}' in {$reflection}.", E_USER_WARNING); } } } elseif ($service = $this->getServiceName($factory)) { // alias or factory if (!$def->implement) { $def->autowired = FALSE; } if (Strings::contains($service, '\\')) { // @\Class return $def->class = $service; } if ($this->definitions[$service]->implement) { $def->autowired = FALSE; } return $def->class = $this->definitions[$service]->implement ?: $this->resolveClass($service, $recursive); } else { return $def->class = $factory; // class name } }
/** * Generates list of properties with annotation @inject. * @return array */ public static function getInjectProperties(Nette\Reflection\ClassType $class, $container = NULL) { $res = array(); foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { $type = $property->getAnnotation('var'); if (!$property->getAnnotation('inject')) { continue; } elseif (!$type) { throw new Nette\InvalidStateException("Property $property has no @var annotation."); } $type = Nette\Reflection\AnnotationsParser::expandClassName($type, self::getDeclaringClass($property)); if (!class_exists($type) && !interface_exists($type)) { throw new Nette\InvalidStateException("Class or interface '$type' used in @var annotation at $property not found. Check annotation and 'use' statements."); } elseif ($container && !$container->getByType($type, FALSE)) { throw new ServiceCreationException("Service of type {$type} used in @var annotation at $property not found. Did you register it in configuration file?"); } $res[$property->getName()] = $type; } return $res; }