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 / PhpGenerator.php

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

170 lines 6.6 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;
9
10 use Packetery\Nette;
11 use Packetery\Nette\DI\Definitions\Reference;
12 use Packetery\Nette\DI\Definitions\Statement;
13 use Packetery\Nette\PhpGenerator as Php;
14 use Packetery\Nette\Utils\Strings;
15 /**
16 * Container PHP code generator.
17 */
18 class PhpGenerator
19 {
20 use \Packetery\Nette\SmartObject;
21 /** @var ContainerBuilder */
22 private $builder;
23 /** @var string */
24 private $className;
25 public function __construct(ContainerBuilder $builder)
26 {
27 $this->builder = $builder;
28 }
29 /**
30 * Generates PHP classes. First class is the container.
31 */
32 public function generate(string $className) : Php\ClassType
33 {
34 $this->className = $className;
35 $class = new Php\ClassType($this->className);
36 $class->setExtends(Container::class);
37 $class->addMethod('__construct')->addBody('parent::__construct($params);')->addParameter('params', [])->setType('array');
38 foreach ($this->builder->exportMeta() as $key => $value) {
39 $class->addProperty($key)->setProtected()->setValue($value);
40 }
41 $definitions = $this->builder->getDefinitions();
42 \ksort($definitions);
43 foreach ($definitions as $def) {
44 $class->addMember($this->generateMethod($def));
45 }
46 $class->getMethod(Container::getMethodName(ContainerBuilder::ThisContainer))->setReturnType($className)->setBody('return $this;');
47 $class->addMethod('initialize')->setReturnType('void');
48 return $class;
49 }
50 public function toString(Php\ClassType $class) : string
51 {
52 return '/** @noinspection PhpParamsInspection,PhpMethodMayBeStaticInspection */
53
54 declare(strict_types=1);
55
56 ' . $class->__toString();
57 }
58 public function addInitialization(Php\ClassType $class, CompilerExtension $extension) : void
59 {
60 $closure = $extension->getInitialization();
61 if ($closure->getBody()) {
62 $class->getMethod('initialize')->addBody('// ' . $extension->prefix(''))->addBody("({$closure})();");
63 }
64 }
65 public function generateMethod(Definitions\Definition $def) : Php\Method
66 {
67 $name = $def->getName();
68 try {
69 $method = new Php\Method(Container::getMethodName($name));
70 $method->setPublic();
71 $method->setReturnType($def->getType());
72 $def->generateMethod($method, $this);
73 return $method;
74 } catch (\Throwable $e) {
75 throw new ServiceCreationException("Service '{$name}': " . $e->getMessage(), 0, $e);
76 }
77 }
78 /**
79 * Formats PHP code for class instantiating, function calling or property setting in PHP.
80 */
81 public function formatStatement(Statement $statement) : string
82 {
83 $entity = $statement->getEntity();
84 $arguments = $statement->arguments;
85 switch (\true) {
86 case \is_string($entity) && Strings::contains($entity, '?'):
87 // PHP literal
88 return $this->formatPhp($entity, $arguments);
89 case \is_string($entity):
90 // create class
91 return $arguments ? $this->formatPhp("new {$entity}(...?:)", [$arguments]) : $this->formatPhp("new {$entity}", []);
92 case \is_array($entity):
93 switch (\true) {
94 case $entity[1][0] === '$':
95 // property getter, setter or appender
96 $name = \substr($entity[1], 1);
97 if ($append = \substr($name, -2) === '[]') {
98 $name = \substr($name, 0, -2);
99 }
100 $prop = $entity[0] instanceof Reference ? $this->formatPhp('?->?', [$entity[0], $name]) : $this->formatPhp('?::$?', [$entity[0], $name]);
101 return $arguments ? $this->formatPhp(($append ? '?[]' : '?') . ' = ?', [new Php\Literal($prop), $arguments[0]]) : $prop;
102 case $entity[0] instanceof Statement:
103 $inner = $this->formatPhp('?', [$entity[0]]);
104 if (\substr($inner, 0, 4) === 'new ') {
105 $inner = "({$inner})";
106 }
107 return $this->formatPhp('?->?(...?:)', [new Php\Literal($inner), $entity[1], $arguments]);
108 case $entity[0] instanceof Reference:
109 return $this->formatPhp('?->?(...?:)', [$entity[0], $entity[1], $arguments]);
110 case $entity[0] === '':
111 // function call
112 return $this->formatPhp('?(...?:)', [new Php\Literal($entity[1]), $arguments]);
113 case \is_string($entity[0]):
114 // static method call
115 return $this->formatPhp('?::?(...?:)', [new Php\Literal($entity[0]), $entity[1], $arguments]);
116 }
117 }
118 throw new \Packetery\Nette\InvalidStateException();
119 }
120 /**
121 * Formats PHP statement.
122 * @internal
123 */
124 public function formatPhp(string $statement, array $args) : string
125 {
126 return (new Php\Dumper())->format($statement, ...$this->convertArguments($args));
127 }
128 public function convertArguments(array $args) : array
129 {
130 \array_walk_recursive($args, function (&$val) : void {
131 if ($val instanceof Statement) {
132 $val = new Php\Literal($this->formatStatement($val));
133 } elseif ($val instanceof Reference) {
134 $name = $val->getValue();
135 if ($val->isSelf()) {
136 $val = new Php\Literal('$service');
137 } elseif ($name === ContainerBuilder::ThisContainer) {
138 $val = new Php\Literal('$this');
139 } else {
140 $val = ContainerBuilder::literal('$this->getService(?)', [$name]);
141 }
142 }
143 });
144 return $args;
145 }
146 /**
147 * Converts parameters from Definition to PhpGenerator.
148 * @return Php\Parameter[]
149 */
150 public function convertParameters(array $parameters) : array
151 {
152 $res = [];
153 foreach ($parameters as $k => $v) {
154 $tmp = \explode(' ', \is_int($k) ? $v : $k);
155 $param = $res[] = new Php\Parameter(\end($tmp));
156 if (!\is_int($k)) {
157 $param->setDefaultValue($v);
158 }
159 if (isset($tmp[1])) {
160 $param->setType($tmp[0]);
161 }
162 }
163 return $res;
164 }
165 public function getClassName() : ?string
166 {
167 return $this->className;
168 }
169 }
170