Completed
Push — master ( 6404cf...85a2d9 )
by Vitaly
02:45
created

MetadataBuilder::loadFromClassNames()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php declare(strict_types = 1);
2
/**
3
 * Created by PhpStorm.
4
 * User: root
5
 * Date: 02.08.16
6
 * Time: 0:46.
7
 */
8
namespace samsonframework\container;
9
10
use Interop\Container\ContainerInterface;
11
use samsonframework\container\metadata\ClassMetadata;
12
use samsonframework\container\resolver\ResolverInterface;
13
use samsonframework\di\Container;
14
use samsonframework\filemanager\FileManagerInterface;
15
16
/**
17
 * Class Container.
18
 */
19
class MetadataBuilder
20
{
21
    /** Controller classes scope name */
22
    const SCOPE_CONTROLLER = 'controllers';
23
24
    /** Service classes scope name */
25
    const SCOPE_SERVICES = 'services';
26
27
    /** @var string[] Collection of available container scopes */
28
    protected $scopes = [
29
        self::SCOPE_CONTROLLER => [],
30
        self::SCOPE_SERVICES => []
31
    ];
32
33
    /** @var ClassMetadata[] Collection of classes metadata */
34
    protected $classMetadata = [];
35
36
    /** @var FileManagerInterface */
37
    protected $fileManger;
38
39
    /** @var ResolverInterface */
40
    protected $classResolver;
41
42
    /** @var Container */
43
    protected $diContainer;
44
45
    /**
46
     * Container constructor.
47
     *
48
     * @param FileManagerInterface $fileManger
49
     * @param ResolverInterface    $classResolver
50
     * @param ContainerInterface   $diContainer
51
     */
52 5
    public function __construct(FileManagerInterface $fileManger, ResolverInterface $classResolver, Container $diContainer)
53
    {
54 5
        $this->diContainer = $diContainer;
55 5
        $this->fileManger = $fileManger;
56 5
        $this->classResolver = $classResolver;
57 5
    }
58
59
    /**
60
     * Load classes from paths.
61
     *
62
     * @param array $paths Paths for importing
63
     *
64
     * @return $this
65
     */
66 1
    public function loadFromPaths(array $paths)
67
    {
68
        // Iterate all paths and get files
69 1
        foreach ($this->fileManger->scan($paths, ['php']) as $phpFile) {
70
            // Read all classes in given file
71 1
            $this->loadFromClassNames($this->getDefinedClasses(require_once($phpFile)));
72
        }
73
74 1
        return $this;
75
    }
76
77
    /**
78
     * Load classes from class names collection.
79
     *
80
     * @param string[] $classes Collection of class names for resolving
81
     *
82
     * @return $this
83
     */
84 5
    public function loadFromClassNames(array $classes)
85
    {
86
        // Read all classes in given file
87 5
        foreach ($classes as $className) {
88
            // Resolve class metadata
89 4
            $this->classMetadata[$className] = $this->classResolver->resolve(new \ReflectionClass($className));
90
            // Store class in defined scopes
91 4
            foreach ($this->classMetadata[$className]->scopes as $scope) {
92 4
                $this->scopes[$scope][] = $className;
93
            }
94
        }
95
96 5
        return $this;
97
    }
98
99
    /**
100
     * Find class names defined in PHP code.
101
     *
102
     * @param string $php PHP code for scanning
103
     *
104
     * @return string[] Collection of found class names in php code
105
     */
106 2
    protected function getDefinedClasses($php) : array
107
    {
108 2
        $classes = array();
109
110
        // Append php marker for parsing file
111 2
        $php = strpos(is_string($php) ? $php : '', '<?php') !== 0 ? '<?php ' . $php : $php;
112
113 2
        $tokens = token_get_all($php);
114
115 2
        for ($i = 2, $count = count($tokens); $i < $count; $i++) {
116 1
            if ($tokens[$i - 2][0] === T_CLASS
117 1
                && $tokens[$i - 1][0] === T_WHITESPACE
118 1
                && $tokens[$i][0] === T_STRING
119
            ) {
120 1
                $classes[] = $tokens[$i][1];
121
            }
122
        }
123
124 2
        return $classes;
125
    }
126
127
    /**
128
     * Load classes from PHP code.
129
     *
130
     * @param string $php PHP code
131
     *
132
     * @return $this
133
     */
134 1
    public function loadFromCode($php)
135
    {
136
        // TODO: Consider writing cache file and require it
137 1
        eval($php);
138 1
        $this->loadFromClassNames($this->getDefinedClasses($php));
139
140 1
        return $this;
141
    }
142
143
    /**
144
     * Build container class.
145
     *
146
     * @param string|null $containerClass
147
     */
148 2
    public function build($containerClass = null)
0 ignored issues
show
Unused Code introduced by
The parameter $containerClass is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
149
    {
150 2
        foreach ($this->classMetadata as $className => $classMetadata) {
151
            // Process constructor dependencies
152 2
            $constructorDependencies = [];
153 2
            if (array_key_exists('__construct', $classMetadata->methodsMetadata)) {
154 2
                $constructorDependencies = $classMetadata->methodsMetadata['__construct']->dependencies;
155
            }
156
157
            // If this class has services scope
158 2
            if (in_array($className, $this->scopes[self::SCOPE_SERVICES], true)) {
159 1
                $this->diContainer->service($className, $constructorDependencies, $classMetadata->name);
0 ignored issues
show
Documentation introduced by
$constructorDependencies is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$classMetadata->name is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
160
            } else { // Handle not service classes dependencies
161 1
                $this->diContainer->set($className, $constructorDependencies, $classMetadata->name);
0 ignored issues
show
Documentation introduced by
$constructorDependencies is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$classMetadata->name is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
162
            }
163
        }
164
    }
165
}
166