Passed
Push — master ( 96803c...b18ae0 )
by Divine Niiquaye
01:37
created

PhpGenerator::toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 15
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Biurad opensource projects.
7
 *
8
 * PHP version 7.2 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Biurad\DependencyInjection;
19
20
use Exception;
21
use Nette;
22
use Nette\DI\ContainerBuilder;
23
use Nette\DI\Definitions;
24
use Nette\DI\PhpGenerator as NettePhpGenerator;
25
use Nette\DI\ServiceCreationException;
26
use Nette\PhpGenerator as Php;
27
use Throwable;
28
29
/**
30
 * Container PHP code generator.
31
 *
32
 * @author Divine Niiquaye Ibok <[email protected]>
33
 */
34
class PhpGenerator extends NettePhpGenerator
35
{
36
    /** @var ContainerBuilder */
37
    private $builder;
38
39
    /** @var string */
40
    private $className;
41
42
    public function __construct(ContainerBuilder $builder)
43
    {
44
        $this->builder = $builder;
45
46
        parent::__construct($builder);
47
    }
48
49
    /**
50
     * Generates PHP classes. First class is the container.
51
     *
52
     * @param string $className
53
     *
54
     * @return Nette\PhpGenerator\ClassType
55
     */
56
    public function generate(string $className): Nette\PhpGenerator\ClassType
57
    {
58
        $this->className = $className;
59
        $class           = new Nette\PhpGenerator\ClassType($this->className);
60
        $class->setExtends(Container::class);
61
        $class->addMethod('__construct')
62
            ->addBody('parent::__construct($params);')
63
            ->addParameter('params', [])
64
                ->setType('array');
65
66
        foreach ($this->builder->exportMeta() as $key => $value) {
67
            $class->addProperty($key)
68
                ->setProtected()
69
                ->setValue($value);
70
        }
71
72
        $definitions = $this->builder->getDefinitions();
73
        \ksort($definitions);
74
75
        foreach ($definitions as $def) {
76
            $class->addMember($this->generateMethod($def));
77
        }
78
79
        $class->getMethod(Container::getMethodName(ContainerBuilder::THIS_CONTAINER))
80
            ->setReturnType($className)
81
            ->setProtected()
82
            ->setBody('return $this; //container instance is binded to it self');
83
84
        $class->addMethod('initialize');
85
86
        return $class;
87
    }
88
89
    /**
90
     * @param Nette\PhpGenerator\ClassType $class
91
     *
92
     * @throws Throwable
93
     *
94
     * @return string
95
     */
96
    public function toString(Nette\PhpGenerator\ClassType $class): string
97
    {
98
        return '/** @noinspection PhpParamsInspection,PhpMethodMayBeStaticInspection */
99
100
declare(strict_types=1);
101
102
/**
103
 * Main DependencyInjection Container. This class has been auto-generated
104
 * by the Nette Dependency Injection Component.
105
 *
106
 * Automatically detects if "container" property are presented in class or uses
107
 * global container as fallback.
108
 *
109
 */
110
' . (string) $class;
111
    }
112
113
    public function generateMethod(Definitions\Definition $def): Nette\PhpGenerator\Method
114
    {
115
        $name     = $def->getName();
116
        $comment  = 'This service can be accessed by it\'s name in lower case,';
117
        $comment2 = "thus `%s`, using container get or make methods.\n\n@return %s";
118
119
        try {
120
            $method = new Nette\PhpGenerator\Method(Container::getMethodName($name));
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type null; however, parameter $name of Nette\DI\Container::getMethodName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
            $method = new Nette\PhpGenerator\Method(Container::getMethodName(/** @scrutinizer ignore-type */ $name));
Loading history...
121
            $method->setProtected();
122
            $method->setComment(\sprintf($comment . "\n" . $comment2, $name, $def->getType()));
123
            $method->setReturnType($def->getType());
124
            $def->generateMethod($method, $this);
125
126
            return $method;
127
        } catch (Exception $e) {
128
            throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e);
129
        }
130
    }
131
132
    /**
133
     * Formats PHP statement.
134
     *
135
     * @internal
136
     */
137
    public function formatPhp(string $statement, array $args): string
138
    {
139
        \array_walk_recursive($args, function (&$val): void {
140
            if ($val instanceof Definitions\Statement) {
141
                $val = new Php\Literal($this->formatStatement($val));
142
            } elseif ($val instanceof Definitions\Reference) {
143
                $name = $val->getValue();
144
145
                if ($val->isSelf()) {
146
                    $val = new Php\Literal('$service');
147
                } elseif ($name === ContainerBuilder::THIS_CONTAINER) {
148
                    $val = new Php\Literal('$this');
149
                } else {
150
                    $val = ContainerBuilder::literal('$this->getService(?)', [$name]);
151
                }
152
            }
153
        });
154
155
        return (new Nette\PhpGenerator\Dumper())->format($statement, ...$args);
156
    }
157
158
    public function getClassName(): ?string
159
    {
160
        return $this->className;
161
    }
162
}
163