首先,我已经阅读了以下两个stackoverflow问题,但他们并没有给我一个答案:
在我的应用程序中,我有一个员工数据库表,它有许多属性,但目前我最感兴趣的是manager_id
和bank_id
这些是外键。
manager_id
是另一名员工的外键(因为您可以想象员工可以拥有一名经理)bank_id
是另一个名为bank
的model / db-table的外键 - 因为员工可以拥有银行帐户; - )现在在我的EmployeeTable.php
文件中,我有那些魔术方法,我获得了数据库结果。
为了让一名员工我这样做:
/**
* @param int $id
*
* @return Employee
*/
public function getEmployeeById($id)
{
$rowset = $this->tableGateway->select(['id' => (int) $id]);
/** @var Employee $row */
$row = $rowset->current();
if (!$row) {
throw new RuntimeException(sprintf(
'Could not find row with identifier %d',
(int) $id
));
}
return $row;
}
但是没有任何 sql join 我只返回了员工对象中的manager_id和bank_id。
问题:获取所需信息的最佳做法是什么?
到目前为止,我有两个想法:
第一
我应该 - 如果$row
不是空的 - 请求bankTable
对象(通过依赖注入),它具有getBankById
方法。
然后,我使用Employee.php
属性扩展我的$bank
模型,使用getter / setter,在我return
方法的getEmployeeId
语句之前,我会做这样的事情:
$row->setBank($this->bankTable->getBankById($row->bank_id));
但我害怕为manager_id
执行此操作的递归循环,因为我会使用与我目前相同的方法。
第二
或者我应该使用左连接扩展我的getEmployeeById
方法,以便从银行表中获取数据,如下所示:
$select = $this->tableGateway->getSql()->select()
->join(['b' => 'bank'], 'bank_id = m.id',
[
'bank.id' => 'id',
'bank.description' => 'description',
'bank.bic' => 'bic',
],
Select::JOIN_LEFT)
->join(['m' => 'employee'], 'manager_id = m.id',
[
'manager.id' => 'id',
'manager.forename' => 'forename',
'manager.surname' => 'surname',
// and all the other properties
],
Select::JOIN_LEFT);
$result = $this->tableGateway->selectWith($select);
$row= $result->current();
$resultSet = $this->hydrator->hydrate($this->hydrator->extract($row), $row);
不幸的是,我必须提供我的已加入列别名,否则我会用来自银行ID等的员工覆盖id
。
在这种sql语句之后,你可以看到,我将提取结果以将属性作为值,然后将它们保湿。
水化将如下所示:
/**
* @param array $data
* @param Employee $object
*
* @return Employee
*/
public function hydrate(array $data, $object)
{
if (!$object instanceof Employee) {
throw new \BadMethodCallException(sprintf(
'%s expects the provided $object to be a PHP Employee object)',
__METHOD__
));
}
$employee = new Employee();
$employee->exchangeArray($data);
$bank = new Bank();
$bank->exchangeArray($data, 'bank.');
$employee->setBank($bank);
$manager = new Employee();
$manager->exchangeArray($data, 'manager.');
$employee->setManager($manager);
return $employee;
}
因此,我有一个干净的employee
模型(没有那些额外的别名列),另外还有2个新属性,它们是另一个雇员(经理)和银行的对象。
但这看起来很重载......
感谢您的阅读 - 如果您有任何提示或建议,我们将受到热烈欢迎!
修改
我已编辑了EmployeeTableFactory
以执行以下操作(关于保湿):
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new HydratingResultSet();
$resultSetPrototype->setHydrator(new EmployeeHydrator());
$resultSetPrototype->setObjectPrototype(new Employee());
$tableGateway = new TableGateway('employee', $dbAdapter, null, $resultSetPrototype);
return new EmployeeTable($tableGateway);
}
我更改了EmployeeHydrator
以实现 HydratorInterface ,因为我已经在使用提取内容,现在它与resultSetPrototype->setHydrator()
方法的必要接口匹配。
现在getEmployeeById
方法变得非常简单,因为使用以下代码我已经拥有完成的员工对象和所有相关的外键对象(由于我的EmployeeHydrator
)
$result = $this->tableGateway->selectWith($select);
$row = $result->current(); // the given employee object result already hydrated!
return $row;
我有点喜欢这个实现