5

首先,我阅读了以下两个 stackoverflow 问题,但它们并没有真正给我答案:

在我的应用程序中,我有一个员工数据库表,它有很多属性,但目前对我来说最有趣的是外键manager_idbank_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的属性扩展我的模型,并且在我的方法中的语句之前,我会执行以下操作:$bankreturngetEmployeeId

$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;

我有点喜欢这个实现

4

0 回答 0