PluginProbe
Packeta / trunk
Packeta vtrunk
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / di / src / DI / Extensions / SearchExtension.php

SearchExtension.php in Packeta trunk, at deps/nette/di/src/DI/Extensions/SearchExtension.php

107 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace Packetery\Nette\DI\Extensions;
9
10 use Packetery\Nette;
11 use Packetery\Nette\Loaders\RobotLoader;
12 use Packetery\Nette\Schema\Expect;
13 use Packetery\Nette\Utils\Arrays;
14 /**
15 * Services auto-discovery.
16 */
17 final class SearchExtension extends \Packetery\Nette\DI\CompilerExtension
18 {
19 /** @var array */
20 private $classes = [];
21 /** @var string */
22 private $tempDir;
23 public function __construct(string $tempDir)
24 {
25 $this->tempDir = $tempDir;
26 }
27 public function getConfigSchema() : \Packetery\Nette\Schema\Schema
28 {
29 return Expect::arrayOf(Expect::structure(['in' => Expect::string()->required(), 'files' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'classes' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'extends' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'implements' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'exclude' => Expect::structure(['classes' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'extends' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), 'implements' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([])]), 'tags' => Expect::array()]))->before(function ($val) {
30 return \is_string($val['in'] ?? null) ? ['default' => $val] : $val;
31 });
32 }
33 public function loadConfiguration()
34 {
35 foreach (\array_filter($this->config) as $name => $batch) {
36 if (!\is_dir($batch->in)) {
37 throw new \Packetery\Nette\DI\InvalidConfigurationException(\sprintf("Option '%s › %s › in' must be valid directory name, '%s' given.", $this->name, $name, $batch->in));
38 }
39 foreach ($this->findClasses($batch) as $class) {
40 $this->classes[$class] = \array_merge($this->classes[$class] ?? [], $batch->tags);
41 }
42 }
43 }
44 public function findClasses(\stdClass $config) : array
45 {
46 $robot = new RobotLoader();
47 $robot->setTempDirectory($this->tempDir);
48 $robot->addDirectory($config->in);
49 $robot->acceptFiles = $config->files ?: ['*.php'];
50 $robot->reportParseErrors(\false);
51 $robot->refresh();
52 $classes = \array_unique(\array_keys($robot->getIndexedClasses()));
53 $exclude = $config->exclude;
54 $acceptRE = self::buildNameRegexp($config->classes);
55 $rejectRE = self::buildNameRegexp($exclude->classes);
56 $acceptParent = \array_merge($config->extends, $config->implements);
57 $rejectParent = \array_merge($exclude->extends, $exclude->implements);
58 $found = [];
59 foreach ($classes as $class) {
60 if (!\class_exists($class) && !\interface_exists($class) && !\trait_exists($class)) {
61 throw new \Packetery\Nette\InvalidStateException(\sprintf('Class %s was found, but it cannot be loaded by autoloading.', $class));
62 }
63 $rc = new \ReflectionClass($class);
64 if (($rc->isInstantiable() || $rc->isInterface() && \count($methods = $rc->getMethods()) === 1 && \in_array($methods[0]->name, ['get', 'create'], \true)) && (!$acceptRE || \preg_match($acceptRE, $rc->name)) && (!$rejectRE || !\preg_match($rejectRE, $rc->name)) && (!$acceptParent || Arrays::some($acceptParent, function ($nm) use($rc) {
65 return $rc->isSubclassOf($nm);
66 })) && (!$rejectParent || Arrays::every($rejectParent, function ($nm) use($rc) {
67 return !$rc->isSubclassOf($nm);
68 }))) {
69 $found[] = $rc->name;
70 }
71 }
72 return $found;
73 }
74 public function beforeCompile()
75 {
76 $builder = $this->getContainerBuilder();
77 foreach ($this->classes as $class => $foo) {
78 if ($builder->findByType($class)) {
79 unset($this->classes[$class]);
80 }
81 }
82 foreach ($this->classes as $class => $tags) {
83 if (\class_exists($class)) {
84 $def = $builder->addDefinition(null)->setType($class);
85 } elseif (\method_exists($class, 'create')) {
86 $def = $builder->addFactoryDefinition(null)->setImplement($class);
87 } else {
88 $def = $builder->addAccessorDefinition(null)->setImplement($class);
89 }
90 $def->setTags(Arrays::normalize($tags, \true));
91 }
92 }
93 private static function buildNameRegexp(array $masks) : ?string
94 {
95 $res = [];
96 foreach ($masks as $mask) {
97 $mask = (\strpos($mask, '\\') === \false ? '**\\' : '') . $mask;
98 $mask = \preg_quote($mask, '#');
99 $mask = \str_replace('\\*\\*\\\\', '(.*\\\\)?', $mask);
100 $mask = \str_replace('\\\\\\*\\*', '(\\\\.*)?', $mask);
101 $mask = \str_replace('\\*', '\\w*', $mask);
102 $res[] = $mask;
103 }
104 return $res ? '#^(' . \implode('|', $res) . ')$#i' : null;
105 }
106 }
107