rog*_*gaa 5 php mysql zend-framework zend-framework2 zend-framework3
首先,我阅读了以下两个 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;
}
Run Code Online (Sandbox Code Playgroud)
但是没有任何sql 连接,我返回的员工对象中只有 manager_id 和 bank_id。
问题:获取这些所需信息的最佳实践是什么?
到目前为止,我有两个想法:
第一的
我应该 - 如果$row不为空 - 调用例如bankTable具有getBankById方法的对象(通过依赖注入)。然后我将使用带有 getter/setterEmployee.php的$bank属性扩展我的模型,return在我的getEmployeeId方法中的语句之前,我将执行以下操作:
$row->setBank($this->bankTable->getBankById($row->bank_id));
Run Code Online (Sandbox Code Playgroud)
但是我害怕递归循环会这样做,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);
Run Code Online (Sandbox Code Playgroud)
不幸的是,我必须给我加入的列别名,否则我会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;
}
Run Code Online (Sandbox Code Playgroud)
因此,我有一个干净的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);
}
Run Code Online (Sandbox Code Playgroud)
我改变了我EmployeeHydrator来实现HydratorInterface因为我已经在使用提取的东西,现在它匹配了该resultSetPrototype->setHydrator()方法的必要接口。
现在方法中的事情变得非常简单,getEmployeeById因为使用以下代码我已经完成了我的员工对象和所有相关的外键对象(由于我的EmployeeHydrator)
$result = $this->tableGateway->selectWith($select);
$row = $result->current(); // the given employee object result already hydrated!
return $row;
Run Code Online (Sandbox Code Playgroud)
我有点喜欢这个实现