1
votes

I am using zend 3 and unable to solve this error when trying to list all albums from the database table. The error is

Catchable fatal error: Argument 1 passed to Album\Controller\AlbumController::__construct() must be an instance of Album\Model\AlbumTable, none given, called in C:\xampp\htdocs\zftutorial\vendor\zendframework\zend-servicemanager\src\Factory\InvokableFactory.php

These are my files: AlbumController.php

<?php
namespace Album\Controller;

 use Zend\Mvc\Controller\AbstractActionController;
 use Zend\View\Model\ViewModel;
 use Album\Model\AlbumTable;
 use Zend\Db\Adapter\AdapterInterface;


 class AlbumController extends AbstractActionController
 {


    private $table;

   public function __construct(AlbumTable $table)
    {
        $this->table = $table;
    }



        public function indexAction()
        {
             return new ViewModel([
            'albums' => $this->table->fetchAll(),
        ]);
        }  



     public function addAction()
     {
     }

     public function editAction()
     {
     }

     public function deleteAction()
     {
     }


 }

AlbumTable.php

<?php
namespace Album\Model;

use RuntimeException;
use Zend\Db\TableGateway\TableGateway;

class AlbumTable
{
    protected $tableGateway;

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

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

    public function getAlbum($id)
    {
        $id = (int) $id;
        $rowset = $this->tableGateway->select(['id' => $id]);
        $row = $rowset->current();
        if (! $row) {
            throw new RuntimeException(sprintf(
                'Could not find row with identifier %d',
                $id
            ));
        }

        return $row;
    }

    public function saveAlbum(Album $album)
    {
        $data = [
            'artist' => $album->artist,
            'title'  => $album->title,
        ];

        $id = (int) $album->id;

        if ($id === 0) {
            $this->tableGateway->insert($data);
            return;
        }

        if (! $this->getAlbum($id)) {
            throw new RuntimeException(sprintf(
                'Cannot update album with identifier %d; does not exist',
                $id
            ));
        }

        $this->tableGateway->update($data, ['id' => $id]);
    }

    public function deleteAlbum($id)
    {
        $this->tableGateway->delete(['id' => (int) $id]);
    }
}

Module.php

<?php
namespace Album;

 use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
 use Album\Model\Album;
 use Album\Model\AlbumTable;
 use Zend\Db\Adapter\AdapterInterface;
 use Zend\Db\ResultSet\ResultSet;
 use Zend\Db\TableGateway\TableGateway;
 use Zend\ModuleManager\Feature\ConfigProviderInterface;

 //use \Zend\Mvc\Controller\ControllerManager;


 class Module implements AutoloaderProviderInterface, ConfigProviderInterface

 {
     public function getAutoloaderConfig()
     {
         return array(
             'Zend\Loader\ClassMapAutoloader' => array(
                 __DIR__ . '/autoload_classmap.php',
             ),
             'Zend\Loader\StandardAutoloader' => array(
                 'namespaces' => array(
                     __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                 ),
             ),
         );
     }

     public function getConfig()
     {
         return include __DIR__ . '/config/module.config.php';
     }




 public function getServiceConfig() {
        return [
            'factories' => [
                Model\AlbumTable::class => function($container) {
                    $tableGateway = $container->get(Model\AlbumTableGateway::class);
                    return new Model\AlbumTable($tableGateway);
                },
                Model\AlbumTableGateway::class => function ($container) {
                    $dbAdapter = $container->get(AdapterInterface::class);
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new Album());
                    return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
                },
            ],
        ];
    }
    public function getControllerConfig() {
        return [
            'factories' => [
                Controller\AlbumController::class => function($container) {
                    return new Controller\AlbumController(
                        $container->get(Model\AlbumTable::class)
                    );
                },
            ],
        ];
    } 
}

module.config.php

<?php
namespace Album;
return array(
     'controllers' => array(
         'invokables' => array(
             'Album\Controller\Album' => 'Album\Controller\AlbumController',
         ),    

      ), 


     'router' => array(
         'routes' => array(
             'album' => array(
                 'type'    => 'segment',
                 'options' => array(
                     'route'    =>'/album[/][:action][/:id]',

                     'constraints' => array(
                         'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                         'id'     => '[0-9]+',
                     ),
                     'defaults' => array(
                         'controller' => 'Album\Controller\Album',
                         'action'     => 'index',
                     ),
                 ),
             ),
         ),
     ),
     'view_manager' => array(
         'template_path_stack' => array(
             'album' => __DIR__ . '/../view',
         ),
     ),
 );
2

2 Answers

0
votes

In your module.config.php you have this:

 'controllers' => array(
     'invokables' => array(
         'Album\Controller\Album' => 'Album\Controller\AlbumController',
     ),    
  ),

It looks like you mix up a few concepts here. An invokable would be a class with no parameters in it's constructor. Also invokables no longer exist in ZF3 as they did in ZF2.

Since the controller wants an AlbumTable object you can't use it as an invokable and need to create a factory to inject it. Which you have done already in Module.php.

Looking at your code, it might work if you remove those lines from module.config.php.

You should also remove the getAutoloaderConfig() from Module.php. Since a while the zend loader is deprecated in favor of the composer autoloader.

0
votes

You need to replace the below code

   'controllers' => array(
     'invokables' => array(
         'Album\Controller\Album' => 'Album\Controller\AlbumController',
      ),    

   ),

with the code

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

As from the docs

invokables is no longer exists in zf3.