Too exhausted about the entrance of Controller __construct()

I learned from the tutorial and document that, I can only do the dependency injection from the controller construct methond.

Then I encountered problems.

For example:
I have a AtableGateway model class, and we used to write all the A table related logic inside this class.
as well as BtableGateway and CtableGateway, … Until ZtableGateway.

First of all, I inject AtableGateay as dependency via its __construct();

in the some1Action, we call AtableGateway’s amethod() function. In coding, I found I need to use BtableGateway’s bmethod() in amethod(), then I need to inject BtableGateway from controller’s construct method, and add 1 param on amethod() for passing the BtableGateway as DI.

When AtableGateway’s amethod() need BtableGateway’s bmethod() and B need C’s cmethod(), then C need dmethod()…
It became a long chain. everytime I need a more DI, I need to change a lot, need to do the DI one by one along the chain.

It is impossible because I just encounter, the chain is around 3-4 layers. I feel it is very inconvinient.

When I try to break and chain, and flat it inside the action. in action, call A’s a, B’s b directly. It can resolve the above problem. But it make the action very big and thick. I remember I see principle from the website that “thin controller/action, fat model”. I think it said not too much code inside action.

Then I am facing a choise and a long DI chain or a thick action, what should I do?

Ps: and I found those DI are mostly DB related, socalled tablegateway. I don’t know whether I can new the tablegateway manually as a normal class, use inside and new it.

The tablegateway DI idea comes from here Database and Models - tutorials - Laminas Docs

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 Model\Album());
                    return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
                },
            ],
        ];
    }

when register as lazy mode inside container, it is global shared and just single instance, maybe to use less memory on the webserver.

====================================split=================================
following is my code in a real project.

Controller action

public function __construct(ForumMainTable $forumMainTable, UserFavoriteTable $userFavoriteTable, BaseFuncModel $baseFuncModel, ForumClassTable $forumClassTable, Redis $redis, ThreadMainTable $threadMainTable, AdapterInterface $dbAdapter,ForumUserTable $forumUserTable,FormElementManager $formElementManager, DiyEntityTable $diyEntityTable, DiyEavsTable $diyEavsTable)
    {
        $this->forumMainTable = $forumMainTable;
        $this->userFavoriteTable = $userFavoriteTable;
        $this->baseFuncModel = $baseFuncModel;
        $this->forumClassTable = $forumClassTable;
        $this->redis = $redis;
        $this->threadMainTable = $threadMainTable;
        $this->dbAdapter = $dbAdapter;
        $this->forumUserTable = $forumUserTable;
        $this->formElementManager = $formElementManager;
        $this->diyEntityTable = $diyEntityTable;
        $this->diyEavsTable = $diyEavsTable;

    }
    // onDispatch 目前看来,不需要这个,打算用 JsonModel

    /** 版区 */
    public function indexAction()
    {
        $identityArr = $this->plugin('auth')->getIdentity($this->getRequest());
       //in purpose to keep this part thin, I wrap all the logic into indexforum method.
        $data = $this->forumMainTable->indexforum($identityArr,$this->userFavoriteTable, $this->baseFuncModel, $this->forumClassTable);

        return new JsonModel([
            'status' => true,
            'msg' => 'success',
            'code' => 111,
            'data' => $data,
        ]);
    }

ForumMainTable::indexforum

//版区首页,生成一个list,读取全部的
    public function indexforum($identityArr, UserFavoriteTable $userFavoriteTable, BaseFuncModel $baseFuncModel, ForumClassTable $forumClassTable)
    {
        $data = [];

        $forumMainList = $this->mainListArr($baseFuncModel); //版区原始的一个数组

        $cacheForumList = $baseFuncModel->fsCacheApdater('indexforum','data/cache/forum','forum','600');
        if ($cacheForumList)
        {
            $forumMainSorted = unserialize($cacheForumList); //版区按分类折叠的一个数组
        }
        else
        {
            $forumClassList = $forumClassTable->classListArr($baseFuncModel);
            $forumMainSorted = $this->forumMainSortedByClass($forumMainList,$forumClassList);
            $baseFuncModel->fsCacheApdater('indexforum','data/cache/forum','forum','600','set',serialize($forumMainSorted));
        }

        $data['forumMain'] = $forumMainSorted;

        $data['userFocus'] = $identityArr ? $userFavoriteTable->indexForumMainFocus($identityArr['uid'], $forumMainList, $baseFuncModel) : null;

        return $data;
    }

I placed the userfavorite related logic inside UserFavoriteTable::indexForumMainFocus in natural.

public function userFavoriteByType($uid,BaseFuncModel $baseFuncModel,$type = 1)
    {
        $cache = $baseFuncModel->fsCacheApdater('favorite-uid'.$uid.'-type'.$type,'data/cache/forum-favorite','forum',2592000); //特别的长一个月
        if ($cache)
        {
            return unserialize($cache);
        }
        else
        {
            $columnsArr = ['id','type','uid','entityid','addtime'];
            $userFavoriteList = $this->tableGateway->select(function(Select $select) use ($columnsArr, $type, $uid){
                $predicate = new Predicate();
                $predicate->equalTo('uid', $uid);
                $predicate->and;
                $predicate->equalTo('type', $type);
                $select->columns($columnsArr);
                $select->where($predicate);
                $select->limit(500); //只取500条,太多会有问题
            });

            $userFavoriteList = $baseFuncModel->selectResults2ArrayWithColumnsLimits($userFavoriteList,$columnsArr);
            $baseFuncModel->fsCacheApdater('favorite-uid'.$uid.'-type'.$type,'data/cache/forum-favorite','forum',2592000,'set',serialize($userFavoriteList));

            return $userFavoriteList;
        }
    }

As you will see, if I need to use some other tableModel logic inside UserFavoriteTable::indexForumMainFocus, I need to change a lot. along the chain to do the dependency injection.

If I break the chain(passing di one by one), and parallel then line by line in action, that will make the action seems very fat.

Hope to find a good way to solve this.