最初に、次の 2 つのスタックオーバーフローの質問を読みましたが、実際には答えが得られませんでした。
私のアプリケーションには、多数のプロパティを持つ従業員データベース テーブルがありますが、現在最も興味深いのは、外部キーであるmanager_id
とです。bank_id
manager_id
別の従業員への外部キーです(従業員が1人のマネージャーを持つことができると想像できるように)bank_id
bank
従業員は銀行口座を持つことができるため、呼び出された別のモデル/データベーステーブルへの外部キーです;-)
私の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
モデルを拡張し、メソッド内のステートメントの前に次のようにします。$bank
return
getEmployeeId
$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;
私はこの実装が好きです