mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
NEW ORM eager loading
This commit is contained in:
parent
f54bbc50f0
commit
246735101a
@ -11,8 +11,10 @@ use Exception;
|
|||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use BadMethodCallException;
|
use BadMethodCallException;
|
||||||
|
use SilverStripe\ORM\Connect\Query;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
use SilverStripe\ORM\DataQuery;
|
use SilverStripe\ORM\DataQuery;
|
||||||
|
use SilverStripe\ORM\ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a "lazy loading" DataObjectSet.
|
* Implements a "lazy loading" DataObjectSet.
|
||||||
@ -58,6 +60,11 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
*/
|
*/
|
||||||
protected $finalisedQuery;
|
protected $finalisedQuery;
|
||||||
|
|
||||||
|
|
||||||
|
private array $eagerLoadRelations = [];
|
||||||
|
|
||||||
|
private array $eagerLoadedData = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new DataList.
|
* Create a new DataList.
|
||||||
* No querying is done on construction, but the initial query schema is set up.
|
* No querying is done on construction, but the initial query schema is set up.
|
||||||
@ -824,8 +831,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
*/
|
*/
|
||||||
public function toArray()
|
public function toArray()
|
||||||
{
|
{
|
||||||
$query = $this->dataQuery->query();
|
$rows = $this->executeQuery();
|
||||||
$rows = $query->execute();
|
|
||||||
$results = [];
|
$results = [];
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
@ -916,10 +922,60 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
$creationType = empty($row['ID']) ? DataObject::CREATE_OBJECT : DataObject::CREATE_HYDRATED;
|
$creationType = empty($row['ID']) ? DataObject::CREATE_OBJECT : DataObject::CREATE_HYDRATED;
|
||||||
|
|
||||||
$item = Injector::inst()->create($class, $row, $creationType, $this->getQueryParams());
|
$item = Injector::inst()->create($class, $row, $creationType, $this->getQueryParams());
|
||||||
|
$this->setDataObjectEagerLoadedData($item);
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setDataObjectEagerLoadedData(DataObject $item): void
|
||||||
|
{
|
||||||
|
foreach (array_keys($this->eagerLoadedData) as $eagerLoadRelation) {
|
||||||
|
list($dataClasses, $relations) = $this->getEagerLoadVariables($eagerLoadRelation);
|
||||||
|
$dataClass = $dataClasses[count($dataClasses) - 2];
|
||||||
|
$relation = $relations[count($relations) - 1];
|
||||||
|
foreach (array_keys($this->eagerLoadedData[$eagerLoadRelation]) as $eagerLoadID) {
|
||||||
|
$eagerLoadedData = $this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation];
|
||||||
|
if ($dataClass === $dataClasses[0]) {
|
||||||
|
if ($eagerLoadID === $item->ID) {
|
||||||
|
$item->setEagerLoadedData($relation, $eagerLoadedData);
|
||||||
|
}
|
||||||
|
} elseif ($dataClass === $dataClasses[1]) {
|
||||||
|
$relationData = $item->{$relations[1]}();
|
||||||
|
if ($relationData instanceof DataObject) {
|
||||||
|
if ($relationData->ID === $eagerLoadID) {
|
||||||
|
$subItem = $relationData;
|
||||||
|
} else {
|
||||||
|
$subItem = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$subItem = $item->{$relations[1]}()->find('ID', $eagerLoadID);
|
||||||
|
}
|
||||||
|
if ($subItem) {
|
||||||
|
$subItem->setEagerLoadedData($relations[2], $eagerLoadedData);
|
||||||
|
}
|
||||||
|
} elseif ($dataClass === $dataClasses[2]) {
|
||||||
|
$relationData = $item->{$relations[1]}();
|
||||||
|
if ($relationData instanceof DataObject) {
|
||||||
|
$list = new ArrayList([$relationData]);
|
||||||
|
} else {
|
||||||
|
$list = $relationData;
|
||||||
|
}
|
||||||
|
foreach ($list as $subItem) {
|
||||||
|
$subRelationData = $subItem->{$relations[2]}();
|
||||||
|
if ($relationData instanceof DataObject) {
|
||||||
|
$subList = new ArrayList([$subRelationData]);
|
||||||
|
} else {
|
||||||
|
$subList = $subRelationData;
|
||||||
|
}
|
||||||
|
$subSubItem = $subList->find('ID', $eagerLoadID);
|
||||||
|
if ($subSubItem) {
|
||||||
|
$subSubItem->setEagerLoadedData($relations[3], $eagerLoadedData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get query parameters for this list.
|
* Get query parameters for this list.
|
||||||
* These values will be assigned as query parameters to newly created objects from this list.
|
* These values will be assigned as query parameters to newly created objects from this list.
|
||||||
@ -956,12 +1012,227 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
|||||||
protected function getFinalisedQuery()
|
protected function getFinalisedQuery()
|
||||||
{
|
{
|
||||||
if (!$this->finalisedQuery) {
|
if (!$this->finalisedQuery) {
|
||||||
$this->finalisedQuery = $this->dataQuery->query()->execute();
|
$this->finalisedQuery = $this->executeQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->finalisedQuery;
|
return $this->finalisedQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getEagerLoadVariables(string $eagerLoadRelation): array
|
||||||
|
{
|
||||||
|
$schema = DataObject::getSchema();
|
||||||
|
$relations = array_merge(['root'], explode('.', $eagerLoadRelation));
|
||||||
|
$dataClasses = [$this->dataClass];
|
||||||
|
$hasOneIDField = null;
|
||||||
|
$belongsToIDField = null;
|
||||||
|
$hasManyIDField = null;
|
||||||
|
$manyManyLastComponent = null;
|
||||||
|
for ($i = 0; $i < count($relations) - 1; $i++) {
|
||||||
|
$hasOneComponent = $schema->hasOneComponent($dataClasses[$i], $relations[$i + 1]);
|
||||||
|
if ($hasOneComponent) {
|
||||||
|
$dataClasses[] = $hasOneComponent;
|
||||||
|
$hasOneIDField = $relations[$i + 1] . 'ID';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$belongsToComponent = $schema->belongsToComponent($dataClasses[$i], $relations[$i + 1]);
|
||||||
|
if ($belongsToComponent) {
|
||||||
|
$dataClasses[] = $belongsToComponent;
|
||||||
|
$belongsToIDField = $schema->getRemoteJoinField($dataClasses[$i], $relations[$i + 1], 'belongs_to');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$hasManyComponent = $schema->hasManyComponent($dataClasses[$i], $relations[$i + 1]);
|
||||||
|
if ($hasManyComponent) {
|
||||||
|
$dataClasses[] = $hasManyComponent;
|
||||||
|
$hasManyIDField = $schema->getRemoteJoinField($dataClasses[$i], $relations[$i + 1], 'has_many');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// this works for both many_many and belongs_many_many
|
||||||
|
$manyManyComponent = $schema->manyManyComponent($dataClasses[$i], $relations[$i + 1]);
|
||||||
|
if ($manyManyComponent) {
|
||||||
|
$dataClasses[] = $manyManyComponent['childClass'];
|
||||||
|
$manyManyLastComponent = $manyManyComponent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new InvalidArgumentException("Invalid relation passed to eagerLoad() - $eagerLoadRelation");
|
||||||
|
}
|
||||||
|
return [$dataClasses, $relations, $hasOneIDField, $belongsToIDField, $hasManyIDField, $manyManyLastComponent];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function executeQuery(): Query
|
||||||
|
{
|
||||||
|
$query = $this->dataQuery->query()->execute();
|
||||||
|
$this->fetchEagerLoadRelations($query);
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fetchEagerLoadRelations(Query $query): void
|
||||||
|
{
|
||||||
|
if (empty($this->eagerLoadRelations)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$ids = $query->column('ID');
|
||||||
|
if (empty($ids)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$topLevelIDs = $ids;
|
||||||
|
// Using ->toArray() and then iterating instead of just iterating DataList because
|
||||||
|
// in some instances it prevents some extra SQL queries
|
||||||
|
$prevRelationArray = [];
|
||||||
|
foreach ($this->eagerLoadRelations as $eagerLoadRelation) {
|
||||||
|
list(
|
||||||
|
$dataClasses,
|
||||||
|
$relations,
|
||||||
|
$hasOneIDField,
|
||||||
|
$belongsToIDField,
|
||||||
|
$hasManyIDField,
|
||||||
|
$manyManyLastComponent
|
||||||
|
) = $this->getEagerLoadVariables($eagerLoadRelation);
|
||||||
|
$dataClass = $dataClasses[count($dataClasses) - 2];
|
||||||
|
$relation = $relations[count($relations) - 1];
|
||||||
|
$relationDataClass = $dataClasses[count($dataClasses) - 1];
|
||||||
|
if ($dataClass === $this->dataClass) {
|
||||||
|
// When we're at "the top of a tree of nested relationships", we can just use the IDs from the query
|
||||||
|
// This is important to do when handling multiple eager-loaded relatioship trees.
|
||||||
|
$ids = $topLevelIDs;
|
||||||
|
}
|
||||||
|
// has_one
|
||||||
|
if ($hasOneIDField) {
|
||||||
|
$itemArray = [];
|
||||||
|
$relationItemIDs = [];
|
||||||
|
if ($dataClass === $dataClasses[0]) {
|
||||||
|
while ($row = $query->record()) {
|
||||||
|
$itemArray[] = [
|
||||||
|
'ID' => $row['ID'],
|
||||||
|
$hasOneIDField => $row[$hasOneIDField]
|
||||||
|
];
|
||||||
|
$relationItemIDs[] = $row[$hasOneIDField];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($prevRelationArray as $itemData) {
|
||||||
|
$itemArray[] = [
|
||||||
|
'ID' => $itemData->ID,
|
||||||
|
$hasOneIDField => $itemData->$hasOneIDField
|
||||||
|
];
|
||||||
|
$relationItemIDs[] = $itemData->$hasOneIDField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$relationArray = DataObject::get($relationDataClass)->filter(['ID' => $relationItemIDs])->toArray();
|
||||||
|
foreach ($itemArray as $itemData) {
|
||||||
|
foreach ($relationArray as $relationItem) {
|
||||||
|
$eagerLoadID = $itemData['ID'];
|
||||||
|
if ($relationItem->ID === $itemData[$hasOneIDField]) {
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation] = $relationItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$prevRelationArray = $relationArray;
|
||||||
|
$ids = $relationItemIDs;
|
||||||
|
// belongs_to
|
||||||
|
} elseif ($belongsToIDField) {
|
||||||
|
$relationArray = DataObject::get($relationDataClass)->filter([$belongsToIDField => $ids])->toArray();
|
||||||
|
$relationItemIDs = [];
|
||||||
|
foreach ($relationArray as $relationItem) {
|
||||||
|
$relationItemIDs[] = $relationItem->ID;
|
||||||
|
$eagerLoadID = $relationItem->$belongsToIDField;
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation] = $relationItem;
|
||||||
|
}
|
||||||
|
$prevRelationArray = $relationArray;
|
||||||
|
$ids = $relationItemIDs;
|
||||||
|
// has_many
|
||||||
|
} elseif ($hasManyIDField) {
|
||||||
|
$relationArray = DataObject::get($relationDataClass)->filter([$hasManyIDField => $ids])->toArray();
|
||||||
|
$relationItemIDs = [];
|
||||||
|
foreach ($relationArray as $relationItem) {
|
||||||
|
$relationItemIDs[] = $relationItem->ID;
|
||||||
|
$eagerLoadID = $relationItem->$hasManyIDField;
|
||||||
|
if (!isset($this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation])) {
|
||||||
|
$arrayList = ArrayList::create();
|
||||||
|
$arrayList->setDataClass($relationItem->dataClass);
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation] = $arrayList;
|
||||||
|
}
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation]->push($relationItem);
|
||||||
|
}
|
||||||
|
$prevRelationArray = $relationArray;
|
||||||
|
$ids = $relationItemIDs;
|
||||||
|
// many_many + belongs_many_many & many_many_through
|
||||||
|
} elseif ($manyManyLastComponent) {
|
||||||
|
$parentField = $manyManyLastComponent['parentField'];
|
||||||
|
$childField = $manyManyLastComponent['childField'];
|
||||||
|
// $join will either be:
|
||||||
|
// - the join table name for many-many
|
||||||
|
// - the join data class for many-many-through
|
||||||
|
$join = $manyManyLastComponent['join'];
|
||||||
|
// many_many_through
|
||||||
|
if (is_a($manyManyLastComponent['relationClass'], ManyManyThroughList::class, true)) {
|
||||||
|
$joinThroughObjs = $join::get()->filter([$parentField => $ids]);
|
||||||
|
$relationItemIDs = [];
|
||||||
|
$rows = [];
|
||||||
|
foreach ($joinThroughObjs as $joinThroughObj) {
|
||||||
|
$rows[] = [
|
||||||
|
$parentField => $joinThroughObj->$parentField,
|
||||||
|
$childField => $joinThroughObj->$childField
|
||||||
|
];
|
||||||
|
$relationItemIDs[] = $joinThroughObj->$childField;
|
||||||
|
}
|
||||||
|
// many_many + belongs_many_many
|
||||||
|
} else {
|
||||||
|
$joinTableQuery = DB::query('SELECT * FROM "' . $join . '" WHERE "' . $parentField . '" IN (' . implode(',', $ids) . ')');
|
||||||
|
$relationItemIDs = [];
|
||||||
|
$rows = [];
|
||||||
|
while ($row = $joinTableQuery->record()) {
|
||||||
|
$rows[] = [
|
||||||
|
$parentField => $row[$parentField],
|
||||||
|
$childField => $row[$childField]
|
||||||
|
];
|
||||||
|
$relationItemIDs[] = $row[$childField];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$relationArray = DataObject::get($relationDataClass)->filter(['ID' => $relationItemIDs])->toArray();
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$eagerLoadID = $row[$parentField];
|
||||||
|
if (!isset($this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation])) {
|
||||||
|
$arrayList = ArrayList::create();
|
||||||
|
$arrayList->setDataClass($manyManyLastComponent['childClass']);
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation] = $arrayList;
|
||||||
|
}
|
||||||
|
$relationItem = array_values(array_filter($relationArray, function ($relationItem) use ($row, $childField) {
|
||||||
|
return $relationItem->ID === $row[$childField];
|
||||||
|
}))[0];
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation][$eagerLoadID][$relation]->push($relationItem);
|
||||||
|
}
|
||||||
|
$prevRelationArray = $relationArray;
|
||||||
|
$ids = $relationItemIDs;
|
||||||
|
} else {
|
||||||
|
throw new LogicException('Something went wrong with the eager loading');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $myDataList->eagerLoad('Some.Nested.Relation', 'Another.Relation')
|
||||||
|
*/
|
||||||
|
public function eagerLoad(...$relations): static
|
||||||
|
{
|
||||||
|
$arr = [];
|
||||||
|
foreach ($relations as $relation) {
|
||||||
|
$parts = explode('.', $relation);
|
||||||
|
$count = count($parts);
|
||||||
|
if ($count > 3) {
|
||||||
|
$message = "Eager loading only supports up to 3 levels of nesting, passed $count levels - $relation";
|
||||||
|
throw new InvalidArgumentException($message);
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$arr[] = $parts[$i];
|
||||||
|
} else {
|
||||||
|
$arr[] = $arr[count($arr) - 1] . '.' . $parts[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->eagerLoadRelations = array_merge($this->eagerLoadRelations, $arr);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of items in this DataList
|
* Return the number of items in this DataList
|
||||||
*/
|
*/
|
||||||
|
@ -304,6 +304,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
protected $unsavedRelations;
|
protected $unsavedRelations;
|
||||||
|
|
||||||
|
private array $eagerLoadedData = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of relations that should be cascade deleted, similar to `owns`
|
* List of relations that should be cascade deleted, similar to `owns`
|
||||||
* Note: This will trigger delete on many_many objects, not only the mapping table.
|
* Note: This will trigger delete on many_many objects, not only the mapping table.
|
||||||
@ -1802,6 +1804,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
public function getComponent($componentName)
|
public function getComponent($componentName)
|
||||||
{
|
{
|
||||||
|
if (isset($this->eagerLoadedData[$componentName])) {
|
||||||
|
return $this->eagerLoadedData[$componentName];
|
||||||
|
}
|
||||||
if (isset($this->components[$componentName])) {
|
if (isset($this->components[$componentName])) {
|
||||||
return $this->components[$componentName];
|
return $this->components[$componentName];
|
||||||
}
|
}
|
||||||
@ -1924,6 +1929,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setEagerLoadedData(string $eagerLoadRelation, mixed $eagerLoadedData): void
|
||||||
|
{
|
||||||
|
$this->eagerLoadedData[$eagerLoadRelation] = $eagerLoadedData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a one-to-many relation as a HasManyList
|
* Returns a one-to-many relation as a HasManyList
|
||||||
*
|
*
|
||||||
@ -1933,6 +1943,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
public function getComponents($componentName, $id = null)
|
public function getComponents($componentName, $id = null)
|
||||||
{
|
{
|
||||||
|
if (isset($this->eagerLoadedData[$componentName])) {
|
||||||
|
return $this->eagerLoadedData[$componentName];
|
||||||
|
}
|
||||||
if (!isset($id)) {
|
if (!isset($id)) {
|
||||||
$id = $this->ID;
|
$id = $this->ID;
|
||||||
}
|
}
|
||||||
@ -2150,6 +2163,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
*/
|
*/
|
||||||
public function getManyManyComponents($componentName, $id = null)
|
public function getManyManyComponents($componentName, $id = null)
|
||||||
{
|
{
|
||||||
|
if (isset($this->eagerLoadedData[$componentName])) {
|
||||||
|
return $this->eagerLoadedData[$componentName];
|
||||||
|
}
|
||||||
if (!isset($id)) {
|
if (!isset($id)) {
|
||||||
$id = $this->ID;
|
$id = $this->ID;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,31 @@ use SilverStripe\ORM\Tests\DataObjectTest\Team;
|
|||||||
use SilverStripe\ORM\Tests\DataObjectTest\TeamComment;
|
use SilverStripe\ORM\Tests\DataObjectTest\TeamComment;
|
||||||
use SilverStripe\ORM\Tests\DataObjectTest\ValidatedObject;
|
use SilverStripe\ORM\Tests\DataObjectTest\ValidatedObject;
|
||||||
use SilverStripe\ORM\Tests\ManyManyListTest\Category;
|
use SilverStripe\ORM\Tests\ManyManyListTest\Category;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\EagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasOneEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasOneSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasOneSubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsToEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsToSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsToSubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasManyEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasManySubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\HasManySubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManySubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManySubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyThroughEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyThroughSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyThroughSubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\EagerLoadObjectManyManyThroughEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyThroughEagerLoadObjectManyManyThroughSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\ManyManyThroughSubEagerLoadObjectManyManyThroughSubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsManyManyEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsManyManySubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\BelongsManyManySubSubEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\MixedHasManyEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\MixedHasOneEagerLoadObject;
|
||||||
|
use SilverStripe\ORM\Tests\DataListTest\MixedManyManyEagerLoadObject;
|
||||||
|
|
||||||
class DataListTest extends SapphireTest
|
class DataListTest extends SapphireTest
|
||||||
{
|
{
|
||||||
@ -35,9 +60,37 @@ class DataListTest extends SapphireTest
|
|||||||
|
|
||||||
public static function getExtraDataObjects()
|
public static function getExtraDataObjects()
|
||||||
{
|
{
|
||||||
|
$eagerLoadDataObjects = [
|
||||||
|
EagerLoadObject::class,
|
||||||
|
HasOneEagerLoadObject::class,
|
||||||
|
HasOneSubEagerLoadObject::class,
|
||||||
|
HasOneSubSubEagerLoadObject::class,
|
||||||
|
BelongsToEagerLoadObject::class,
|
||||||
|
BelongsToSubEagerLoadObject::class,
|
||||||
|
BelongsToSubSubEagerLoadObject::class,
|
||||||
|
HasManyEagerLoadObject::class,
|
||||||
|
HasManySubEagerLoadObject::class,
|
||||||
|
HasManySubSubEagerLoadObject::class,
|
||||||
|
ManyManyEagerLoadObject::class,
|
||||||
|
ManyManySubEagerLoadObject::class,
|
||||||
|
ManyManySubSubEagerLoadObject::class,
|
||||||
|
ManyManyThroughEagerLoadObject::class,
|
||||||
|
ManyManyThroughSubEagerLoadObject::class,
|
||||||
|
ManyManyThroughSubSubEagerLoadObject::class,
|
||||||
|
EagerLoadObjectManyManyThroughEagerLoadObject::class,
|
||||||
|
ManyManyThroughEagerLoadObjectManyManyThroughSubEagerLoadObject::class,
|
||||||
|
ManyManyThroughSubEagerLoadObjectManyManyThroughSubSubEagerLoadObject::class,
|
||||||
|
BelongsManyManyEagerLoadObject::class,
|
||||||
|
BelongsManyManySubEagerLoadObject::class,
|
||||||
|
BelongsManyManySubSubEagerLoadObject::class,
|
||||||
|
MixedHasManyEagerLoadObject::class,
|
||||||
|
MixedHasOneEagerLoadObject::class,
|
||||||
|
MixedManyManyEagerLoadObject::class,
|
||||||
|
];
|
||||||
return array_merge(
|
return array_merge(
|
||||||
DataObjectTest::$extra_data_objects,
|
DataObjectTest::$extra_data_objects,
|
||||||
ManyManyListTest::$extra_data_objects
|
ManyManyListTest::$extra_data_objects,
|
||||||
|
$eagerLoadDataObjects
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2197,4 +2250,611 @@ class DataListTest extends SapphireTest
|
|||||||
$this->assertEmpty($expectedIDs, 'chunk returns all the results that the regular iterator does');
|
$this->assertEmpty($expectedIDs, 'chunk returns all the results that the regular iterator does');
|
||||||
$this->assertEquals($expectedQueryCount, $dataQuery->getCount());
|
$this->assertEquals($expectedQueryCount, $dataQuery->getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideEagerLoadRelations
|
||||||
|
*/
|
||||||
|
public function testEagerLoadRelations(string $iden, array $eagerLoad, int $expected): void
|
||||||
|
{
|
||||||
|
$this->createEagerLoadData();
|
||||||
|
$dataList = EagerLoadObject::get()->eagerLoad(...$eagerLoad);
|
||||||
|
list($results, $selectCount) = $this->iterateEagerLoadData($dataList);
|
||||||
|
$this->assertSame($this->expectedEagerLoadData(), $results, $iden);
|
||||||
|
$this->assertSame($expected, $selectCount, $iden);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideEagerLoadRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'iden' => 'lazy-load',
|
||||||
|
'eagerLoad' => [],
|
||||||
|
'expected' => 83
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-one-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasOneEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 82
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-one-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasOneEagerLoadObject.HasOneSubEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 81
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-one-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasOneEagerLoadObject.HasOneSubEagerLoadObject.HasOneSubSubEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 80
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-to-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsToEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 82
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-to-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsToEagerLoadObject.BelongsToSubEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 81
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-to-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsToEagerLoadObject.BelongsToSubEagerLoadObject.BelongsToSubSubEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 80
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-many-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasManyEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 82
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-many-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasManyEagerLoadObjects.HasManySubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 79
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'has-many-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasManyEagerLoadObjects.HasManySubEagerLoadObjects.HasManySubSubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 72
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 83 // same number as lazy-load, though without an INNER JOIN
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyEagerLoadObjects.ManyManySubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 81
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyEagerLoadObjects.ManyManySubEagerLoadObjects.ManyManySubSubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 75
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-through-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyThroughEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 83
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-through-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyThroughEagerLoadObjects.ManyManyThroughSubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 81
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'many-many-through-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'ManyManyThroughEagerLoadObjects.ManyManyThroughSubEagerLoadObjects.ManyManyThroughSubSubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 75
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-many-many-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsManyManyEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 83
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-many-many-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsManyManyEagerLoadObjects.BelongsManyManySubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 81
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'belongs-many-many-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'BelongsManyManyEagerLoadObjects.BelongsManyManySubEagerLoadObjects.BelongsManyManySubSubEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 75
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'mixed-a',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'MixedManyManyEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 83
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'mixed-b',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'MixedManyManyEagerLoadObjects.MixedHasManyEagerLoadObjects',
|
||||||
|
],
|
||||||
|
'expected' => 80
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'mixed-c',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'MixedManyManyEagerLoadObjects.MixedHasManyEagerLoadObjects.MixedHasOneEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 73
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'iden' => 'all',
|
||||||
|
'eagerLoad' => [
|
||||||
|
'HasOneEagerLoadObject.HasOneSubEagerLoadObject.HasOneSubSubEagerLoadObject',
|
||||||
|
'BelongsToEagerLoadObject.BelongsToSubEagerLoadObject.BelongsToSubSubEagerLoadObject',
|
||||||
|
'HasManyEagerLoadObjects.HasManySubEagerLoadObjects.HasManySubSubEagerLoadObjects',
|
||||||
|
'ManyManyEagerLoadObjects.ManyManySubEagerLoadObjects.ManyManySubSubEagerLoadObjects',
|
||||||
|
'ManyManyThroughEagerLoadObjects.ManyManyThroughSubEagerLoadObjects.ManyManyThroughSubSubEagerLoadObjects',
|
||||||
|
'BelongsManyManyEagerLoadObjects.BelongsManyManySubEagerLoadObjects.BelongsManyManySubSubEagerLoadObjects',
|
||||||
|
'MixedManyManyEagerLoadObjects.MixedHasManyEagerLoadObjects.MixedHasOneEagerLoadObject',
|
||||||
|
],
|
||||||
|
'expected' => 32
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEagerLoadData(): void
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < 2; $i++) {
|
||||||
|
// base object
|
||||||
|
$obj = new EagerLoadObject();
|
||||||
|
$obj->Title = "obj $i";
|
||||||
|
$objID = $obj->write();
|
||||||
|
// has_one
|
||||||
|
$hasOneObj = new HasOneEagerLoadObject();
|
||||||
|
$hasOneObj->Title = "hasOneObj $i";
|
||||||
|
$hasOneObjID = $hasOneObj->write();
|
||||||
|
$obj->HasOneEagerLoadObjectID = $hasOneObjID;
|
||||||
|
$obj->write();
|
||||||
|
$hasOneSubObj = new HasOneSubEagerLoadObject();
|
||||||
|
$hasOneSubObj->Title = "hasOneSubObj $i";
|
||||||
|
$hasOneSubObjID = $hasOneSubObj->write();
|
||||||
|
$hasOneObj->HasOneSubEagerLoadObjectID = $hasOneSubObjID;
|
||||||
|
$hasOneObj->write();
|
||||||
|
$hasOneSubSubObj = new HasOneSubSubEagerLoadObject();
|
||||||
|
$hasOneSubSubObj->Title = "hasOneSubSubObj $i";
|
||||||
|
$hasOneSubSubObjID = $hasOneSubSubObj->write();
|
||||||
|
$hasOneSubObj->HasOneSubSubEagerLoadObjectID = $hasOneSubSubObjID;
|
||||||
|
$hasOneSubObj->write();
|
||||||
|
// belongs_to
|
||||||
|
$belongsToObj = new BelongsToEagerLoadObject();
|
||||||
|
$belongsToObj->EagerLoadObjectID = $objID;
|
||||||
|
$belongsToObj->Title = "belongsToObj $i";
|
||||||
|
$belongsToObjID = $belongsToObj->write();
|
||||||
|
$belongsToSubObj = new BelongsToSubEagerLoadObject();
|
||||||
|
$belongsToSubObj->BelongsToEagerLoadObjectID = $belongsToObjID;
|
||||||
|
$belongsToSubObj->Title = "belongsToSubObj $i";
|
||||||
|
$belongsToSubObjID = $belongsToSubObj->write();
|
||||||
|
$belongsToSubSubObj = new BelongsToSubSubEagerLoadObject();
|
||||||
|
$belongsToSubSubObj->BelongsToSubEagerLoadObjectID = $belongsToSubObjID;
|
||||||
|
$belongsToSubSubObj->Title = "belongsToSubSubObj $i";
|
||||||
|
$belongsToSubSubObj->write();
|
||||||
|
// has_many
|
||||||
|
for ($j = 0; $j < 2; $j++) {
|
||||||
|
$hasManyObj = new HasManyEagerLoadObject();
|
||||||
|
$hasManyObj->EagerLoadObjectID = $objID;
|
||||||
|
$hasManyObj->Title = "hasManyObj $i $j";
|
||||||
|
$hasManyObjID = $hasManyObj->write();
|
||||||
|
for ($k = 0; $k < 2; $k++) {
|
||||||
|
$hasManySubObj = new HasManySubEagerLoadObject();
|
||||||
|
$hasManySubObj->HasManyEagerLoadObjectID = $hasManyObjID;
|
||||||
|
$hasManySubObj->Title = "hasManySubObj $i $j $k";
|
||||||
|
$hasManySubObjID = $hasManySubObj->write();
|
||||||
|
for ($l = 0; $l < 2; $l++) {
|
||||||
|
$hasManySubSubObj = new HasManySubSubEagerLoadObject();
|
||||||
|
$hasManySubSubObj->HasManySubEagerLoadObjectID = $hasManySubObjID;
|
||||||
|
$hasManySubSubObj->Title = "hasManySubSubObj $i $j $k $l";
|
||||||
|
$hasManySubSubObj->write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// many_many
|
||||||
|
for ($j = 0; $j < 2; $j++) {
|
||||||
|
$manyManyObj = new ManyManyEagerLoadObject();
|
||||||
|
$manyManyObj->Title = "manyManyObj $i $j";
|
||||||
|
$manyManyObj->write();
|
||||||
|
$obj->ManyManyEagerLoadObjects()->add($manyManyObj);
|
||||||
|
for ($k = 0; $k < 2; $k++) {
|
||||||
|
$manyManySubObj = new ManyManySubEagerLoadObject();
|
||||||
|
$manyManySubObj->Title = "manyManySubObj $i $j $k";
|
||||||
|
$manyManySubObj->write();
|
||||||
|
$manyManyObj->ManyManySubEagerLoadObjects()->add($manyManySubObj);
|
||||||
|
for ($l = 0; $l < 2; $l++) {
|
||||||
|
$manyManySubSubObj = new ManyManySubSubEagerLoadObject();
|
||||||
|
$manyManySubSubObj->Title = "manyManySubSubObj $i $j $k $l";
|
||||||
|
$manyManySubSubObj->write();
|
||||||
|
$manyManySubObj->ManyManySubSubEagerLoadObjects()->add($manyManySubSubObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// many_many_through
|
||||||
|
for ($j = 0; $j < 2; $j++) {
|
||||||
|
$manyManyThroughObj = new ManyManyThroughEagerLoadObject();
|
||||||
|
$manyManyThroughObj->Title = "manyManyThroughObj $i $j";
|
||||||
|
$manyManyThroughObj->write();
|
||||||
|
$obj->ManyManyThroughEagerLoadObjects()->add($manyManyThroughObj);
|
||||||
|
for ($k = 0; $k < 2; $k++) {
|
||||||
|
$manyManyThroughSubObj = new ManyManyThroughSubEagerLoadObject();
|
||||||
|
$manyManyThroughSubObj->Title = "manyManyThroughSubObj $i $j $k";
|
||||||
|
$manyManyThroughSubObj->write();
|
||||||
|
$manyManyThroughObj->ManyManyThroughSubEagerLoadObjects()->add($manyManyThroughSubObj);
|
||||||
|
for ($l = 0; $l < 2; $l++) {
|
||||||
|
$manyManyThroughSubSubObj = new ManyManyThroughSubSubEagerLoadObject();
|
||||||
|
$manyManyThroughSubSubObj->Title = "manyManyThroughSubSubObj $i $j $k $l";
|
||||||
|
$manyManyThroughSubSubObj->write();
|
||||||
|
$manyManyThroughSubObj->ManyManyThroughSubSubEagerLoadObjects()->add($manyManyThroughSubSubObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// belongs_many_many
|
||||||
|
for ($j = 0; $j < 2; $j++) {
|
||||||
|
$belongsManyManyObj = new BelongsManyManyEagerLoadObject();
|
||||||
|
$belongsManyManyObj->Title = "belongsManyManyObj $i $j";
|
||||||
|
$belongsManyManyObj->write();
|
||||||
|
$obj->BelongsManyManyEagerLoadObjects()->add($belongsManyManyObj);
|
||||||
|
for ($k = 0; $k < 2; $k++) {
|
||||||
|
$belongsManyManySubObj = new BelongsManyManySubEagerLoadObject();
|
||||||
|
$belongsManyManySubObj->Title = "belongsManyManySubObj $i $j $k";
|
||||||
|
$belongsManyManySubObj->write();
|
||||||
|
$belongsManyManyObj->BelongsManyManySubEagerLoadObjects()->add($belongsManyManySubObj);
|
||||||
|
for ($l = 0; $l < 2; $l++) {
|
||||||
|
$belongsManyManySubSubObj = new BelongsManyManySubSubEagerLoadObject();
|
||||||
|
$belongsManyManySubSubObj->Title = "belongsManyManySubSubObj $i $j $k $l";
|
||||||
|
$belongsManyManySubSubObj->write();
|
||||||
|
$belongsManyManySubObj->BelongsManyManySubSubEagerLoadObjects()->add($belongsManyManySubSubObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// mixed
|
||||||
|
for ($j = 0; $j < 2; $j++) {
|
||||||
|
$mixedManyManyObj = new MixedManyManyEagerLoadObject();
|
||||||
|
$mixedManyManyObj->Title = "mixedManyManyObj $i $j";
|
||||||
|
$mixedManyManyObj->write();
|
||||||
|
$obj->MixedManyManyEagerLoadObjects()->add($mixedManyManyObj);
|
||||||
|
for ($k = 0; $k < 2; $k++) {
|
||||||
|
$mixedHasManyObj = new MixedHasManyEagerLoadObject();
|
||||||
|
$mixedHasManyObj->Title = "mixedHasManyObj $i $j $k";
|
||||||
|
$mixedHasManyObjID = $mixedHasManyObj->write();
|
||||||
|
$mixedManyManyObj->MixedHasManyEagerLoadObjects()->add($mixedHasManyObj);
|
||||||
|
for ($l = 0; $l < 2; $l++) {
|
||||||
|
$mixedHasOneObj = new MixedHasOneEagerLoadObject();
|
||||||
|
$mixedHasOneObj->Title = "mixedHasOneObj $i $j $k $l";
|
||||||
|
$mixedHasOneObjID = $mixedHasOneObj->write();
|
||||||
|
$mixedHasManyObj->MixedHasOneEagerLoadObjectID = $mixedHasOneObjID;
|
||||||
|
$mixedHasManyObj->write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function iterateEagerLoadData(DataList $dataList): array
|
||||||
|
{
|
||||||
|
$results = [];
|
||||||
|
$selectCount = -1;
|
||||||
|
$showqueries = $_REQUEST['showqueries'] ?? null;
|
||||||
|
try {
|
||||||
|
// force showqueries on to count the number of SELECT statements via output-buffering
|
||||||
|
// if this approach turns out to be too brittle later on, switch to what debugbar
|
||||||
|
// does and use tractorcow/proxy-db which should be installed as a dev-dependency
|
||||||
|
// https://github.com/lekoala/silverstripe-debugbar/blob/master/code/Collector/DatabaseCollector.php#L79
|
||||||
|
$_REQUEST['showqueries'] = 1;
|
||||||
|
ob_start();
|
||||||
|
echo '__START_ITERATE__';
|
||||||
|
$results = [];
|
||||||
|
$i = 0;
|
||||||
|
foreach ($dataList as $obj) {
|
||||||
|
// base obj
|
||||||
|
$results[] = $obj->Title;
|
||||||
|
// has_one
|
||||||
|
$hasOneObj = $obj->HasOneEagerLoadObject();
|
||||||
|
$hasOneSubObj = $hasOneObj->HasOneSubEagerLoadObject();
|
||||||
|
$hasOneSubSubObj = $hasOneSubObj->HasOneSubSubEagerLoadObject();
|
||||||
|
$results[] = $hasOneObj->Title;
|
||||||
|
$results[] = $hasOneSubObj->Title;
|
||||||
|
$results[] = $hasOneSubSubObj->Title;
|
||||||
|
// belongs_to
|
||||||
|
$belongsToObj = $obj->BelongsToEagerLoadObject();
|
||||||
|
$belongsToSubObj = $belongsToObj->BelongsToSubEagerLoadObject();
|
||||||
|
$belongsToSubSubObj = $belongsToSubObj->BelongsToSubSubEagerLoadObject();
|
||||||
|
$results[] = $belongsToObj->Title;
|
||||||
|
$results[] = $belongsToSubObj->Title;
|
||||||
|
$results[] = $belongsToSubSubObj->Title;
|
||||||
|
// has_many
|
||||||
|
foreach ($obj->HasManyEagerLoadObjects() as $hasManyObj) {
|
||||||
|
$results[] = $hasManyObj->Title;
|
||||||
|
foreach ($hasManyObj->HasManySubEagerLoadObjects() as $hasManySubObj) {
|
||||||
|
$results[] = $hasManySubObj->Title;
|
||||||
|
foreach ($hasManySubObj->HasManySubSubEagerLoadObjects() as $hasManySubSubObj) {
|
||||||
|
$results[] = $hasManySubSubObj->Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// many_many
|
||||||
|
foreach ($obj->ManyManyEagerLoadObjects() as $manyManyObj) {
|
||||||
|
$results[] = $manyManyObj->Title;
|
||||||
|
foreach ($manyManyObj->ManyManySubEagerLoadObjects() as $manyManySubObj) {
|
||||||
|
$results[] = $manyManySubObj->Title;
|
||||||
|
foreach ($manyManySubObj->ManyManySubSubEagerLoadObjects() as $manyManySubSubObj) {
|
||||||
|
$results[] = $manyManySubSubObj->Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// many_many_through
|
||||||
|
foreach ($obj->ManyManyThroughEagerLoadObjects() as $manyManyThroughObj) {
|
||||||
|
$results[] = $manyManyThroughObj->Title;
|
||||||
|
foreach ($manyManyThroughObj->ManyManyThroughSubEagerLoadObjects() as $manyManyThroughSubObj) {
|
||||||
|
$results[] = $manyManyThroughSubObj->Title;
|
||||||
|
foreach ($manyManyThroughSubObj->ManyManyThroughSubSubEagerLoadObjects() as $manyManyThroughSubSubObj) {
|
||||||
|
$results[] = $manyManyThroughSubSubObj->Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// belongs_many_many
|
||||||
|
foreach ($obj->BelongsManyManyEagerLoadObjects() as $belongsManyManyObj) {
|
||||||
|
$results[] = $belongsManyManyObj->Title;
|
||||||
|
foreach ($belongsManyManyObj->BelongsManyManySubEagerLoadObjects() as $belongsManyManySubObj) {
|
||||||
|
$results[] = $belongsManyManySubObj->Title;
|
||||||
|
foreach ($belongsManyManySubObj->BelongsManyManySubSubEagerLoadObjects() as $belongsManyManySubSubObj) {
|
||||||
|
$results[] = $belongsManyManySubSubObj->Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// mixed
|
||||||
|
foreach ($obj->MixedManyManyEagerLoadObjects() as $mixedManyManyObj) {
|
||||||
|
$results[] = $mixedManyManyObj->Title;
|
||||||
|
foreach ($mixedManyManyObj->MixedHasManyEagerLoadObjects() as $mixedHasManyObj) {
|
||||||
|
$results[] = $mixedHasManyObj->Title;
|
||||||
|
$results[] = $mixedHasManyObj->MixedHasOneEagerLoadObject()->Title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$s = ob_get_clean();
|
||||||
|
$s = preg_replace('/.*__START_ITERATE__/s', '', $s);
|
||||||
|
$selectCount = substr_count($s, ': SELECT');
|
||||||
|
} finally {
|
||||||
|
if ($showqueries) {
|
||||||
|
$_REQUEST['showqueries'] = $showqueries;
|
||||||
|
} else {
|
||||||
|
unset($_REQUEST['showqueries']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [$results, $selectCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function expectedEagerLoadData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'obj 0',
|
||||||
|
'hasOneObj 0',
|
||||||
|
'hasOneSubObj 0',
|
||||||
|
'hasOneSubSubObj 0',
|
||||||
|
'belongsToObj 0',
|
||||||
|
'belongsToSubObj 0',
|
||||||
|
'belongsToSubSubObj 0',
|
||||||
|
'hasManyObj 0 0',
|
||||||
|
'hasManySubObj 0 0 0',
|
||||||
|
'hasManySubSubObj 0 0 0 0',
|
||||||
|
'hasManySubSubObj 0 0 0 1',
|
||||||
|
'hasManySubObj 0 0 1',
|
||||||
|
'hasManySubSubObj 0 0 1 0',
|
||||||
|
'hasManySubSubObj 0 0 1 1',
|
||||||
|
'hasManyObj 0 1',
|
||||||
|
'hasManySubObj 0 1 0',
|
||||||
|
'hasManySubSubObj 0 1 0 0',
|
||||||
|
'hasManySubSubObj 0 1 0 1',
|
||||||
|
'hasManySubObj 0 1 1',
|
||||||
|
'hasManySubSubObj 0 1 1 0',
|
||||||
|
'hasManySubSubObj 0 1 1 1',
|
||||||
|
'manyManyObj 0 0',
|
||||||
|
'manyManySubObj 0 0 0',
|
||||||
|
'manyManySubSubObj 0 0 0 0',
|
||||||
|
'manyManySubSubObj 0 0 0 1',
|
||||||
|
'manyManySubObj 0 0 1',
|
||||||
|
'manyManySubSubObj 0 0 1 0',
|
||||||
|
'manyManySubSubObj 0 0 1 1',
|
||||||
|
'manyManyObj 0 1',
|
||||||
|
'manyManySubObj 0 1 0',
|
||||||
|
'manyManySubSubObj 0 1 0 0',
|
||||||
|
'manyManySubSubObj 0 1 0 1',
|
||||||
|
'manyManySubObj 0 1 1',
|
||||||
|
'manyManySubSubObj 0 1 1 0',
|
||||||
|
'manyManySubSubObj 0 1 1 1',
|
||||||
|
'manyManyThroughObj 0 0',
|
||||||
|
'manyManyThroughSubObj 0 0 0',
|
||||||
|
'manyManyThroughSubSubObj 0 0 0 0',
|
||||||
|
'manyManyThroughSubSubObj 0 0 0 1',
|
||||||
|
'manyManyThroughSubObj 0 0 1',
|
||||||
|
'manyManyThroughSubSubObj 0 0 1 0',
|
||||||
|
'manyManyThroughSubSubObj 0 0 1 1',
|
||||||
|
'manyManyThroughObj 0 1',
|
||||||
|
'manyManyThroughSubObj 0 1 0',
|
||||||
|
'manyManyThroughSubSubObj 0 1 0 0',
|
||||||
|
'manyManyThroughSubSubObj 0 1 0 1',
|
||||||
|
'manyManyThroughSubObj 0 1 1',
|
||||||
|
'manyManyThroughSubSubObj 0 1 1 0',
|
||||||
|
'manyManyThroughSubSubObj 0 1 1 1',
|
||||||
|
'belongsManyManyObj 0 0',
|
||||||
|
'belongsManyManySubObj 0 0 0',
|
||||||
|
'belongsManyManySubSubObj 0 0 0 0',
|
||||||
|
'belongsManyManySubSubObj 0 0 0 1',
|
||||||
|
'belongsManyManySubObj 0 0 1',
|
||||||
|
'belongsManyManySubSubObj 0 0 1 0',
|
||||||
|
'belongsManyManySubSubObj 0 0 1 1',
|
||||||
|
'belongsManyManyObj 0 1',
|
||||||
|
'belongsManyManySubObj 0 1 0',
|
||||||
|
'belongsManyManySubSubObj 0 1 0 0',
|
||||||
|
'belongsManyManySubSubObj 0 1 0 1',
|
||||||
|
'belongsManyManySubObj 0 1 1',
|
||||||
|
'belongsManyManySubSubObj 0 1 1 0',
|
||||||
|
'belongsManyManySubSubObj 0 1 1 1',
|
||||||
|
'mixedManyManyObj 0 0',
|
||||||
|
'mixedHasManyObj 0 0 0',
|
||||||
|
'mixedHasOneObj 0 0 0 1',
|
||||||
|
'mixedHasManyObj 0 0 1',
|
||||||
|
'mixedHasOneObj 0 0 1 1',
|
||||||
|
'mixedManyManyObj 0 1',
|
||||||
|
'mixedHasManyObj 0 1 0',
|
||||||
|
'mixedHasOneObj 0 1 0 1',
|
||||||
|
'mixedHasManyObj 0 1 1',
|
||||||
|
'mixedHasOneObj 0 1 1 1',
|
||||||
|
'obj 1',
|
||||||
|
'hasOneObj 1',
|
||||||
|
'hasOneSubObj 1',
|
||||||
|
'hasOneSubSubObj 1',
|
||||||
|
'belongsToObj 1',
|
||||||
|
'belongsToSubObj 1',
|
||||||
|
'belongsToSubSubObj 1',
|
||||||
|
'hasManyObj 1 0',
|
||||||
|
'hasManySubObj 1 0 0',
|
||||||
|
'hasManySubSubObj 1 0 0 0',
|
||||||
|
'hasManySubSubObj 1 0 0 1',
|
||||||
|
'hasManySubObj 1 0 1',
|
||||||
|
'hasManySubSubObj 1 0 1 0',
|
||||||
|
'hasManySubSubObj 1 0 1 1',
|
||||||
|
'hasManyObj 1 1',
|
||||||
|
'hasManySubObj 1 1 0',
|
||||||
|
'hasManySubSubObj 1 1 0 0',
|
||||||
|
'hasManySubSubObj 1 1 0 1',
|
||||||
|
'hasManySubObj 1 1 1',
|
||||||
|
'hasManySubSubObj 1 1 1 0',
|
||||||
|
'hasManySubSubObj 1 1 1 1',
|
||||||
|
'manyManyObj 1 0',
|
||||||
|
'manyManySubObj 1 0 0',
|
||||||
|
'manyManySubSubObj 1 0 0 0',
|
||||||
|
'manyManySubSubObj 1 0 0 1',
|
||||||
|
'manyManySubObj 1 0 1',
|
||||||
|
'manyManySubSubObj 1 0 1 0',
|
||||||
|
'manyManySubSubObj 1 0 1 1',
|
||||||
|
'manyManyObj 1 1',
|
||||||
|
'manyManySubObj 1 1 0',
|
||||||
|
'manyManySubSubObj 1 1 0 0',
|
||||||
|
'manyManySubSubObj 1 1 0 1',
|
||||||
|
'manyManySubObj 1 1 1',
|
||||||
|
'manyManySubSubObj 1 1 1 0',
|
||||||
|
'manyManySubSubObj 1 1 1 1',
|
||||||
|
'manyManyThroughObj 1 0',
|
||||||
|
'manyManyThroughSubObj 1 0 0',
|
||||||
|
'manyManyThroughSubSubObj 1 0 0 0',
|
||||||
|
'manyManyThroughSubSubObj 1 0 0 1',
|
||||||
|
'manyManyThroughSubObj 1 0 1',
|
||||||
|
'manyManyThroughSubSubObj 1 0 1 0',
|
||||||
|
'manyManyThroughSubSubObj 1 0 1 1',
|
||||||
|
'manyManyThroughObj 1 1',
|
||||||
|
'manyManyThroughSubObj 1 1 0',
|
||||||
|
'manyManyThroughSubSubObj 1 1 0 0',
|
||||||
|
'manyManyThroughSubSubObj 1 1 0 1',
|
||||||
|
'manyManyThroughSubObj 1 1 1',
|
||||||
|
'manyManyThroughSubSubObj 1 1 1 0',
|
||||||
|
'manyManyThroughSubSubObj 1 1 1 1',
|
||||||
|
'belongsManyManyObj 1 0',
|
||||||
|
'belongsManyManySubObj 1 0 0',
|
||||||
|
'belongsManyManySubSubObj 1 0 0 0',
|
||||||
|
'belongsManyManySubSubObj 1 0 0 1',
|
||||||
|
'belongsManyManySubObj 1 0 1',
|
||||||
|
'belongsManyManySubSubObj 1 0 1 0',
|
||||||
|
'belongsManyManySubSubObj 1 0 1 1',
|
||||||
|
'belongsManyManyObj 1 1',
|
||||||
|
'belongsManyManySubObj 1 1 0',
|
||||||
|
'belongsManyManySubSubObj 1 1 0 0',
|
||||||
|
'belongsManyManySubSubObj 1 1 0 1',
|
||||||
|
'belongsManyManySubObj 1 1 1',
|
||||||
|
'belongsManyManySubSubObj 1 1 1 0',
|
||||||
|
'belongsManyManySubSubObj 1 1 1 1',
|
||||||
|
'mixedManyManyObj 1 0',
|
||||||
|
'mixedHasManyObj 1 0 0',
|
||||||
|
'mixedHasOneObj 1 0 0 1',
|
||||||
|
'mixedHasManyObj 1 0 1',
|
||||||
|
'mixedHasOneObj 1 0 1 1',
|
||||||
|
'mixedManyManyObj 1 1',
|
||||||
|
'mixedHasManyObj 1 1 0',
|
||||||
|
'mixedHasOneObj 1 1 0 1',
|
||||||
|
'mixedHasManyObj 1 1 1',
|
||||||
|
'mixedHasOneObj 1 1 1 1',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEagerLoadFourthLevelException(): void
|
||||||
|
{
|
||||||
|
$eagerLoadRelation = implode('.', [
|
||||||
|
'MixedManyManyEagerLoadObjects',
|
||||||
|
'MixedHasManyEagerLoadObjects',
|
||||||
|
'MixedHasOneEagerLoadObject',
|
||||||
|
'FourthLevel'
|
||||||
|
]);
|
||||||
|
$expectedMessage = implode(' - ', [
|
||||||
|
'Eager loading only supports up to 3 levels of nesting, passed 4 levels',
|
||||||
|
$eagerLoadRelation
|
||||||
|
]);
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage($expectedMessage);
|
||||||
|
EagerLoadObject::get()->eagerLoad($eagerLoadRelation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideEagerLoadInvalidRelationException
|
||||||
|
*/
|
||||||
|
public function testEagerLoadInvalidRelationException(string $eagerLoadRelation): void
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage("Invalid relation passed to eagerLoad() - $eagerLoadRelation");
|
||||||
|
$this->createEagerLoadData();
|
||||||
|
EagerLoadObject::get()->eagerLoad($eagerLoadRelation)->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideEagerLoadInvalidRelationException(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'Invalid',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'MixedManyManyEagerLoadObjects.Invalid',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'MixedManyManyEagerLoadObjects.MixedHasManyEagerLoadObjects.Invalid'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsManyManyEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsManyManyEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'EagerLoadObjects' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'BelongsManyManySubEagerLoadObjects' => BelongsManyManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsManyManySubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsManyManySubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
// note: need to use singular name for relationship rather than plural otherwise
|
||||||
|
// will get error get
|
||||||
|
// mysqli_sql_exception: Incorrect table name 'BelongsManyManySubEagerLoadObject_BelongsManyManyEagerLoadObjects'
|
||||||
|
'BelongsManyManyEagerLoadObject' => BelongsManyManyEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'BelongsManyManySubSubEagerLoadObjects' => BelongsManyManySubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsManyManySubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsManyManySubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
// note: using 'MyManyMany' as name to otherise will get
|
||||||
|
// mysqli_sql_exception: Incorrect table name'BelongsManyManySubSubEagerLoadObject_BelongsManyManySubEagerLoadObjects'
|
||||||
|
// or 'BelongsManyManySubSubEagerLoadObject_BelongsManyManySubEagerLoadObjects'
|
||||||
|
// for relationships named BelongsManyManySubEagerLoadObjects (plural) and
|
||||||
|
// BelongsManyManySubEagerLoadObject (singular)
|
||||||
|
'MyManyMany' => BelongsManyManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/BelongsToEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/BelongsToEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsToEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsToEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'EagerLoadObject' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'BelongsToSubEagerLoadObject' => BelongsToSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/BelongsToSubEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/BelongsToSubEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsToSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsToSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'BelongsToEagerLoadObject' => BelongsToEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'BelongsToSubSubEagerLoadObject' => BelongsToSubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class BelongsToSubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'BelongsToSubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'BelongsToSubEagerLoadObject' => BelongsToSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
41
tests/php/ORM/DataListTest/EagerLoadObject.php
Normal file
41
tests/php/ORM/DataListTest/EagerLoadObject.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class EagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'EagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'HasOneEagerLoadObject' => HasOneEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'BelongsToEagerLoadObject' => BelongsToEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_many = [
|
||||||
|
'HasManyEagerLoadObjects' => HasManyEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'ManyManyEagerLoadObjects' => ManyManyEagerLoadObject::class,
|
||||||
|
'ManyManyThroughEagerLoadObjects' => [
|
||||||
|
'through' => EagerLoadObjectManyManyThroughEagerLoadObject::class,
|
||||||
|
'from' => 'EagerLoadObject',
|
||||||
|
'to' => 'ManyManyThroughEagerLoadObject',
|
||||||
|
],
|
||||||
|
'MixedManyManyEagerLoadObjects' => MixedManyManyEagerLoadObject::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'BelongsManyManyEagerLoadObjects' => BelongsManyManyEagerLoadObject::class,
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class EagerLoadObjectManyManyThroughEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'EagerLoadObjectManyManyThroughEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'EagerLoadObject' => EagerLoadObject::class,
|
||||||
|
'ManyManyThroughEagerLoadObject' => ManyManyThroughEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/HasManyEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/HasManyEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasManyEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasManyEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'EagerLoadObject' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_many = [
|
||||||
|
'HasManySubEagerLoadObjects' => HasManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/HasManySubEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/HasManySubEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasManySubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasManySubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'HasManyEagerLoadObject' => HasManyEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_many = [
|
||||||
|
'HasManySubSubEagerLoadObjects' => HasManySubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/HasManySubSubEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/HasManySubSubEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasManySubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasManySubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'HasManySubEagerLoadObject' => HasManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_many = [
|
||||||
|
'HasManySubSubSubEagerLoadObjects' => HasManySubSubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/HasOneEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/HasOneEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasOneEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasOneEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'HasOneSubEagerLoadObject' => HasOneSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'EagerLoadObject' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/HasOneSubEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/HasOneSubEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasOneSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasOneSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'HasOneSubSubEagerLoadObject' => HasOneSubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'HasOneEagerLoadObject' => HasOneEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
19
tests/php/ORM/DataListTest/HasOneSubSubEagerLoadObject.php
Normal file
19
tests/php/ORM/DataListTest/HasOneSubSubEagerLoadObject.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class HasOneSubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'HasOneSubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_to = [
|
||||||
|
'HasOneSubEagerLoadObject' => HasOneSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/ManyManyEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/ManyManyEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManyEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'ManyManySubEagerLoadObjects' => ManyManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'EagerLoadObjects' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
24
tests/php/ORM/DataListTest/ManyManySubEagerLoadObject.php
Normal file
24
tests/php/ORM/DataListTest/ManyManySubEagerLoadObject.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManySubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManySubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'ManyManySubSubEagerLoadObjects' => ManyManySubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'EagerLoadObjects' => EagerLoadObject::class,
|
||||||
|
'ManyManyEagerLoadObjects' => ManyManyEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
20
tests/php/ORM/DataListTest/ManyManySubSubEagerLoadObject.php
Normal file
20
tests/php/ORM/DataListTest/ManyManySubSubEagerLoadObject.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManySubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManySubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'ManyManyEagerLoadObjects' => ManyManyEagerLoadObjects::class,
|
||||||
|
'ManyManySubEagerLoadObjects' => ManyManySubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyThroughEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManyThroughEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'ManyManyThroughSubEagerLoadObjects' => [
|
||||||
|
'through' => ManyManyThroughEagerLoadObjectManyManyThroughSubEagerLoadObject::class,
|
||||||
|
'from' => 'ManyManyThroughEagerLoadObject',
|
||||||
|
'to' => 'ManyManyThroughSubEagerLoadObject',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'EagerLoadObjects' => EagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyThroughEagerLoadObjectManyManyThroughSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManyThroughEagerLoadObjectManyManyThroughSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'ManyManyThroughEagerLoadObject' => ManyManyThroughEagerLoadObject::class,
|
||||||
|
'ManyManyThroughSubEagerLoadObject' => ManyManyThroughSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyThroughSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManyThroughSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $many_many = [
|
||||||
|
'ManyManyThroughSubSubEagerLoadObjects' => [
|
||||||
|
'through' => ManyManyThroughSubEagerLoadObjectManyManyThroughSubSubEagerLoadObject::class,
|
||||||
|
'from' => 'ManyManyThroughSubEagerLoadObject',
|
||||||
|
'to' => 'ManyManyThroughSubSubEagerLoadObject',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'ManyManyThroughEagerLoadObjects' => ManyManyThroughEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyThroughSubEagerLoadObjectManyManyThroughSubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
// Removed some of the table name and suffixed _truncated because the table name was too long for MySQL
|
||||||
|
private static $table_name = 'ManyManyThroughSubEagerLoadObjectManyManyThroughSubSub_truncated';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'ManyManyThroughSubEagerLoadObject' => ManyManyThroughSubEagerLoadObject::class,
|
||||||
|
'ManyManyThroughSubSubEagerLoadObject' => ManyManyThroughSubSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class ManyManyThroughSubSubEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'ManyManyThroughSubSubEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'ManyManyThroughSubEagerLoadObjects' => ManyManyThroughSubEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
20
tests/php/ORM/DataListTest/MixedHasManyEagerLoadObject.php
Normal file
20
tests/php/ORM/DataListTest/MixedHasManyEagerLoadObject.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class MixedHasManyEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'MixedHasManyEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
'MixedManyManyEagerLoadObject' => MixedManyManyEagerLoadObject::class,
|
||||||
|
'MixedHasOneEagerLoadObject' => MixedHasOneEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
20
tests/php/ORM/DataListTest/MixedHasOneEagerLoadObject.php
Normal file
20
tests/php/ORM/DataListTest/MixedHasOneEagerLoadObject.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class MixedHasOneEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'MixedHasOneEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_one = [
|
||||||
|
// this is used for a "four levels deep" test
|
||||||
|
'FourthLevel' => MixedHasOneEagerLoadObject::class
|
||||||
|
];
|
||||||
|
}
|
23
tests/php/ORM/DataListTest/MixedManyManyEagerLoadObject.php
Normal file
23
tests/php/ORM/DataListTest/MixedManyManyEagerLoadObject.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\ORM\Tests\DataListTest;
|
||||||
|
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class MixedManyManyEagerLoadObject extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'MixedManyManyEagerLoadObject';
|
||||||
|
|
||||||
|
private static $db = [
|
||||||
|
'Title' => 'Varchar'
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $has_many = [
|
||||||
|
'MixedHasManyEagerLoadObjects' => MixedHasManyEagerLoadObject::class
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $belongs_many_many = [
|
||||||
|
'EagerLoadObjects' => EagerLoadObject::class,
|
||||||
|
];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user