Upgrade to Symfony flex (3.4) - Problems when there are many bundles - php

I have an application with symfony 3.4, and I am updating it to flex and then going to version 4.
The problem is that i have many bundles, and in FLEX they do not work with these ... so I am looking for a way to maintain my bundles ...
This is what i have in my SRC folder (controller, entity and repository are empty):
> SRC
> CONTROLLER
> ENTITY
> REPOSITORY
> Kernel.php
> .htaccess
> H360 (the place of my bundles)
> comercialBundle
> jasperBundle
> generalBundle
> ...
This is the error message it returns to me:
In FileLoader.php line 168:
Expected to find class "App\H360\JasperBundle\Controller\DefaultController" in file "C:\inetpub\wwwroot\360forhotels\src/H360\JasperBundle\Controller\DefaultController.php" while importing services from resource "../src/*", but it was not found! Check the name
space prefix used with the resource in C:\inetpub\wwwroot\360forhotels\config/services.yaml (which is loaded in resource "C:\inetpub\wwwroot\360forhotels\config/services.yaml").
In FileLoader.php line 157:
Expected to find class "App\H360\JasperBundle\Controller\DefaultController" in file "C:\inetpub\wwwroot\360forhotels\src/H360\JasperBundle\Controller\DefaultController.php" while importing services from resource "../src/*", but it was not found! Check the name
space prefix used with the resource.
So this is part of my "services.yaml" file (I know it's not right):
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']

Start by adding H360 to the exclude section under App. Trying to autowire complete bundles will not only result in those App prefix errors but will cause a considerable amount of fun besides. Hopefully your bundles are already working so there will be no need yo autowire them. In fact you might consider just turning autowire off completely until you get your app working.
You might then have issues with the psr4 section of composer.json. You need to setup autoloading (not autowire) so you classes can be loaded.

Related

How to tag services by path in Symfony?

In a Symfony application, how can I automatically tag all classes in a specific directory?
In services.yaml I have:
services:
App\Service\TaggableServicesDirectory\:
resource: '../src/Service/TaggableServicesDirectory/*'
tags: ['app.my_tag']
However, those services don't get actually tagged. I can see that by running bin/console debug:container --tag=app.my_tag, which returns an error about not existing tag.
I have also tried tagging by parent class:
services:
_instanceof:
App\Service\TaggableServicesDirectory\AbstractTaggableService:
tags: ['app.my_tag']
which works as expected, so I know that path and tag name are correct. However, tagging by parent class is not ideal for my use case.
EDIT: the configuration from the first example works as expected on a new Symfony project, so it's likely some other incorrect configuration on my main project.
Unfortunately, you can't specify the directory as in your example. But you can do it manually by specifying class name and tag individually for each object.
services:
App\Service\TaggableServicesDirectory\ClassOne:
tags: ['app.my_tag']
However, to bind the tag automatically, use the interface as recommended in the symfony documentation.
#[AutoconfigureTag('app.my_tag')]
interface CustomTagInterface
{
// ...
}
Then implement this interface in your classes.

Fallback route in Symfony 4 while using annotation routing

I'm currently using routing via controller annotations in a Symfony 4 application.
I am trying to route all requests that don't match an existing annotation (e.g. http://example.com/route-that-isnt-defined) to a specific controller and function (e.g. DefaultController::dynamicPage() which has logic to find if I should be serving content or triggering a NotFoundHttpException).
Defining the route for DefaultController::dynamicPage() as #Route("/{param}") precedes and intercepts all other defined routes, making them inaccesible.
I have tried this solution for Symfony 3, not knowing if it will work but get stuck on what "AppBundle" is supposed to refer to, as it's not something that exists in my project.
Currently, my routes.yaml only has one route in it for the index, as all other named routes are defined via annotations:
index:
path: /
controller: App\Controller\DefaultController::index
I am looking for either the proper way to implement the link Symfony 3 solution in Symfony 4, or an alternative method of achieving the routing I want without doing something convoluted like extending the exceptions controller and inserting routing functionality into cases of NotFoundHttpException.
You could try adding a kernel event listener that would handle the kernel.exception event, and for cases where the exception is a NotFoundHttpException you'd return your custom response instead of the 404 Not Found page.
This could be quite flexible since you can implement any custom logic in such listener.
I haven't moved to sf4 yet, but isn't this problem just related to the order of the routes being evaluated? I.e. you could try by just adding explicit definition to load the DefaultController.php annotations in your routes.yml as the last element? I.e. something like this should do the trick (works in sf2.8 at least):
app_annotations:
resource: '#MyBundle/Controller/'
type: annotation
fallback_annotations:
resource: '#MyBundle/Controller/DefaultController.php'
type: annotation
or if that doesn't work in sf4 (if it loads the controller route annotations with some other logic automatically), another workaround would be to just name this fallback controller so that it will be the last one alphabetically (and thus the routes there should be evaluated the last).
From your comment I "smell" you have some composer packages that are not compatible with the current config of your project. Are you upgrading to SF4 from SF3?
I also had this InvalidArguementException:
"The "App" (from the _controller value "App:Default:index") does not exist
or is not enabled in your kernel...
Turns out that I have a non supported package easycorp/easyadmin-bundle version ^3.1 which I fixed it by
Removing the vendor folder
Removing the composer.lock file.
Explicitly specify the version my project supports ^2.3 in composer.json
Run composer install... et Voila!

Symfony 4 _instanceof in Bundle's services.yaml

I have a bundle which has interface Optimax\HealthCheckBundle\Service\HealthInterface
I need set tags to all services which implement this interface. I do it with the following directive:
_instanceof:
Optimax\HealthCheckBundle\Service\HealthInterface:
tags: ['health.service']
It works fine when I put this directive into config/services.yaml. But if I put this code into my bundle's config (which required via composer) vendor/optimax/health-check/src/Resources/config/services.yaml it doesn't work. I don't want copy-paste this directive into services.yaml every time when I require this bundle to a new project.
How can I move this directive into services.yaml which is in my Bundle's directory or at least into another file in config/packages folder of the project?
To expand on the issue for others.
_instanceof functions identically to the _defaults definition. In that the _instanceof definition only applies to the file it is used in.
This prevents third-party bundle definitions from affecting your entire application with definitions like:
_defaults:
public: true
autowire: false
_instanceof:
Psr\Log\LoggerAwareInterface:
- method: setLogger
arguments:
- '#custom_logger'
tags:
- { name: monologer.log, channel: 'custom_channel' }
Therefor if the service you are attempting to tag with _instanceof is not declared in the same services.yml file the tag will not be added.
To tag services that implements an Interface in the entire application, you would need to use the method provided by #Jeroen
Did you try auto tagging all services with this interface in your Bundle extension like this:
$container->registerForAutoconfiguration(CustomInterface::class)
->addTag('app.custom_tag')
;
Taken from the Symfony docs:
https://symfony.com/doc/current/service_container/tags.html

Symfony 2.4 CRUD please; Controller not found

I'm (almost) new to Symfony and I'm using 2.4 but I got a problem that is giving me lots of headaches. For several days I have not been able to fix this issue.
I use the app/console commands to build my base code; from entities to crud:
doctrine:generate:entity (to build the models), then code relations, etc
doctrine:generate: entities (to generate setters, getters, etc)
doctrine:schema:update --force (to update to the database all the models)
generate:doctrine:crud (to make controllers, forms, etc....)
At last, since I choose to declare the routing via annotations, I import into my bundle's routing.yml file all the controller routes like:
AutocondatECRBundle_controllers:
resource: "#AutocondatECRBundle/Controller"
type: annotation
This, as far as I'm aware, makes available all the routes inside the generated controllers at crud generation. However, no matter what route I try to test, Symfony keeps telling me:
FileLoaderLoadException: Cannot import resource "/var/www/autocondat-ecr/src/Autocondat/ECRBundle/Controller" from "/var/www/autocondat-ecr/src/Autocondat/ECRBundle/Resources/config/routing.yml". (Class Autocondat\ECRBundle\Controller\Clasificacion_EstudioController does not exist)
no mater what controller or route I choose to test, always fails to find the controller class, and believe me; those classes are there.
-There are no typos on names or cases
-Classes are there, controllers are there
-Routes are there and can't be loaded even using :
pattern: /whatever
defaults: { _controller: AutocondatECRBundle:ControllerWhatever:index }
This is driving me crazy.
For anyone able to help me, here is the source of all the project:
Link to the project
NOTES:
-There are several bundles inside my project; the one I'm testing is AutocondatECRBundle.
-Security inside security.yml file has been deactivated in order to test it faster.
-Of course, database can be generated fast with the same console commands.
Thanks -A LOT- for your help!
For your class Autocondat\ECRBundle\Controller\Clasificacion_EstudioController
Symfony will resolve both the namespace seperator \ and the underscore _ to a directory seperator, using PSR-0 autoloading standards for the autoloading of classes.
That means it is expecting your class to be located in the file src/Autocondat/ECRBundle/Controller/Clasificacion/EstudioController.php.
Name you class to ClasificacionEstudioController and the file to ClasificacionEstudioController.php.

Symfony2 bundle inheritance losing parent bundles routes

I am trying to create a simple bundle inheritance as instructed in here and ran into a problem with routes. I'm using annotations for routing. When I register my child bundle in AppKernel.php all my parent bundles routes are lost.
For what I understand from the documentation Symfony2 should look all files, including routes, first from the child bundle and then from the parent bundle. Now that is not happening, only child bundles controllers seems to be loaded.
In my child bundles Bundle file I have implemented getParent function as instructed, and in my routing.yml I have:
ParentBundle:
resource: "#Parent/Controller/"
type: annotation
prefix: /admin/
which worked fine before the inheritance.
I have tested that the system works fine if in include all controller files separetely in routing.yml but that seems very cumbersome way to make the inheritance to work as I only want to override few parts of the parent bundle ( not all controllers ).
Profiler is showing both of my bundles as active.
I found the right solution for this issue. Today I was also trying to override a parent bundle configured with annotations routing and also found that parent routes were ignored if the anotation routing imported the whole bundle ("#SomeBundle/Controller").
After a little debugging I found that the explanation for this is that if you use "#" as prefix for the controller this will pass to the kernel resolver which will return ONLY the child resource if the parent resource has been overridden. So the solution is to provide the full path of the bundle, considering that the kernel will try to match the resource from app/Resources so you will have to add a relative directory (../../) before the actual path:
# app/config/routing.yml:
some_parent:
resource: "../../src/Application/ParentBundle/Controller"
type: annotation
# ChildBundle implements getParent() method to inherit from ParentBundle
some_child:
resource: "#ChildBundle/Controller"
type: annotation
This will work as expected: all parent routes will be imported and will be overridden by all routes specified in the child bundle.
In addition to previous answer, I also had to change the name of the routing.yml of the child bundle (e.g. to routing_child.yml) to get it working. I assume this is because Symfony totally ignores the parent bundle routing file if the name is identical.
EDIT:
In many cases it's also practical to import parent bundle routes into the child bundle routing file like this:
# routing_child.yml
_parent:
resource: "#MyParentBundle/Resources/config/routing.yml"
The official documentation says that you shall just copy parent routing file to your child bundle:
The easiest way to "override" a bundle's routing is to never import it at all. Instead of importing a third-party bundle's routing, simply copying that routing file into your application, modify it, and import it instead.
Also, you cannot include parent's bundle routing file using symbolic names "#ParentBundle" because this name is resolved to "#ChildBundle".
If you really want to include parent routes file, then you shall use the absolute path to that file or path relative to current directory, i.e.:
# #YourChildBundle/Resources/routing.yml
YourParentBundle:
resource: "/srv/www/example.com/src/Your/ParentBundle/Resources/routing.yml"
or
# #YourChildBundle/Resources/routing.yml
YourParentBundle:
resource: "../../../../../Your/ParentBundle/Resources/routing.yml"
Another workaround is to symlink your parent routing file into your child bundle and include it with shorter path, i.e.:
cd YourChildBunde
ln -s ../../../../../Your/ParentBundle/Resources/routing.yml parent_routes.yml
and then
# #YourChildBundle/Resources/routing.yml
YourParentBundle:
resource: "parent_routing.yml"
P.S. I hope they'll find some better and less uglier way to override and extend routing from parent bundle, but now we have to se some of those ugly workarounds.
With bundle inheritance, you can override the parent bundle's files.
If you create a routing file in the same location as the parents in your bundle (if the routing of the parent file is at ParentBundle/Resources/config/routing.yml, and you create a routing file at ChildBundle/Resources/config/routing.yml), it will override the parent's routing.yml, and symfony will only use the child's routing.yml.
I haven't tried, but if you import the parent bundle's routing.yml in the child bundle's routing.yml, you can solve your problem. As Symfony router will always choose the first matching route it finds, you can override the specific route you want by writing the relevant routing code on top of the import code.

Categories