5

最初に、次の 2 つのスタックオーバーフローの質問を読みましたが、実際には答えが得られませんでした。

私のアプリケーションには、多数のプロパティを持つ従業員データベース テーブルがありますが、現在最も興味深いのは、外部キーであるmanager_idとです。bank_id

  • manager_id別の従業員への外部キーです(従業員が1人のマネージャーを持つことができると想像できるように)
  • bank_idbank従業員は銀行口座を持つことができるため、呼び出された別のモデル/データベーステーブルへの外部キーです;-)

私のEmployeeTable.phpファイルには、データベースの結果を取得する魔法のメソッドがあります。

従業員を 1 人獲得するには、次のようにします。

/**
 * @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 しかありません。

質問: 必要な情報を取得するためのベスト プラクティスは何ですか?

これまでのところ、次の 2 つの考えがあります。

初め

が空でない場合は$row、たとえばbankTable、メソッドを持つオブジェクトを (依存性注入を介して)呼び出す必要がありますgetBankById。次に、getter/setter を使用してEmployee.phpモデルを拡張し、メソッド内のステートメントの前に次のようにします。$bankreturngetEmployeeId

$row->setBank($this->bankTable->getBankById($row->bank_id));

manager_idしかし、現在使用しているのと同じメソッドを呼び出すため、これを行う再帰ループが怖いです。

2番

または、左結合でメソッドを拡張して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);
}

私はすでに抽出物を使用していたので、 HydratorInterfaceEmployeeHydratorを実装するように変更しましたが、メソッドに必要なインターフェイスと一致するようになりました。resultSetPrototype->setHydrator()

次のコードでは、完成した従業員オブジェクトと関連するすべての外部キーオブジェクトが既にあるため、メソッドは非常に簡単になってgetEmployeeByIdいます( my によるEmployeeHydrator

$result = $this->tableGateway->selectWith($select);
$row = $result->current(); // the given employee object result already hydrated!

return $row;

私はこの実装が好きです

4

0 に答える 0