1

I'm trying to get some params from a config yaml file, I'm doing the following:

namespace ExampleVendor\AdminBundle\Controller;

/**
 * @Route("/", name="_home")
 */
public function index(ParameterBagInterface $params) {
    $menuIcons = $this->getParameter('admin-aside-menu');
    dump($menuIcons);

    return $this->render('@ExampleVendorAdminBundle/index.html.twig');
}

As you can see is just a dump function that prints the admin-aside-menu parameter, the problem is, this code works when it is in a controller in App\src\Controller, I mean in the "main" application src folder, but when I copy this code and paste it in a controller inside a custom bundle (something like vendor/myVendor/myBundle/src/Controller) I get an error when reloading the page:

Could not resolve argument $params of "ExampleVendor\AdminBundle\Controller\AdminController::index()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?

I need ParameterBagInterface to get those parameters but I dont know how to "inject" it in my controller.


Okay so it seems like this post says how to fix this issue but, since the controller I need to inject something is in a custom bundle in the vendor folder, the answer doesn't help me at all

Project
|
+--AdminBundle <- My custom bundle, installed via composer as symlink
|  |
|  +--Controller
|  |  |
|  |  +--AdminController.php <- Heres where I want to get my parameter
|  |
|  +--DependencyInjection
|  +--Entity
|  +--Resources
|     |
|     +--config
|        |
|        +--custom.yaml <- There are my custom params
|        +--services.yaml <- Heres where I should register my controller as service?
|
+--assets
|
+--bin
|
+--config
|
+--public
|
+--src
|
+--templates
|
+--vendor <- Heres my admin bundle as symlink

The AdminBundle folder is installer via composer as symlink so I can use it in my project, so knowing this, anyone know how can I inject ParametersBag or the parameter directly into my controller?


This is my custom.yaml that holds the params from my bundle

// AdminBundle/Resources/config/custom.yaml
parameters:
  admin-aside-menu:
    items:
      - icon: 'Home/Chair2'
        title: 'Prueba'
      - icon: 'Home/Deer'
        title: 'Prueba Venado'

This is the configuration class in the dependency injection

// AdminBundle/DependencyInjection/Configuration.php

class Configuration implements ConfigurationInterface {
    public function getConfigTreeBuilder() {
        $treeBuilder = new TreeBuilder('admin-aside-menu');

        $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('items')
                    ->children()
                        ->scalarNode('icon')->end()
                        ->scalarNode('title')->end()
                ->end()
            ->end()
        ;

        return $treeBuilder;
    }
}

and this is the bundle extension

// AdminBundle/DependencyInjection/ExampleVendorAdminExtension .php
class ExampleVendorAdminExtension extends Extension {

    /**
     * Loads a specific configuration.
     *
     * @throws \InvalidArgumentException When provided tag is not defined in this extension
     */
    public function load(array $configs, ContainerBuilder $container) {
        $loader = new YamlFileLoader( $container, new FileLocator(__DIR__.'/../Resources/config') );
        $loader->load('custom.yaml');
        $loader->load('services.yaml');

        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);
    }
}

I wrote this in my services.yaml to inject my parameter into my controller according to Florian's response

// AdminBundle/Resources/config/services.yaml
services:
    admin-bundle.controller.admin-controller:
        class: ExampleVendor\AdminBundle\Controller\AdminController
        arguments:
            - "%admin-aside-menu%"

it seems to work in a way because when I write "%admin-aside-menu%" bad (a typo) an error page says

"Did you mean this: "admin-aside-menu"?"

So I think it is actually loading my param but in my controller I cannot "inject" it

This is the controller:

/**
 * @Route(name="admin")
 *
 * Class AdminController
 * @package ExampleVendor\AdminBundle\Controller
 */
class AdminController extends AbstractController {
    public function __construct(array $adminAsideMenu) {
        dump($adminAsideMenu);
    }
}

but when I run this I get this error

The controller for URI "/admin/" is not callable. Controller "ExampleVendor\AdminBundle\Controller\AdminController" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?

yivi
  • 42,438
  • 18
  • 116
  • 138
H3lltronik
  • 562
  • 8
  • 26
  • 1
    Your controller from your bundle is not registered as a service so you can't use the autowiring. A solution could be to declare your controller as a service and inject the parameter manually in your declaration. – Florian Hermann Dec 02 '19 at 20:12
  • 1
    Moreover, if you use the previous solution, you can inject your parameter directly instead of injecting the parameter bag. – Florian Hermann Dec 02 '19 at 20:20
  • Hi Florian thank you so much for your help. How can I inject my parameter directly? Im struggling trying to register my controller as a service so if you could provide me a link or some docs you can recommend, I would really appreciate it – H3lltronik Dec 02 '19 at 21:31
  • I edited my post, hoping it can help you a little more to help me out this hole – H3lltronik Dec 02 '19 at 21:50
  • Can you share your service.yaml and also the main service.yaml? – Tejas Gosai Dec 03 '19 at 12:18
  • I just updated the post again, I added the content of my files – H3lltronik Dec 03 '19 at 18:23

3 Answers3

1

Open service.yaml then put the class name and choose an id to fetch it with autowiring

services:
    ExampleVendor\AdminBundle\Controller = '@adminbundle_thenameyouchoose'
JohnDoe
  • 75
  • 8
  • Hi John, Im kinda confused, I realized that I need to register my controller as a service so I found this [post](https://stackoverflow.com/questions/49793355/symfony-3-4-injection-of-service-in-controller-action) but in the comments of the answer, someone has the same problem I have, I just simply cannot make it work since my controller is the vendor folder so idk which namespace and realtive route should I write in – H3lltronik Dec 02 '19 at 21:34
  • I edited my post, hoping it can help you a little more to help me out this hole – H3lltronik Dec 02 '19 at 21:50
  • Can you declare it as AdminBundle\controller ? and call him from service.ymal as AdminBundle\controller\adminController. Please take care of the incrementation – JohnDoe Dec 02 '19 at 22:00
1

You should never write code in vendor packages due to any coding standards and practices. vendor is not a folder that you should push into the git repository, one of the reasons is the excess size of the static libraries that does not practically belong to your project, also this practice would make a total mess when you would try to update your composer dependencies. You should keep it clean and add vendor into the .gitignore. Symfony provides good support for overriding services check this.

rnenciu
  • 368
  • 4
  • 13
  • Is there a way to override twig error templates, like the error pages (404, 403, etc) but from a different bundle and not from the project itself, like just having installed a bundle it automatically override those pages – H3lltronik Dec 02 '19 at 22:21
  • 1
    @H3lltronik https://symfony.com/doc/3.4/templating/overriding.html this is exactly what you need, but it's for symfony 2 to 3 versions, because bundles were deprecated since symfony 4, they no longer provided support for this but were found some workarounds -> https://stackoverflow.com/questions/45239350/how-can-i-override-resources-for-third-party-bundles-in-symfony-4/45239524#45239524 Also you might wanna check this https://symfony.com/doc/4.3/controller/error_pages.html#overriding-the-default-error-templates for overriding error pages. – rnenciu Dec 02 '19 at 22:28
1

Building your own bundle is not straightforward.

From the bundle structure you shared with us, I can see that you already have the Dependency injection folder.

This folder should contains two file:

  • Configuration.php
  • YourBundleNameExtension.php

The parameter you want to inject in your controller should be in the configuration of your bundle so you have to complete the Configuration.php to add it. (I'm not a pro for that so I let you search by yourself)

Moreover, in order to acces your configuration in your bundle's code, you have to inject the configuration as a parameter with a a prefix for your bundle. You can find an example to see how to do it here : https://github.com/Orbitale/CmsBundle/blob/4.x/DependencyInjection/OrbitaleCmsExtension.php

Now in your Resources/services.yaml you can add you controller as a service:

services:
    bundle_name.controller.your_controller:
        class: Your\Controller\Namespace
        arguments:
            - '%bundle_key.your_parameter_name%'

Something like that should work but it's maybe not totally clear. So if you have more questions, I'll try to answer you.

Don't hesitate to check existing bundles as a source of inspiration.

---------------------- EDIT TO ANSWER EDIT 2 ----------------------

From what I see, your bundle configuration key is "admin-aside-menu"? Maybe it should be "admin_aside_menu" instead (to match convention). Anyway :

Yeah you almost there but there is missing something. You can't directly define parameters in config from your bundle. Instead, when you will use your bundle from your application you will have a file like this in /config/packages/admin-aside-menu.yaml :

admin-aside-menu:
    items:
        - icon: 'Home/Chair2'
          title: 'Prueba'
        - icon: 'Home/Deer'
          title: 'Prueba Venado'

This is your bundle configuration for your current usage and this should match the format you define in your AdminBundle/DependencyInjection/Configuration.php file. (I can't help you with that because it's not something I often do).

You can now remove totally the file AdminBundle/Resources/config/custom.yaml because the configuration is in your application.

Then in your extension, you can get this configuration to inject it in your the application parameters with a prefix for your bundle. If I modify your code, it should be something like this :

// AdminBundle/DependencyInjection/ExampleVendorAdminExtension .php
class ExampleVendorAdminExtension extends Extension {

    /**
     * Loads a specific configuration.
     *
     * @throws \InvalidArgumentException When provided tag is not defined in this extension
     */
    public function load(array $configs, ContainerBuilder $container) {
        $loader = new YamlFileLoader( $container, new FileLocator(__DIR__.'/../Resources/config') );
        // $loader->load('custom.yaml'); not needed anymore
        $loader->load('services.yaml');

        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        // This part inject your config in parameters
        foreach ($config as $key => $value) {
            $container->setParameter('admin-aside-menu.'.$key, $value);
        }
    }
}

Now your config parameters are set!

Last step, inject it in your controller :

// AdminBundle/Resources/config/services.yaml
services:
    admin-bundle.controller.admin-controller:
        class: ExampleVendor\AdminBundle\Controller\AdminController
        arguments:
            - "%admin-aside-menu.items%"

Is this ok ?

Florian Hermann
  • 750
  • 6
  • 15