简体   繁体   中英

Zend framework - get config inside controller

I'm using this to build zend application. http://github.com/zendframework/ZendSkeletonApplication

I'm trying to get the config data I put inside the config/autoload/global.php and config/local.php.dist with the bottom line but it returns

Zend\\ServiceManager\\Exception\\ServiceNotFoundException

and also

A plugin by the name "getServiceLocator" was not found in the plugin manager Zend\\Mvc\\Controller\\PluginManager

Any idea how I can get the config?

$config = $this->getServiceLocator()->get('config');

The Master branch of ZendSkeletonApplication at the moment using Zend Framework 3. And getServiceLocator() in controller had been remove in Zend Framework 3. So, if you wanna pass some variables from service to controller, you should create a factory. And pass the variables when instantiate the controller in factory.

Example:

Your controller name is IndexController from Application Module. And the factory class is IndexControllerFactory .

Application\\Controller\\IndexControllerFactory

<?php
namespace Application\Controller;

use Zend\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;

class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $config = $container->get("Config");
        return new IndexController($config);
    }
}

Application\\Controller\\IndexController

<?php
namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{
    private $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function indexAction()
    {
        // use $this->config here
    }
}

and here the configuration in module.config.php

'controllers' => [
        'factories' => [
            Controller\IndexController::class => Controller\IndexControllerFactory::class
        ],
    ],

Hope this help

This is for clarification

In ZF3 , if you are creating any classes that need in your application, make them serviceable, make them available in your application via ServiceManager . ServiceManager implements a container which stores registered services. So how is that? ZF uses a method called factory (in short, it creates object). It helps store services into container. We can then pull services from that container using ServiceManager . Let's see how?

ServiceManager is itself a service.

So using a factory let's make ServiceManager instance available in a controller (For example, IndexController). So that we can get any service using it.

Application\\Controller\\IndexControllerFactory

<?php
namespace Application\Controller;

// This is the container 
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;

class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = NULL)
    {   
        $serviceManager = $container->get('ServiceManager');
        return new IndexController($serviceManager);
    }    
}

Let's register the IndexControllerFactory as a factory for IndexController so that we can use it. Make the following change in the module.config.php

'controllers' => [
    'factories' => [
        Controller\IndexController::class => Controller\IndexControllerFactory::class,
    ],
],

Once the IndexController is instantiated by IndexControllerFactory (by above configurations) the ServiceManager instance becomes available through IndexController's constructor.

<?php
namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\ServiceManager\ServiceManager;

class IndexController extends AbstractActionController
{
    protected $serviceManager;

    public function __construct(ServiceManager $serviceManager) 
    {
        // Here we set the service manager instance 
        $this->serviceManager = $serviceManager;
    }

    public function indexAction()
    {
        // Use this as you want
        $config = $this->serviceManager->get('config');

        return new ViewModel();
    }

What if we need something from config service inside another class instead of the controller ? For example, we want to upload images into a specific destination. So how would we fix the upload path? See the following example.

We will upload images through RenameUpload filter. It has an option named target which specifies the destination of upload path. Let's create another factory for upload filter.

Application\\Controller\\Form\\Filter\\UploadFilterFactory

<?php
namespace Application\Form\Filter;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Form\Filter\UploadFilter;

class UploadFilterFactory implements FactoryInterface
{

    public function __invoke(ContainerInterface $container, $requestedName, array $options = NULL)
    { 
        $config = $container->get('config');

        // Look! here we fix the upload path
        $uploadPath = $config['module_config']['upload_path'];

        // Here we're injecting that path
        return new UploadFilter($uploadPath);
    }
}

Do the same for the UploadForm if you need. This will be UploadFormFactory

Put the following two snippets in the module.config.php . This is for UploadFilterFactory .

'service_manager' => [
    'factories' => [
        // UploadForm::class => UploadFormFactory::class, 
        UploadFilter::class => UploadFilterFactory::class,
    ],

    // Make an alias so that we can use it where we need
    // it could be uploadAction() inside any controller
    // $inputForm = $this->serviceManager->get('UploadForm');
    // $inputFilter = $this->serviceManager->get('UploadFilter');
    // $uploadForm->setInputFilter($inputFilter), for example
    'aliases' => [
        // 'UploadForm' => UploadForm::class,
        'UploadFilter' => UploadFilter::class,
    ],
],

and this one for the upload path wherever you want to upload.

'module_config' => [
    // Set the path as you want
    'upload_path' => __DIR__ . '/../data/upload',
],

This is the Application\\Form\\Filter\\UploadFilter .

<?php
namespace Application\Form\Filter;

use Zend\InputFilter\InputFilter;
use Zend\Filter\File\RenameUpload;

class UploadFilter extends InputFilter
{
    protected $uploadPath;

    public function __construct(string $uploadPath)
    { 
        // We're assigning here so that we can use it
        // on the filter section.
        $this->uploadPath = $uploadPath;

        $this->prepareFilters();
    }

    public function prepareFilters()
    { 
        $this->add(array(
            'name' => 'image',
            'required' => true,
            'filters' => array(
                array(
                    'name' => RenameUpload::class,
                    'options' => array(
                        // Thus here we use it
                        'target' => $this->uploadPath,
                        'overwrite' => true,
                        'randomize' => true,
                        'use_upload_extension' => true,
                    ),        
                ),
            ),
            'validators' => array(),
        ));
    }
}

This is a one way of making things serviceable. So why is ServiceManager ? This is for making scattered uses of objects stop. It removes hidden dependencies . This makes code clean and easier to understand. The principle is Good Design .

In order to do that you need to inject the config, as the getServiceLocator (and all other locators) have been removed from ZF3.

In your module configuration you have this:

'controllers' => [
    'factories' => [
        Controller\IndexController::class => InvokableFactory::class,
    ],
],

You can change the factory to create your own.

Controller\IndexController::class => Controller\IndexControllerFactory::class,

Here's the code:

final class IndexControllerFactory
{
    public function __invoke(Container $container) : IndexController
    {
        $config = $container->get('config');
        if (!isset($config['stuff']['stuff']) {
            throw new \Exception('Please add the stuff.stuff parameter in the config');
        }
        $myParam = $config['stuff']['stuff'];
        return new IndexController($myParam);
    }
}

Container is a PSR container.

In your controller add a constructor to receive the config you need:

public function __construct(string $param)
{
    $this->param = $param;
}

And here you have your config in your class, as an attribute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM