Ibrahim Mumcu
Ibrahim Mumcu

Reputation: 243

getting data from another module in zend framework 2

I installed SkeletonApplication and created default album module from ZF2 Docs. http://framework.zend.com/manual/2.2/en/user-guide/modules.html

After that, I created category module like album module. Here are it`s fields: category_id and category_name

Then added extra field for album table: cat_id As you understand I'm trying to categorize albums.

Then I added this code to AlbumForm.php file for fieldset choose cat_id from selectbox

$this->add(array(
    'type' => 'Zend\Form\Element\Select',
    'name' => 'cat_id',
    'options' => array(
            'value_options' => $selectOptions,
        'label' => 'Category',
     ),
)); 

And now, how can I get category_name and category_id from another category module to album module?

Upvotes: 2

Views: 2722

Answers (2)

Nono HERON
Nono HERON

Reputation: 114

Infact, you don't have to create a new module for your Category Model => put it in your Album Module :)

it is not a good idea to multiplicate modules... one per table is quite too much :D

As I see you still have troubles after my precedent aswer, I wrote and commented all the code so you can better understand :)

The ServiceManager factory is a concept very important to understand very well !

So, you first have to make the factory configuration in your module.php file :

namespace Album;

use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;

use Album\Model\Album;
use Album\Model\AlbumTable;
use Album\Model\Category;
use Album\Model\CategoryTable;

class Module
{

    public function getServiceConfig()
    {
        return array (
            'factories' => array(
                //here already the AlbumTable config

                // here begin the categoryTable factory
                'Album\Model\CategoryTable' =>  function($sm)
                {
                    //get the tableGateway just below in his own factory
                    $tableGateway = $sm->get('CategoryTableGateway');
                    //inject the tableGateway in the Table
                    $table = new CategoryTable($tableGateway);
                    return $table;
                },
                //here is the tableGateway Factory for the category
                'CategoryTableGateway' => function($sm)
                {
                    //get adapter to donnect dataBase
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    // create a resultSet
                    $resultSetPrototype = new ResultSet();
                    //define the prototype of the resultSet 
                    // => what object will be cloned to get the results
                    $resultSetPrototype->setArrayObjectPrototype(new Category());
                    //here you define your database table (category) 
                    //when you return the tableGateway to the CategoryTable factory
                    return new TableGateway('category', $dbAdapter, null, $resultSetPrototype);
                },
            ),
        ),
    }
}

create your Category.php file in module/Album/src/Album/Model :

namespace Album\Model;

class Category
{
    public $id;
    public $name;

    public function exchangeArray(){
        $this->id     = (isset($data['id'])) ? $data['id'] : null;
        $this->name = (isset($data['name'])) ? $data['name'] : null;
    }

}

create your CategoryTable.php file in the same folder (only the fetchAll() method is required for the Select input, you just want a list of all categories)

namespace Album\Model;

use Zend\Db\TableGateway\TableGateway;

use Album\Model\Category;

class CategoryTable
{
    protected $tableGateway;

    public function __construct(TableGateway $tableGateway)
     {
         $this->tableGateway = $tableGateway;
     }

     public function fetchAll()
     {
         $resultSet = $this->tableGateway->select();
         return $resultSet;
     }


     public function getCategory($id){
        // ...
     }

    public function saveCategory(Category $category)
    {
       // ...
    }

     public function deleteCategory($id)
     {       
        // ...
     }
}

don't forget to add the new cat_id field in your AlbumTable::saveAlbum() method ;)

Create your form and his filters in Album/Form folder

namespace Album\Form;

class AlbumForm{
    public function __construct($cat_options){

        $this->add(array(
            'name' => 'id',
            'required' => false,
            'type' => 'hidden',
        ));

        $this->add(array(
            'name' => 'cat_id',
            'required' => true,
            'type' => 'Select',
            'options' => array(
                'value_options' => $cat_options,
                'label' => 'Category',
            )
            'attributes' => array(
                'value' => 3, // to select a default value
            )
        ));
        //and the rest of the form
         $this->add(array(
            'name' => 'submit',
            'type' => 'Submit',
            'attributes' => array(
                'id' => 'submitbutton',
                'value' => 'Go',
            ),
        ));
    }
}

Notice that I put the filters in a specific class, in the same namespace where the Form is. => much more easy to find when you have a lot of Forms and Models in a module... => I prefer it like that so I recomment it :D => you can have several forms for the same Model like registration, login and resetPassword forms for example, all used for the same User class

namespace Album\Form;

use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;

class AlbumFilter implements InputFilterAwareInterface
{
    protected $inputFilter;

    public function setInputFilter(InputFilterInterface $inputFilter)
    {
        throw new \Exception("Not used");
    }

    public function getInputFilter()
    {
        if(!$this->inputFilter)
        {
            $inputFilter = new InputFilter();

            $inputFilter->add(array(
                'name'     => 'id',
                'required' => false,
                'filters'  => array(
                    array('name' => 'Int'),
                ),
            ));
            $inputFilter->add(array(
                'name'     => 'cat_id',
                'required' => true,
                'filters'  => array(
                    array('name' => 'Int'),
                ),
            ));

            $inputFilter->add(array(
                'name'     => 'artist',
                'required' => true,
                'filters'  => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 1,
                            'max'      => 45,
                        ),
                    ),
                ),
            ));

            $inputFilter->add(array(
                'name'     => 'title',
                'required' => true,
                'filters'  => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 1,
                            'max'      => 45,
                        ),
                    ),
                ),
            ));
            $this->inputFilter = $inputFilter;
        }
        return $this->inputFilter;
    }

}

And now that everything is configured, make the Controller :)

namespace Album\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Album\Model\Album;
use Album\Form\AlbumForm;

class MyControler extends AbstractActionController
{
    private $CategoryTable;

    public function getAlbumsTable(){
        if(!$this->Album){
            // get AlbumTable from the ServiceLocator factory (defined in Module.php)
            $this->Album = $this->getServiceLocator()
                ->get('Album\Model\AlbumTable'); 
        }
    }

    public function getCategoryTable(){
        if(!$this->CategoryTable){
            $this->CategoryTable = $this->getServiceLocator()
                ->get('Album\Model\CategoryTable');
        }
    }

    public function addAction(){
        //get the categories from the database
        $categories = $this->getCategoryTable()->fetchall();

        //make an array from the resultSet
            // you can do it as well in your controller
            //or in your form class like I did in my yersterday's answer
        $cat_options = array();
            foreach ($categories as $category) {
                $cat_options[$category->id]=$category->name;
            }

        //create your form with category list as parameter
        $form = new AlbumForm($cat_options);
        //here I recomend to create a specific class for you filters
        // and not put it in your Album class as describe in the zf tutorial

        // => so you can have several forms using the same Model
        // and it is more easy to find on the form folder ;)
        $filter = new AlbumFilter();
        //inject InputFilter in your form
        $form->setInputFilter($filter->getInputFilter());
        //inject data in form
        $form->setData($request->getPost());
        //check the form validity (data vs filters)
        if($form->isValid()){
            //create a new album
            $album = new Album();  
            //hydrate your Album
            $album->exchangeArray($form->getData());
            //ask the albumsTable to save album in the database
            $this->albumsTable->saveAlbum($album);

            //here you can redirect to the Album list
            $this->redirect()->toRoute('Album');
        }
        //call the viewModel if first time you see the page
        // or if validation errors of the form.
        return array('form' =>$form);
    }
}

Then you only have to make your view... I won't make the offense to put this code here ;)

If you still have to make several modules in your application, you can call any objectTable in the controller with the getobjectTable() method, using the factories : as Carlos said, the getServiceConfig() array are all merged in one, so you can get any Table from anywhere in the application :)

Upvotes: 2

Carlos Robles
Carlos Robles

Reputation: 10947

It would be good if we could see the code of your category module files.

First of all, you should consider if you actually need a new module for this, since probably it should be in the same module, just creating new model classes and new views (if there is some). Anyways, at this point it doesnt matter.

If you are using the SkeletonApplication i suppose in your Album module, in Module.php you have this code:

 public function getServiceConfig()
    {
        return array(
                'factories' => array(
                        'Album\Model\AlbumTable' =>  function($sm) {
                            $tableGateway = $sm->get('AlbumTableGateway');
                            $table = new AlbumTable($tableGateway);
                            return $table;
                        },
                        'AlbumTableGateway' => function ($sm) {
                            $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                            $resultSetPrototype = new ResultSet();
                            $resultSetPrototype->setArrayObjectPrototype(new Album());
                            return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
                        },
                ),
        );
    }

And then probably you created something similar for your category tables, something like

 public function getServiceConfig()
    {
        return array(
                'factories' => array(
                        'Category\Model\CategoryTable' =>  function($sm) {
                            $tableGateway = $sm->get('CategoryTableGateway');
                            $table = new CategoryTable($tableGateway);
                            return $table;
                        },
                        'CategoryTableGateway' => function ($sm) {
                            $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                            $resultSetPrototype = new ResultSet();
                            $resultSetPrototype->setArrayObjectPrototype(new Album());
                            return new TableGateway('category', $dbAdapter, null, $resultSetPrototype);
                        },
                ),
        );
    }

Let me know if it is much diferent.

Since all the configuration is merged, in your controller your service manager can locate also the Category\Model\CategoryTable no matter if you are in other module.

So, you have to modify your AlbumForm class, so for instance in the constructor you can pass the dependencies, for example servicemanager, or 'Category\Model\CategoryTable' so when you need to retrieve the $selectOptions list, you can access it to make any query.

Also, you can take a look at more fine solutions like this from samsonasik, but it can be harder to understand.

And also, you can check this blog post and code from jamescarr to achieve more or less the same that you need. It is really easy to understand, and it is a good solution.

Upvotes: 2

Related Questions