I am new to zend framework 3 and I am trying to create a new route type that can search in the database to match the route path. I am using doctrine orm and unfortunately I don't know how to inject the entity manager inside the route class.
I tried defining a factory class for the route to have access to the service manager but that didn't work because the route classes must implement Zend\Router\Http\RouteInterface which states that the route class must contain it's own factory defined as "function factory($options)".
Can anyone please help?
Thank you very much.
In the way you ask the question you have to write your custom Router strategy relying on zend-router's interfaces and abstractions.
For eg. ZF support different router strategies to match the URL (as in any modern framework) but you need to write the custom router strategy to access the DB and return what controller/action should be executed.
To be honest if you are new to ZF3 maybe try to solve the problem on little bit less advanced way.
Other solution, maybe you can create dynamic router and pass URL_SLUG.
Than you will have one action where you will check what content you should load from the DB by URL_SLUG (or any other ID you choose).
Related
I'm a novice developer working on an existing Laravel app. I'm looking through the project and I don't see any controllers constructed anywhere but the controllers all have constructor functions.
Is this a Laravel thing or am I just missing something? Is controller instantiation handled in the routes or something? If so, is it bad practice to call a controller constructor manually?(although I can't think of a case offhand where you would want to do this)
From the docs: "The Laravel service container is used to resolve all Laravel controllers."
And: I often create a base controller in my apps, therefore I also have constructor in my extended controllers. It could also be useful to inject dependencies "properly" like shown in this example:
https://laravel.com/docs/5.2/controllers#dependency-injection-and-controllers
Update 2020 (this should have been much sooner). There can be a new class for each controller action. Each controller can be named by the action it is going to do, with an Invoke() method. Consider "Action Domain Responder" (ADR).
Why do I want to do this? Controllers do not necessarily adhere to SRP, and I'm not about to go creating a new class for each of, what is effectively, a controller 'action'. Therefore, a controller should not have everything injected via constructor, but the relevant method being called should be able to state explicitly "I require these objects" and another method "these other objects".
As of Symfony 2.8, the Dependency Injection component now provides auto-wiring for your services if you provide autowire: true in services.yml.
I'm defining my controller as a service, like so:
test_controller:
class: AppBundle\Controller\TestController
autowire: true
My controller looks as follows:
class TestController
{
public function indexAction(TestClass1 $tc1, $id)
{
return new Response('The slug is: ' . $id);
}
}
You will notice I'm typehinting for TestClass, which is just an empty class. However, the following error appears when I refresh the page:
What do I need to change in my services.yml file to have auto wiring dependency injection in my controller method? Just a note, the issue isn't because I have an $id 'slug' afterwards. Removing it does nothing.
Edit: I've created a bundle allowing to do more or less what you want called DunglasActionBundle.
Disclaimer: I'm the author of the Symfony autowiring system.
The Symfony Dependency Injection Component (and the autowiring system is part of it) doesn't work that way. It only allows to automatically inject dependencies in the class constructor of services and knows nothing about controller classes, actions and other parts of the HttpKernel Component.
It's not currently possible to do what you want to do. Initially, the autowiring system has been designed for domain services, not for controllers.
It should be possible to bridge the autowiring system with controller parameters using a custom param converter. However, I'll suggest you take another way I've first described here:
There is another approach I want to discuss since several time but I
did not have the time to blog about it.
It's a derivate of/similar to the ADR pattern, applied to Symfony.
An action is a single class with a __invoke() method containing all it's
logic (should be only some lines of glue code to call the domain and
the responder).
Actions are registered as a service (it can be
automated using a compiler pass and some conventions, similar to how
we discover controllers right now, with the ability to override the
definition if needed)
On such action services, autowiring is enabled.
It means that almost as easy as current controllers to use for the
developper, but with an explicit dependency graph and a better
reusability. Only things that are really necessary are injected. In
fact, it's already doable to use such system with Symfony. We do it in
API Platform master. Here is one action for instance:
https://github.com/dunglas/DunglasApiBundle/blob/master/Action/PostCollectionAction.php
In this implementation I also rely a lof on kernel events to be able
to plug and play some sort of logic (persistence, validation...) in a
decoupled manner but it's out of scope.
I'm really new to Symfony 2, coming from CI and trying to get me head around where the correct places for everything should go. I've got a bundle that takes care of the few main page types I have, but here's one page element that I use in multiple pages, that can have different configurations for each page.
The logical way around this (as far as I can see) is to have a single class somewhere that all the pages can use... this isn't to be accessed by users so shouldn't go in the controller I'm guessing but where should I put this class?
Make a 'core' type folder within my bundle. Are there naming best practices for this?
Should it go in the vendor folder or is this just for third party bundles?
Make another bundle to somehow use this code... seems a bit overkill for one or two classes?
other?
I guess what you need is to create a service. You can create your own class that has it's own logic and retrieve it using the service container in the controller. The following example is available at Symfony Service Container Docs
$mailer = $this->get('my_mailer');
$mailer->send('ryan#foobar.net', ...);
To make that class available you have to add it in the service.yml file of your bundle like this:
services:
my_mailer:
class: "%my_mailer.class%"
arguments: ["%my_mailer.transport%"]
You can add any other service or parameter to your class via the arguments
More info here: http://symfony.com/doc/current/book/service_container.html
I just followed the http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1 articles, and have some questions about the DI container.
Let's say I want to fire an event inside my controller, how would i get the dispatcher inside my controller?
I'm starting my test framework through
$c->get('app')->handle($request);
where 'app' is the Symfony\HttpKernel. How can i set the dependencies to the container? Let's say I have a view engine, defined in the container
$c->register('view.engine', 'Core\ViewEngine');
and I want to give that object, or resolve that object, inside my Controller to render some views. It's the same problem with the event fire, I don't have access to those values inside my controller ... How is a DI container supposed to work in situations like this?
Thanks!
There are different approaches. You might want to read through the silex documentation as a next step. In silex, the application itself is a DI container. You might also read through the introduction to Symfony 2 documentation.
The most straight forward approach (and the one used by S2 as a default) is to inject the DI container itself into your controller. The controller can then pull out services such as the dispatcher as needed.
A "better" approach is to inject the dispatcher along with whatever else the controller needs directly into the controller. It's "better" because the controller itself does not need access to the container. But it's more difficult since a controller often needs a number of services just to it's job.
==============================================
How would I inject the container in the controller though?
That is where looking at existing frameworks starts to come in handy. Remember that HTTPKernel is a component and not a framework. How you use it is up to you.
In Symfony 2 the app object is actually derived from Kernel and not HTTPKernel. The Kernel in turn contains an instance of HTTPKernel as well as an instance of the container.
There are several approaches you might take. There is no single "correct" one.
If you look into HTTPKernel::handleRaw you will find:
$controller = $this->resolver->getController($request))
You might make your own controller resolver object which would inject the container after creating the controller. Just one possibility.
I have some fairly complex routing rules, that are only achievable with custom code, and not with the default router.
The router has also to take into account the domain name.
Is it possible (and how) to define my own Router class, that would have a method accepting a Request and returning the bundle/controller name?
To achieve what you're asking, you don't need to completely redefine the router
You can simply write your own class that implements UrlMatcherInterface. If you want to be able to generate URLs that match your scheme as well, you'll have to create another class which overrides UrlGeneratorInterface as well.
In order to take into account the domain name, you'll need to use RequestContext, which is passed to their constructors (it's not well documented, but check Router::get{Matcher,Generator} for the details).
Once your classes are prepared, you can inject them into the router simply by overriding the parameters "router.options.generator_class" and "router.options.matcher_class" in your bundle.
However, it may not be the best approach for what you want - overriding parts of the router like that requires a lot of care to preserve all of the caching.
You might want to consider using Symfony2's normal router, but handing it different route files depending on what the request's domain is. This can be done easily if you configure your web server to set a variable or execute a different front controller depending on the domain name.
Using that information, you can then load a different 'environment' per-request, with the only difference between the different environments being that they use different routing files.
After studying Matthias Noback's tutorial, I have made a slight modification for my CRUD routing builder.
Before and after using CrudLoader can be seen here in routing/crud/acompetencies.yml
It is just a workaround or misuse of resource as you can see in this CrudLoader class.
I don't know if it is right or bad practice. It seems to work well.
refer sonata admin bundle which is having custom routing class classes
symfony 2.5 requires parameter for custom matcher: router.options.matcher_base_class
and class which implements Symfony\Component\Routing\Matcher\RequestMatcherInterface