Injecting SQL Tables in Laminas / Zend Framework - is this the correct way?

550 views Asked by At

I probably have some understanding problem with Laminas, or maybe I'm just too complicated :-) hopefully someone can bring light in this...

I have an IndexController, an IndexController Factory and 2 Tables (User, Photos).

The Tables are all extensions of the AbstractTableGateway:

UserTable.php

<?php

declare(strict_types=1);

namespace Slideshow\Model\Table;

use Laminas\Db\Adapter\Adapter;

class UserTable extends AbstractTableGateway
{
    protected $adapter;
    protected $table = 'user';

    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;
        $this->initialize();
    }

    public function getUsersThatHaveAGallery()
    {
         // sql... select... from... where.....
    }
}

PhotosTable.php

<?php

declare(strict_types=1);

namespace Slideshow\Model\Table;

use Laminas\Db\Adapter\Adapter;

class UserTable extends AbstractTableGateway
{
    protected $adapter;
    protected $table = 'photos';

    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;
        $this->initialize();
    }

    public function getPhotosFromUser($user_id)
    {
         // sql...select photos from user where id = ....
    }
}

In my IndexController I'm creating an Instance of an Gallery-Class which needs the above mentioned UserTable and PhotosTable.

Is the correct way now to inject the UserTable and PhotoTable in the IndexControllerFactory.php and from the IndexController.php inject them both to the Gallery Class like this:

IndexControllerFactory.php

<?php

declare(strict_types=1);

namespace Slideshow\Controller\Factory;

use Slideshow\Model\Table\UserTable;
use Slideshow\Model\Table\PhotosTable;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;


class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestName, array $options = null)
    {
        return new IndexController(
            $container->get(UserTable::class),
            $container->get(PhotosTable::class),
            $container->get('ApplicationConfig')
        );
    }
}

IndexController.php


<?php

declare(strict_types=1);

namespace Slideshow\Controller;

use Slideshow\Model\Table\UserTable;
use Slideshow\Model\Table\PhotosTable;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
    private $userTable;
    private $photosTable;
    private $config;

    public function __construct(UserTable $userTable, PhotosTable $photosTable, array $config)
    {
        $this->userTable = $userTable;
        $this->photosTable = $photosTable;
        $this->config = $config;
    }

    public function indexAction()
    {
        // At this Point now I have to inject the Tables again ? 
        $Gallery = new Gallery($this->userTable, $this->photosTable);

        $html = $Gallery->renderUserListHtml();
        
        var_dump($html);
    }
}


Gallery.php

class Gallery {

   private $userTable;
   private $photosTable;

   // At this point I have to inject the tables AGAIN to make them usable in the Gallery.php ?
   public function __construct(UserTable $userTable, PhotosTable $photosTable)
   {
        $this->userTable = $userTable;
        $this->photosTable = $photosTable;
    {
 
   public function renderUserListHtml()
   {
      $sqlResult = $this->userTable->getUsersThatHaveAGallery();

      foreach($sqlResult as $k => $v) {
            $html .= '<div>' . $v['user_name'] . '</div><br />';
      }
 
      return $html;
}

So my main question is: is the above written code correct ? is it really necessary to inject the tables

  1. from Factory to IndexController
  2. from IndexController to Gallery Class

until I can finally "use them" in the methods of the gallery class.

It seems to be a lot of code until I finally can use them !?

1

There are 1 answers

0
Otto Sandström On

A more correct way to do it would be to make a GalleryFactory class for the Gallery class which injects the UserTable and PhotosTable in to it and then inject the Gallery Object in to the IndexController in the IndexControllerFactory

in this way IndexController don't need to handle the table classes.

Like this, create a GalleryFactory that creates the Gallery object and injects the tables.

<?php
namespace Slideshow\Model\Factory;

use Slideshow\Model\Gallery;
use Slideshow\Model\Table\UserTable;
use Slideshow\Model\Table\PhotosTable;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;

class GalleryFactory implements FactoryInterface
{
     public function __invoke(ContainerInterface $container, $requestName, array $options = null)
    {
        return new Gallery(
             $container->get(UserTable::class),
             $container->get(PhotosTable::class)
        );
    }
}

And then change the indexControllerFactory to inject the

<?php
namespace Slideshow\Controller\Factory;

use Slideshow\Model\Gallery;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;


class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestName, array $options = null)
    {
        return new IndexController(
            $container->get(Gallery::class),
            $container->get('ApplicationConfig')
        );
    }
}

And change the indexController to rescive a Gallery object instead

<?php
namespace Slideshow\Controller;

use Slideshow\Model\Gallery;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;

class IndexController extends AbstractActionController
{
    private $gallary;
    private $config;

    public function __construct(Gallary $gallery, array $config)
    {
        $this->gallery= $gallery;
        $this->config = $config;
    }

    public function indexAction()
    {
        $html = $this->gallery->renderUserListHtml();
        var_dump($html);
    }
}