【问题标题】:Zend framework - get config inside controllerZend 框架 - 在控制器中获取配置
【发布时间】:2017-09-13 11:48:18
【问题描述】:

我正在使用它来构建 zend 应用程序。 http://github.com/zendframework/ZendSkeletonApplication

我正在尝试获取我放在config/autoload/global.php 和config/local.php.dist 中的配置数据,但它返回了

Zend\ServiceManager\Exception\ServiceNotFoundException

还有

在插件管理器 Zend\Mvc\Controller\PluginManager 中找不到名为“getServiceLocator”的插件

知道如何获取配置吗?

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

【问题讨论】:

    标签: php zend-framework zend-framework3


    【解决方案1】:

    这是为了澄清

    在 ZF3 中,如果您正在创建应用程序中需要的任何类,请使其可服务,并通过 ServiceManager 使它们在您的应用程序中可用。 ServiceManager 实现了一个存储注册服务的容器。那是怎么回事? ZF 使用一种称为 factory 的方法(简而言之,它创建对象)。它有助于将服务存储到容器中。然后我们可以使用 ServiceManager 从该容器中提取服务。让我们看看如何?

    ServiceManager 本身就是一项服务。

    所以使用 factory 让我们让 ServiceManager 实例在控制器(例如,IndexController)中可用。这样我们就可以使用它获得任何服务。

    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);
        }    
    }
    

    让我们将 IndexControllerFactory 注册为 IndexController 的工厂,以便我们可以使用它。在 module.config.php

    中进行以下更改
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => Controller\IndexControllerFactory::class,
        ],
    ],
    

    一旦 IndexController 被 IndexControllerFactory 实例化(通过上述配置),ServiceManager 实例就可以通过 IndexController 的构造函数获得。

    <?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();
        }
    

    如果我们需要来自另一个类而不是 controller 中的 config 服务的东西怎么办?例如,我们想将图像上传到特定目的地。那么我们如何修复上传路径呢?请参阅以下示例。

    我们将通过 RenameUpload 过滤器上传图片。它有一个名为 target 的选项,用于指定上传路径的目的地。让我们为上传过滤器创建另一个工厂。

    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);
        }
    }
    

    如果需要,对 UploadForm 执行相同操作。这将是 UploadFormFactory

    将以下两个sn-ps放在module.config.php中。这适用于 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,
        ],
    ],
    

    这个用于上传路径,无论您想上传到哪里。

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

    这是 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(),
            ));
        }
    }
    

    这是使事物可用的一种方法。那么为什么是 ServiceManager 呢?这是为了停止对对象的分散使用。它删除了隐藏的依赖项。这使代码更干净,更容易理解。原则是良好的设计。

    【讨论】:

      【解决方案2】:

      ZendSkeletonApplication 的 Master 分支目前使用 Zend Framework 3。控制器中的getServiceLocator() 一直是remove in Zend Framework 3. 所以,如果你想将一些变量从服务传递到控制器,你应该创建一个工厂。并在工厂实例化控制器时传递变量。

      示例:

      您的控制器名称是 IndexController 来自 Application 模块。工厂类是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);
          }
      }
      

      应用程序\控制器\索引控制器

      <?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
          }
      }
      

      这里是module.config.php中的配置

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

      希望有帮助

      【讨论】:

        【解决方案3】:

        为此,您需要注入配置,因为 getServiceLocator(和所有其他定位器)已从 ZF3 中删除。

        在你的模块配置中你有这个:

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

        您可以更改工厂以创建自己的工厂。

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

        代码如下:

        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 是一个 PSR 容器。

        在你的控制器中添加一个构造函数来接收你需要的配置:

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

        这里你的类中有你的配置,作为一个属性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-22
          • 2013-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多