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.