1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Symfony-Util package. |
5
|
|
|
* |
6
|
|
|
* (c) Jean-Bernard Addor |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Tests\Component; |
13
|
|
|
|
14
|
|
|
use Symfony\Bridge\Twig\TwigEngine; |
15
|
|
|
use Symfony\Bundle\FrameworkBundle\Client; |
16
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; |
17
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver; // Many controller resolver exists! |
18
|
|
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass; |
19
|
|
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass; |
20
|
|
|
// use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; |
21
|
|
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ControllerArgumentValueResolverPass; // 2 versions of this! |
22
|
|
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; |
23
|
|
|
use Symfony\Bundle\FrameworkBundle\FrameworkBundle; |
24
|
|
|
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; |
25
|
|
|
use Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader; |
26
|
|
|
use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; |
27
|
|
|
use Symfony\Bundle\FrameworkBundle\Routing\Router; |
28
|
|
|
use Symfony\Component\Config\Loader\LoaderInterface; |
29
|
|
|
use Symfony\Component\Config\Loader\LoaderResolver; |
30
|
|
|
use Symfony\Component\Config\ResourceCheckerConfigCacheFactory; |
31
|
|
|
use Symfony\Component\DependencyInjection\Compiler\PassConfig; |
32
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder; |
33
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
34
|
|
|
use Symfony\Component\DependencyInjection\Reference; |
35
|
|
|
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; |
36
|
|
|
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; |
37
|
|
|
use Symfony\Component\HttpFoundation\RequestStack; |
38
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver; |
39
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver; |
40
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver; |
41
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver; |
42
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver; |
43
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver; |
44
|
|
|
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver; |
45
|
|
|
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory; |
46
|
|
|
// use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass; // 2 versions of this! |
47
|
|
|
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; |
48
|
|
|
use Symfony\Component\HttpKernel\EventListener\RouterListener; |
49
|
|
|
use Symfony\Component\HttpKernel\HttpKernel; |
50
|
|
|
use Symfony\Component\HttpKernel\Kernel; // Manages an environment made of bundles. HttpKernel is needed in addition! |
51
|
|
|
use Symfony\Component\HttpKernel\UriSigner; |
52
|
|
|
use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; |
53
|
|
|
use Symfony\Component\Routing\Generator\UrlGenerator; |
54
|
|
|
use Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader; |
55
|
|
|
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; |
56
|
|
|
use Symfony\Component\Routing\RouteCollectionBuilder; |
57
|
|
|
use Symfony\Component\Templating\EngineInterface; |
58
|
|
|
use Symfony\Component\Templating\TemplateNameParser; |
59
|
|
|
use Symfony\Component\Templating\TemplateNameParserInterface; |
60
|
|
|
use SymfonyUtil\Controller\EngineAsArgumentController; |
61
|
|
|
use SymfonyUtil\Controller\TemplatingController; |
62
|
|
|
|
63
|
|
|
// use Twig_Environment; |
64
|
|
|
// use Twig_Loader_Array; |
65
|
|
|
// use Twig_LoaderInterface; |
66
|
|
|
|
67
|
|
|
class AppKernel extends Kernel |
68
|
|
|
{ |
69
|
|
|
use MicroKernelTrait; |
70
|
|
|
|
71
|
|
|
public function registerBundles() |
72
|
|
|
{ |
73
|
|
|
return [ |
|
|
|
|
74
|
|
|
// new FrameworkBundle(), |
75
|
|
|
]; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
protected function configureRoutes(RouteCollectionBuilder $routes) |
79
|
|
|
{ |
80
|
|
|
$routes->add('/', EngineAsArgumentController::class, 'index'); |
81
|
|
|
$routes->add('/argument', EngineAsArgumentController::class, 'argument'); |
82
|
|
|
$routes->add('/constructor', TemplatingController::class, 'constructor'); |
83
|
|
|
// $routes->add('/', EngineAsArgumentFrameworkController::class, 'index'); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public function registerContainerConfiguration(LoaderInterface $loader) |
87
|
|
|
{ |
88
|
|
|
$loader->load(function (ContainerBuilder $container) use ($loader) { |
89
|
|
|
$this->configureContainer($container, $loader); |
90
|
|
|
|
91
|
|
|
$container->addObjectResource($this); ////////////// TODO understand and consider necessity. |
92
|
|
|
}); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) |
|
|
|
|
96
|
|
|
{ |
97
|
|
|
// https://symfony.com/doc/current/service_container.html |
98
|
|
|
// HttpKernel has to be added! |
99
|
|
|
// TODO: find the way the container is compiled in microKernel, be sure it works.... |
100
|
|
|
// TODO: find the right way to configure the service_container!! cheking... |
101
|
|
|
// It does not replace the framework yet, but this is probably based on a config older than Symfony 3.3 |
102
|
|
|
// TODO: reaorganize in different files by dependecy and use eg. HttpKernel, Matcher, ... allowing for alternatives |
103
|
|
|
// TODO: Read doc di component and load the config xml files from the framework bundle |
104
|
|
|
|
105
|
|
|
$c->register('kernel')->setSynthetic(true); |
106
|
|
|
$c->set('kernel', $this); |
107
|
|
|
|
108
|
|
|
// $c->register('service_container')->setSynthetic(true); |
109
|
|
|
// $c->set('service_container', $c); |
110
|
|
|
// https://github.com/symfony/dependency-injection/blob/master/Container.php |
111
|
|
|
// Seems to be included by default! |
112
|
|
|
|
113
|
|
|
$c->register('event_dispatcher', ContainerAwareEventDispatcher::class) // services.xml |
114
|
|
|
// TODO: Obsolete use EventDispatcher instead, but may cause other problems |
115
|
|
|
->addArgument(new Reference('service_container')) |
116
|
|
|
; |
117
|
|
|
|
118
|
|
|
$c->register('http_kernel', HttpKernel::class) // services.xml |
119
|
|
|
->addArgument(new Reference('event_dispatcher')) |
120
|
|
|
->addArgument(new Reference('controller_resolver')) |
121
|
|
|
->addArgument(new Reference('request_stack')) |
122
|
|
|
->addArgument(new Reference('argument_resolver')) |
123
|
|
|
; |
124
|
|
|
|
125
|
|
|
$c->register('request_stack', RequestStack::class); // services.xml |
126
|
|
|
|
127
|
|
|
$c->register('uri_signer', UriSigner::class) // services.xml |
128
|
|
|
->addArgument('12345') // app config |
129
|
|
|
; |
130
|
|
|
|
131
|
|
|
$c->register('config_cache_factory', ResourceCheckerConfigCacheFactory::class) // services.xml |
132
|
|
|
->addArgument([]) |
133
|
|
|
; |
134
|
|
|
$c->register('controller_name_converter', ControllerNameParser::class) // web.xml |
135
|
|
|
->setPublic(false) |
136
|
|
|
->addTag('monolog.logger', ['channel' => 'request']) |
137
|
|
|
->addArgument(new Reference('kernel')) |
138
|
|
|
; |
139
|
|
|
|
140
|
|
|
$c->register('controller_resolver', ControllerResolver::class) // web.xml |
141
|
|
|
// ->setPublic(false) |
142
|
|
|
->addTag('monolog.logger', ['channel' => 'request']) |
143
|
|
|
->addArgument(new Reference('service_container')) |
144
|
|
|
->addArgument(new Reference('controller_name_converter')) |
145
|
|
|
->addArgument(new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) |
146
|
|
|
; |
147
|
|
|
|
148
|
|
|
$c->register('argument_metadata_factory', ArgumentMetadataFactory::class) // web.xml |
149
|
|
|
// ->setPublic(false) |
150
|
|
|
; |
151
|
|
|
|
152
|
|
|
$c->register('argument_resolver', ArgumentResolver::class) // web.xml |
153
|
|
|
// ->setPublic(false) |
154
|
|
|
->addArgument(new Reference('argument_metadata_factory')) |
155
|
|
|
->addArgument([]) |
156
|
|
|
; |
157
|
|
|
|
158
|
|
|
$c->setParameter('router.resource', 'kernel:loadRoutes'); // resource_type: service |
159
|
|
|
// $c->setParameter('router.resource', new Expression('service("kernel").loadRoutes')); |
160
|
|
|
// $c->setParameter('router.resource', MicroKernel::class . ':loadRoutes'); |
161
|
|
|
// $c->setParameter('router.resource', new Reference('kernel') . ':loadRoutes'); |
162
|
|
|
// $c->setParameter('router.resource', MicroKernel::loadRoutes); |
163
|
|
|
// $c->setParameter('router.resource', self::loadRoutes); |
164
|
|
|
// $c->setParameter('router.resource', parent::loadRoutes); |
165
|
|
|
// $c->setParameter('router.resource', [new Reference('kernel'), 'loadRoutes']); |
166
|
|
|
// $c->setParameter('router.resource', ['kernel', 'loadRoutes']); |
167
|
|
|
// $c->setParameter('router.resource', [MicroKernel::class, 'loadRoutes']); |
168
|
|
|
|
169
|
|
|
$c->setParameter('router.cache_class_prefix', $c->getParameter('kernel.container_class')); |
170
|
|
|
// symfony/framework-bundle/DependencyInjection/FrameworkExtension.php |
171
|
|
|
$c->setParameter('router.options.generator_class', UrlGenerator::class); // routing.xml |
172
|
|
|
$c->setParameter('router.options.generator_base_class', UrlGenerator::class); // routing.xml |
173
|
|
|
$c->setParameter('router.options.generator_dumper_class', PhpGeneratorDumper::class); // routing.xml |
174
|
|
|
$c->setParameter('router.options.generator.cache_class', '%router.cache_class_prefix%UrlGenerator'); // routing.xml |
175
|
|
|
$c->setParameter('router.options.matcher_class', RedirectableUrlMatcher::class); // routing.xml |
176
|
|
|
$c->setParameter('router.options.matcher_base_class', RedirectableUrlMatcher::class); // routing.xml |
177
|
|
|
$c->setParameter('router.options.matcher_dumper_class', PhpMatcherDumper::class); // routing.xml |
178
|
|
|
$c->setParameter('router.options.matcher.cache_class', '%router.cache_class_prefix%UrlMatcher'); // routing.xml |
179
|
|
|
|
180
|
|
|
$c->setParameter('router.request_context.host', 'localhost'); // routing.xml |
181
|
|
|
$c->setParameter('router.request_context.scheme', 'http'); // routing.xml |
182
|
|
|
$c->setParameter('router.request_context.base_url', ''); // routing.xml |
183
|
|
|
|
184
|
|
|
$c->setParameter('request_listener.http_port', 80); |
185
|
|
|
$c->setParameter('request_listener.https_port', 443); |
186
|
|
|
// symfony/framework-bundle/DependencyInjection/FrameworkExtension.php |
187
|
|
|
|
188
|
|
|
$c->register('routing.resolver', LoaderResolver::class) // routing.xml |
189
|
|
|
->setPublic(false) |
190
|
|
|
; |
191
|
|
|
|
192
|
|
|
$c->register('routing.loader.service', ServiceRouterLoader::class) // routing.xml |
193
|
|
|
// ->setPublic(false) |
194
|
|
|
->addTag('routing.loader') |
195
|
|
|
->addArgument(new Reference('service_container')) |
196
|
|
|
; |
197
|
|
|
$c->register('routing.loader', DelegatingLoader::class) // routing.xml |
198
|
|
|
->addArgument(new Reference('controller_name_converter')) |
199
|
|
|
->addArgument(new Reference('routing.resolver')) |
200
|
|
|
; |
201
|
|
|
//... |
202
|
|
|
$c->register('router.default', Router::class) // routing.xml |
203
|
|
|
// ->setPublic(false) |
204
|
|
|
->addTag('monolog.logger', ['channel' => 'router']) |
205
|
|
|
->addArgument(new Reference('service_container')) |
206
|
|
|
->addArgument('%router.resource%') |
207
|
|
|
->addArgument([ |
208
|
|
|
'cache_dir' => '%kernel.cache_dir%', |
209
|
|
|
'debug' => '%kernel.debug%', |
210
|
|
|
'generator_class' => '%router.options.generator_class%', |
211
|
|
|
'generator_base_class' => '%router.options.generator_base_class%', |
212
|
|
|
'generator_dumper_class' => '%router.options.generator_dumper_class%', |
213
|
|
|
'generator_cache_class' => '%router.options.generator.cache_class%', |
214
|
|
|
'matcher_class' => '%router.options.matcher_class%', |
215
|
|
|
'matcher_base_class' => '%router.options.matcher_base_class%', |
216
|
|
|
'matcher_dumper_class' => '%router.options.matcher_dumper_class%', |
217
|
|
|
'matcher_cache_class' => '%router.options.matcher.cache_class%', |
218
|
|
|
'resource_type' => 'service', ////////////////////! |
219
|
|
|
]) |
220
|
|
|
->addArgument(new Reference('router.request_context', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) |
221
|
|
|
->addArgument(new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) |
222
|
|
|
->addMethodCall('setConfigCacheFactory', [new Reference('config_cache_factory')]) |
223
|
|
|
; |
224
|
|
|
$c->setAlias('router', 'router.default'); |
225
|
|
|
|
226
|
|
|
$c->register('router_listener', RouterListener::class) // routing.xml |
227
|
|
|
->addTag('kernel.event_subscriber') |
228
|
|
|
->addTag('monolog.logger', ['channel' => 'request']) |
229
|
|
|
->addArgument(new Reference('router')) |
230
|
|
|
->addArgument(new Reference('request_stack')) |
231
|
|
|
->addArgument(new Reference('router.request_context', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) |
232
|
|
|
->addArgument(new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) |
233
|
|
|
; |
234
|
|
|
|
235
|
|
|
$c->autowire(TemplateNameParser::class) |
236
|
|
|
->setAutoconfigured(true) |
237
|
|
|
->setPublic(false); |
238
|
|
|
$c->setAlias(TemplateNameParserInterface::class, TemplateNameParser::class); |
239
|
|
|
|
240
|
|
|
$c->autowire(\Twig_Loader_Array::class, \Twig_Loader_Array::class) |
241
|
|
|
->setArgument('$templates', ['index.html.twig' => 'Hello Component!']) |
242
|
|
|
->setAutoconfigured(true) |
243
|
|
|
->setPublic(false); |
244
|
|
|
$c->setAlias(\Twig_LoaderInterface::class, \Twig_Loader_Array::class); |
245
|
|
|
|
246
|
|
|
$c->autowire(\Twig_Environment::class, \Twig_Environment::class) |
247
|
|
|
->setAutoconfigured(true) |
248
|
|
|
->setPublic(false); |
249
|
|
|
$c->setAlias(\Twig\Environment::class, \Twig_Environment::class); |
250
|
|
|
|
251
|
|
|
$c->autowire(TwigEngine::class) |
252
|
|
|
->setAutoconfigured(true) |
253
|
|
|
->setPublic(false); |
254
|
|
|
$c->setAlias(EngineInterface::class, TwigEngine::class); |
255
|
|
|
$c->setAlias('templating', TwigEngine::class); // Read Symfony source code to understand! |
256
|
|
|
|
257
|
|
View Code Duplication |
if (\in_array($this->getEnvironment(), ['test'], true)) { |
|
|
|
|
258
|
|
|
$c->autowire('test.client', Client::class) |
259
|
|
|
->setPublic(true); // Public needed! |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
//Controllers |
263
|
|
|
$c->autowire(EngineAsArgumentController::class) |
264
|
|
|
->setAutoconfigured(true) |
265
|
|
|
->addTag('controller.service_arguments') |
266
|
|
|
->setPublic(true); |
267
|
|
|
|
268
|
|
|
$c->autowire(TemplatingController::class) |
269
|
|
|
->setAutoconfigured(true) |
270
|
|
|
// ->addTag('controller.service_arguments') |
271
|
|
|
->setPublic(true); |
272
|
|
|
|
273
|
|
|
$c->autowire(EngineAsArgumentFrameworkController::class) |
274
|
|
|
->setAutoconfigured(true) |
275
|
|
|
->addTag('controller.service_arguments') |
276
|
|
|
->setPublic(true); |
277
|
|
|
|
278
|
|
|
// https://github.com/symfony/framework-bundle/blob/current/Resources/config/web.xml |
279
|
|
|
$c->autowire(RequestAttributeValueResolver::class) // argument_resolver.request_attribute |
280
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => 100])->setPublic(false); |
281
|
|
|
$c->autowire(RequestValueResolver::class) // argument_resolver.request |
282
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => 50])->setPublic(false); |
283
|
|
|
$c->autowire(SessionValueResolver::class) // argument_resolver.session |
284
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => 50])->setPublic(false); |
285
|
|
|
$c->autowire(ServiceValueResolver::class) // argument_resolver.service |
286
|
|
|
->setArgument('$container', new Reference('service_container')) |
287
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => -50])->setPublic(false); |
288
|
|
|
$c->autowire(DefaultValueResolver::class) // argument_resolver.default |
289
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => -100])->setPublic(false); |
290
|
|
|
$c->autowire(VariadicValueResolver::class) // argument_resolver.variadic |
291
|
|
|
->addTag('controller.argument_value_resolver', ['priority' => -150])->setPublic(false); |
292
|
|
|
// https://symfony.com/doc/current/controller/argument_value_resolver.html |
293
|
|
|
// http://api.symfony.com/3.3/Symfony/Component/HttpKernel/Controller/ArgumentResolver/ServiceValueResolver.html |
294
|
|
|
// https://symfony.com/doc/current/service_container/tags.html |
295
|
|
|
|
296
|
|
|
$c->addCompilerPass(new RoutingResolverPass()); |
|
|
|
|
297
|
|
|
$c->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); |
298
|
|
|
// $c->addCompilerPass(new AddConsoleCommandPass()); // Dependency need! |
299
|
|
|
$c->addCompilerPass(new AddCacheWarmerPass()); |
|
|
|
|
300
|
|
|
$c->addCompilerPass(new AddCacheClearerPass()); |
|
|
|
|
301
|
|
|
$c->addCompilerPass(new ControllerArgumentValueResolverPass()); |
|
|
|
|
302
|
|
|
$c->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); |
303
|
|
|
|
304
|
|
|
// Extensions |
305
|
|
|
// $c->loadFromExtension('framework', [ |
306
|
|
|
// 'secret' => 'NotSecret', // What about use $ uuid -v4 or $ uuidgen |
307
|
|
|
// ]); |
308
|
|
|
} |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
// Information for Service "test.client" |
312
|
|
|
// ===================================== |
313
|
|
|
|
314
|
|
|
// ---------------- --------------------------------------- |
315
|
|
|
// Option Value |
316
|
|
|
// ---------------- --------------------------------------- |
317
|
|
|
// Service ID test.client |
318
|
|
|
// Class Symfony\Bundle\FrameworkBundle\Client |
319
|
|
|
// Tags - |
320
|
|
|
// Public yes |
321
|
|
|
// Synthetic no |
322
|
|
|
// Lazy no |
323
|
|
|
// Shared no |
324
|
|
|
// Abstract no |
325
|
|
|
// Autowired no |
326
|
|
|
// Autoconfigured no |
327
|
|
|
// ---------------- --------------------------------------- |
328
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.