Zend Framework 2 module share variables between controllers onBootstrap

流过昼夜 提交于 2019-12-03 03:46:41

Okay... multipart answer.

1. Adding config variables , site-wide. (and how to access in controllers)

This was easy, once I saw it work. But depends on the preDispatch below. In your app root, drop a file in config/autoload. Call it: things.config.local.php

In this file, we just return an array with config items.

<?php
return array(
    'things' => array(
        'avalue' => 'avalue1',
        'boolvalue' => true,
        ),

);

So I want access to that in my controller. Assuming you create a config property in the controller, you can access it this way. (you setup that property in preDispatch below for it to work) In my system I'd prefer to retrieve that value like so:

$this->config['things']['boolvalue'];

However, you could just call upon it in an action like this:

$config = $this->getServiceLocator()->get('Config');
echo $config['things']['boolvalue'];

That was easy actually. Not sure how to do that with an ini file, but in my case its not needed and my ini files not not a big deal to move into arrays directly. Problem 1 solved for me!

2. How to get preDispatch in controllers (because __construct wont load config)

My other problem was that I could get access to some objects and/or values at a global level AND have them load when the controller and actions are initialized. As I understand it, its not possible to access service manager config in __construct of controller.

$this->getServiceLocator()->get('Config');

The above won't work. I believe because ServiceManager isn't available yet during construct of the controller class. makes sense.

A couple extra steps though, and I can get preDispatch working, similar to ZF1. THEN the config stuff works. As well as access to global objects, like database.

In the controller add the below method:

protected function attachDefaultListeners()
{
    parent::attachDefaultListeners();
    $events = $this->getEventManager();
    $this->events->attach('dispatch', array($this, 'preDispatch'), 100);
    $this->events->attach('dispatch', array($this, 'postDispatch'), -100);
}

Then add pre and post methods.

public function preDispatch (MvcEvent $e)
{
    // this is a db convenience class I setup in global.php
    // under the service_manager factories (will show below)
    $this->db = $this->getServiceLocator()->get('FBDb');
    // this is just standard config loaded from ServiceManager
    // set your property in your class for $config  (protected $config;)
    // then have access in entire controller
    $this->config = $this->getServiceLocator()->get('Config');
    // this comes from the things.config.local.php file
    echo "things boolvalue: " . $this->config['things']['boolvalue'];
}

public function postDispatch (MvcEvent $e)
{
    // Called after actions
}

Problem 2 solved! Init for controllers.

3. How to use the above with ServiceManager to load a DB object for use in Controller

Okay, the last thing I wanted was access to my db globally. And I wanted it controller-wide so I can call $this->db->fetchAll anywhere.

First setup service manager in global.php.
Also, keep in mind, I won't be leaving it exactly like this as it is in my global.php file. But it works for now. Add these array's to the return array in global.php:

'db' => array(
    'driver' => 'Pdo',
    'dsn'   => 'mysql:dbname=mydb;host=localhost;',
    'username' => 'root',
    'password' => '',
    'driver_options' => array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
    ),

),
'service_manager' => array(
    'factories' => array(
        'Zend\Db\Adapter\Adapter'
                => 'Zend\Db\Adapter\AdapterServiceFactory',
        'db-adapter' => function($sm) {
                $config = $sm->get('config');
                $config = $config['db'];
                $dbAdapter = new Zend\Db\Adapter\Adapter($config);
                return $dbAdapter;
             },
        'FBDb'  => function($sm) {
                $dba= $sm->get('db-adapter');
                $db = new FBDb\Db($dba);
                return $db;
             },

    ),
),

In the above, I setup the db config, then service_manager has some factories, which are made available when needed in rest of app. In my case, I wanted some convenience for backwards compatibility with some of my old ZF1 code, so I added a custom module called FBDb. I found a fantastic wrapper/bridge-to-zf1-style-db class called ZFBridge by Fabrizio Balliano. Worked great for my needs, you can find here: https://github.com/fballiano/zfbridge

I took that, modified it a bit, and made a module. So the FBDb object is available in my controllers as my database connection. Same with "db-adapter" if I wanted to utilize it elsewhere.

Anyway, in my controller, I setup "protected $db;" at the start of the class so I have that property available. Then as shown in #2 above , I have preDispatch assigning the FBDb database object to $this->db.

$this->db = $this->getServiceLocator()->get('FBDb');

Then in my action methods, if I want, I can call a record set or db value with this:

$sql = 'select * from customer where cust_nbr between ? and ?';
$rs = $this->db->fetchResults($sql, array('120400', '125250'));

OR, for an array returned:

$rs = $this->db->fetchAll($sql, array('120400', '125250'));

(I added fetchResults to ZFBridge to return only the PDO\Results object form the db query for use in foreach later.)

I know some of this is prbably bad design or "bad OOP", but it works for me and I like it. I personally don't lke using pure object based data entities for everything, just some things. Much of the time, I just want to drop a resultset in and be done with it. :)

Problems solved. For now. Makes ZF2 much more friendly now, if you are used to ZF1.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!