首先,我阅读了以下两个 stackoverflow 问题,但它们并没有真正给我答案:
在我的应用程序中,我有一个员工数据库表,它有很多属性,但目前对我来说最有趣的是外键manager_id
和bank_id
外键。
manager_id
是另一个员工的外键(你可以想象一个员工可以有一个经理)bank_id
是另一个模型/数据库表的外键bank
- 因为员工可以有一个银行账户;-)
现在在我的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 连接,我返回的员工对象中只有 manager_id 和 bank_id。
问题:获取这些所需信息的最佳做法是什么?
到目前为止,我有两个想法:
第一的
我应该——如果$row
不是空的——调用例如bankTable
具有方法的对象(通过依赖注入)getBankById
。然后,我将使用带有 getter/setterEmployee.php
的属性扩展我的模型,并且在我的方法中的语句之前,我会执行以下操作:$bank
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;
我有点喜欢这个实现