0
votes

Scenario:

After setting up the Zend Framework Latest Skeleton App and setting up debugging in my local PHP Debugger Tool Eclipse environment, I have come across an issue while setting up my first model, called ActionItem. As per the instructions on Zend Framework I have included getServiceConfig() in my Module.php.

Specific Error

Catchable fatal error: Argument 1 passed to Application\Model\ActionItem::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, none given

Analysis:

In the code below (Module.php), my ActionItem() constructor (in 3rd code block Model.php) has no argument passed to it as a TableGateway argument.

Module.php

 public function getServiceConfig()
        {   
             return array(
                 'factories' => array(
                     'Application\Model\ActionItem' =>  function($sm) {
                         $tableGateway = $sm->get('ActionItemTableGateway');
                         $table = new ActionItem($tableGateway);
                         return $table;
                     },
                     'ActionItemTableGateway' => function ($sm) {
                         $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                         $resultSetPrototype = new ResultSet();
                         $resultSetPrototype->setArrayObjectPrototype(new ActionItem());  ###### Here, the ActionItem Constructor is passed nothing causing the fatal error.
                         return new TableGateway('application', $dbAdapter, null, $resultSetPrototype);
                     },
                 ),
             );
        }

Controller SummaryController.php

namespace Application\Controller;

use Application\Model\ActionItem;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class SummaryController extends AbstractActionController
{
    protected $actionItem;

    public function getActionItem()
    {
        if (!$this->actionItem) {
            $sm = $this->getServiceLocator();
            $this->actionItem = $sm->get('Application\Model\ActionItem');
        }
        return $this->actionItem;
    }

    public function IndexAction()
    {
        return new ViewModel(array (
            'actionitems' => $this->getActionItem()->fetchAll(),    
        ));
        //return new ViewModel();
    }
}

Model ActionItem.php

namespace Application\Model;

    use Zend\Db\TableGateway\TableGateway;

    class ActionItem {
        protected $tableGateway;

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

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

    }

Question

Is there a single way to resolve this, or can I take several approaches? What can I do to resolve the error?

Thank you.

1

1 Answers

1
votes

Your Application\Model\ActionItem shouldn't have a reference to a TableGateway.

You need to split your Application\Model\ActionItem into a service class and a true model class. A model class should represent your business but shouldn't be responsible to store itself.

Module.php

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'ActionItemRepository' => function ($sm) {

                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');

                $resultSetPrototype = new HydratingResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new ClassMethods(), new ActionItemEntity());

                $tableGateway = new TableGateway('application', $dbAdapter, null, $resultSetPrototype);

                $service = new ActionItemRepository($tableGateway);
                return $service;
            },
        ),
    );
}

SummaryController.php

Use the service to interact with ActionItem entities based on the client request (fetch them, update them, create them, ...)

namespace Application\Controller;

use Application\Service\ActionItemRepository;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class SummaryController extends AbstractActionController
{
    public function IndexAction()
    {
        return new ViewModel(array (
            'actionitems' => $this->getActionItemRepository()->fetchAllByType('pending'),
        ));
    }

    /**
     * @return ActionItemRepository
     */
    private function getActionItemRepository()
    {
        return $this->getServiceLocator()->get('ActionItemRepository');
    }
}

ActionItemEntity

Your entity class, does not depend on the storage layer, represent your business following classic OOP principles.

class ActionItemEntity
{
    /**
     * @var DateTime
     */
    protected $myProperty;

    /**
     * @return DateTime
     */
    public function getMyProperty()
    {
        return $this->myProperty;
    }

    /**
     * @param DateTime $myProperty
     */
    public function setMyProperty(DateTime $myProperty)
    {
        $this->myProperty = $myProperty;
    }
}

ActionItemRepository.php

namespace Application\Service;

use Zend\Db\TableGateway\TableGateway;

class ActionItemRepository
{
    /**
     * @var TableGateway
     */
    protected $tableGateway;

    /**
     * @param TableGateway $tableGateway
     */
    public function __construct(TableGateway $tableGateway)
    {
        $this->tableGateway = $tableGateway;
    }

    /**
     * @param string $type
     * @return \Zend\Db\ResultSet\ResultSet
     */
    public function fetchAllByType($type)
    {
        $resultSet = $this->tableGateway->select();

        // @todo: filter on Type

        return $resultSet;
    }

    /**
     * @param ActionItemEntity $actionItem
     */
    public function save(ActionItemEntity $actionItem)
    {
        //@todo
    }
}