primo commit
This commit is contained in:
74
libraries/fof30/Model/DataModel/Relation/BelongsTo.php
Normal file
74
libraries/fof30/Model/DataModel/Relation/BelongsTo.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Model\DataModel;
|
||||
|
||||
/**
|
||||
* BelongsTo (reverse 1-to-1 or 1-to-many) relation: this model is a child which belongs to the foreign table
|
||||
*
|
||||
* For example, parentModel is Articles and foreignModel is Users. Each article belongs to one user. One user can have
|
||||
* one or more article.
|
||||
*
|
||||
* Example #2: parentModel is Phones and foreignModel is Users. Each phone belongs to one user. One user can have zero
|
||||
* or one phones.
|
||||
*/
|
||||
class BelongsTo extends HasOne
|
||||
{
|
||||
/**
|
||||
* Public constructor. Initialises the relation.
|
||||
*
|
||||
* @param DataModel $parentModel The data model we are attached to
|
||||
* @param string $foreignModelName The name of the foreign key's model in the format
|
||||
* "modelName@com_something"
|
||||
* @param string $localKey The local table key for this relation, default: parentModel's ID field
|
||||
* name
|
||||
* @param string $foreignKey The foreign key for this relation, default: parentModel's ID field name
|
||||
* @param string $pivotTable IGNORED
|
||||
* @param string $pivotLocalKey IGNORED
|
||||
* @param string $pivotForeignKey IGNORED
|
||||
*/
|
||||
public function __construct(DataModel $parentModel, $foreignModelName, $localKey = null, $foreignKey = null, $pivotTable = null, $pivotLocalKey = null, $pivotForeignKey = null)
|
||||
{
|
||||
parent::__construct($parentModel, $foreignModelName, $localKey, $foreignKey, $pivotTable, $pivotLocalKey, $pivotForeignKey);
|
||||
|
||||
if (empty($localKey))
|
||||
{
|
||||
/** @var DataModel $foreignModel */
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
|
||||
$this->localKey = $foreignModel->getIdFieldName();
|
||||
}
|
||||
|
||||
if (empty($foreignKey))
|
||||
{
|
||||
if (!isset($foreignModel))
|
||||
{
|
||||
/** @var DataModel $foreignModel */
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
}
|
||||
|
||||
$this->foreignKey = $foreignModel->getIdFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not supported by the belongsTo relation
|
||||
*
|
||||
* @throws DataModel\Relation\Exception\NewNotSupported when it's not supported
|
||||
*/
|
||||
public function getNew()
|
||||
{
|
||||
throw new DataModel\Relation\Exception\NewNotSupported("getNew() is not supported by the belongsTo relation type");
|
||||
}
|
||||
|
||||
}
|
||||
412
libraries/fof30/Model/DataModel/Relation/BelongsToMany.php
Normal file
412
libraries/fof30/Model/DataModel/Relation/BelongsToMany.php
Normal file
@ -0,0 +1,412 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Model\DataModel;
|
||||
use FOF30\Model\DataModel\Relation;
|
||||
use JDatabaseQuery;
|
||||
|
||||
/**
|
||||
* BelongsToMany (many-to-many) relation: one or more records of this model are related to one or more records in the
|
||||
* foreign model.
|
||||
*
|
||||
* For example, parentModel is Users and foreignModel is Groups. Each user can be assigned to many groups. Each group
|
||||
* can be assigned to many users.
|
||||
*/
|
||||
class BelongsToMany extends Relation
|
||||
{
|
||||
/**
|
||||
* Public constructor. Initialises the relation.
|
||||
*
|
||||
* @param DataModel $parentModel The data model we are attached to
|
||||
* @param string $foreignModelName The name of the foreign key's model in the format
|
||||
* "modelName@com_something"
|
||||
* @param string $localKey The local table key for this relation, default: parentModel's ID field
|
||||
* name
|
||||
* @param string $foreignKey The foreign key for this relation, default: parentModel's ID field name
|
||||
* @param string $pivotTable For many-to-many relations, the pivot (glue) table
|
||||
* @param string $pivotLocalKey For many-to-many relations, the pivot table's column storing the local
|
||||
* key
|
||||
* @param string $pivotForeignKey For many-to-many relations, the pivot table's column storing the foreign
|
||||
* key
|
||||
*
|
||||
* @throws DataModel\Relation\Exception\PivotTableNotFound
|
||||
*/
|
||||
public function __construct(DataModel $parentModel, $foreignModelName, $localKey = null, $foreignKey = null, $pivotTable = null, $pivotLocalKey = null, $pivotForeignKey = null)
|
||||
{
|
||||
parent::__construct($parentModel, $foreignModelName, $localKey, $foreignKey, $pivotTable, $pivotLocalKey, $pivotForeignKey);
|
||||
|
||||
if (empty($localKey))
|
||||
{
|
||||
$this->localKey = $parentModel->getIdFieldName();
|
||||
}
|
||||
|
||||
if (empty($pivotLocalKey))
|
||||
{
|
||||
$this->pivotLocalKey = $this->localKey;
|
||||
}
|
||||
|
||||
if (empty($foreignKey))
|
||||
{
|
||||
/** @var DataModel $foreignModel */
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
|
||||
$this->foreignKey = $foreignModel->getIdFieldName();
|
||||
}
|
||||
|
||||
if (empty($pivotForeignKey))
|
||||
{
|
||||
$this->pivotForeignKey = $this->foreignKey;
|
||||
}
|
||||
|
||||
if (empty($pivotTable))
|
||||
{
|
||||
// Get the local model's name (e.g. "users")
|
||||
$localName = $parentModel->getName();
|
||||
$localName = strtolower($localName);
|
||||
|
||||
// Get the foreign model's name (e.g. "groups")
|
||||
if (!isset($foreignModel))
|
||||
{
|
||||
/** @var DataModel $foreignModel */
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
}
|
||||
|
||||
$foreignName = $foreignModel->getName();
|
||||
$foreignName = strtolower($foreignName);
|
||||
|
||||
// Get the local model's app name
|
||||
$parentModelBareComponent = $parentModel->getContainer()->bareComponentName;
|
||||
$foreignModelBareComponent = $foreignModel->getContainer()->bareComponentName;
|
||||
|
||||
// There are two possibilities for the table name: #__component_local_foreign or #__component_foreign_local.
|
||||
// There are also two possibilities for a component name (local or foreign model's)
|
||||
$db = $parentModel->getDbo();
|
||||
$prefix = $db->getPrefix();
|
||||
|
||||
$tableNames = [
|
||||
'#__' . strtolower($parentModelBareComponent) . '_' . $localName . '_' . $foreignName,
|
||||
'#__' . strtolower($parentModelBareComponent) . '_' . $foreignName . '_' . $localName,
|
||||
'#__' . strtolower($foreignModelBareComponent) . '_' . $localName . '_' . $foreignName,
|
||||
'#__' . strtolower($foreignModelBareComponent) . '_' . $foreignName . '_' . $localName,
|
||||
];
|
||||
|
||||
$allTables = $db->getTableList();
|
||||
|
||||
$this->pivotTable = null;
|
||||
|
||||
foreach ($tableNames as $tableName)
|
||||
{
|
||||
$checkName = $prefix . substr($tableName, 3);
|
||||
|
||||
if (in_array($checkName, $allTables))
|
||||
{
|
||||
$this->pivotTable = $tableName;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->pivotTable))
|
||||
{
|
||||
throw new DataModel\Relation\Exception\PivotTableNotFound("Pivot table for many-to-many relation between '$localName and '$foreignName' not found'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the internal $this->data collection from the contents of the provided collection. This is used by
|
||||
* DataModel to push the eager loaded data into each item's relation.
|
||||
*
|
||||
* @param DataModel\Collection $data The relation data to push into this relation
|
||||
* @param mixed $keyMap Passes around the local to foreign key map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDataFromCollection(DataModel\Collection &$data, $keyMap = null)
|
||||
{
|
||||
$this->data = new DataModel\Collection();
|
||||
|
||||
if (!is_array($keyMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($data))
|
||||
{
|
||||
// Get the local key value
|
||||
$localKeyValue = $this->parentModel->getFieldValue($this->localKey);
|
||||
|
||||
// Make sure this local key exists in the (cached) pivot table
|
||||
if (!isset($keyMap[$localKeyValue]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var DataModel $item */
|
||||
foreach ($data as $key => $item)
|
||||
{
|
||||
// Only accept foreign items whose key is associated in the pivot table with our local key
|
||||
if (in_array($item->getFieldValue($this->foreignKey), $keyMap[$localKeyValue]))
|
||||
{
|
||||
$this->data->add($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the count sub-query for DataModel's has() and whereHas() methods.
|
||||
*
|
||||
* @param string $tableAlias The alias of the local table in the query. Leave blank to use the table's name.
|
||||
*
|
||||
* @return JDatabaseQuery
|
||||
*/
|
||||
public function getCountSubquery($tableAlias = null)
|
||||
{
|
||||
/** @var DataModel $foreignModel */
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
|
||||
$db = $foreignModel->getDbo();
|
||||
|
||||
if (empty($tableAlias))
|
||||
{
|
||||
$tableAlias = $this->parentModel->getTableName();
|
||||
}
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->qn($foreignModel->getTableName()) . ' AS ' . $db->qn('reltbl'))
|
||||
->innerJoin(
|
||||
$db->qn($this->pivotTable) . ' AS ' . $db->qn('pivotTable') . ' ON('
|
||||
. $db->qn('pivotTable') . '.' . $db->qn($this->pivotForeignKey) . ' = '
|
||||
. $db->qn('reltbl') . '.' . $db->qn($foreignModel->getFieldAlias($this->foreignKey))
|
||||
. ')'
|
||||
)
|
||||
->where(
|
||||
$db->qn('pivotTable') . '.' . $db->qn($this->pivotLocalKey) . ' ='
|
||||
. $db->qn($tableAlias) . '.'
|
||||
. $db->qn($this->parentModel->getFieldAlias($this->localKey))
|
||||
);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all related items. For many-to-many relations there are two things we have to do:
|
||||
* 1. Save all related items; and
|
||||
* 2. Overwrite the pivot table data with the new associations
|
||||
*/
|
||||
public function saveAll()
|
||||
{
|
||||
// Save all related items
|
||||
parent::saveAll();
|
||||
|
||||
$this->saveRelations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the pivot table data with the new associations
|
||||
*/
|
||||
public function saveRelations()
|
||||
{
|
||||
// Get all the new keys
|
||||
$newKeys = [];
|
||||
|
||||
if ($this->data instanceof DataModel\Collection)
|
||||
{
|
||||
foreach ($this->data as $item)
|
||||
{
|
||||
if ($item instanceof DataModel)
|
||||
{
|
||||
$newKeys[] = $item->getId();
|
||||
}
|
||||
elseif (!is_object($item))
|
||||
{
|
||||
$newKeys[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$newKeys = array_unique($newKeys);
|
||||
|
||||
$db = $this->parentModel->getDbo();
|
||||
$localKeyValue = $this->parentModel->getFieldValue($this->localKey);
|
||||
|
||||
// Kill all existing relations in the pivot table
|
||||
$query = $db->getQuery(true)
|
||||
->delete($db->qn($this->pivotTable))
|
||||
->where($db->qn($this->pivotLocalKey) . ' = ' . $db->q($localKeyValue));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Write the new relations to the database
|
||||
$protoQuery = $db->getQuery(true)
|
||||
->insert($db->qn($this->pivotTable))
|
||||
->columns([$db->qn($this->pivotLocalKey), $db->qn($this->pivotForeignKey)]);
|
||||
|
||||
$i = 0;
|
||||
$query = null;
|
||||
|
||||
foreach ($newKeys as $key)
|
||||
{
|
||||
$i++;
|
||||
|
||||
if (is_null($query))
|
||||
{
|
||||
$query = clone $protoQuery;
|
||||
}
|
||||
|
||||
$query->values($db->q($localKeyValue) . ', ' . $db->q($key));
|
||||
|
||||
if (($i % 50) == 0)
|
||||
{
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
$query = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($query))
|
||||
{
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not supported by the belongsTo relation
|
||||
*
|
||||
* @throws DataModel\Relation\Exception\NewNotSupported when it's not supported
|
||||
*/
|
||||
public function getNew()
|
||||
{
|
||||
throw new DataModel\Relation\Exception\NewNotSupported("getNew() is not supported for many-to-may relations. Please add/remove items from the relation data and use push() to effect changes.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the relation filters to the foreign model when getData is called
|
||||
*
|
||||
* @param DataModel $foreignModel The foreign model you're operating on
|
||||
* @param DataModel\Collection $dataCollection If it's an eager loaded relation, the collection of loaded
|
||||
* parent records
|
||||
*
|
||||
* @return boolean Return false to force an empty data collection
|
||||
*/
|
||||
protected function filterForeignModel(DataModel $foreignModel, DataModel\Collection $dataCollection = null)
|
||||
{
|
||||
$db = $this->parentModel->getDbo();
|
||||
|
||||
// Decide how to proceed, based on eager or lazy loading
|
||||
if (is_object($dataCollection))
|
||||
{
|
||||
// Eager loaded relation
|
||||
if (!empty($dataCollection))
|
||||
{
|
||||
// Get a list of local keys from the collection
|
||||
$values = [];
|
||||
|
||||
/** @var $item DataModel */
|
||||
foreach ($dataCollection as $item)
|
||||
{
|
||||
$v = $item->getFieldValue($this->localKey, null);
|
||||
|
||||
if (!is_null($v))
|
||||
{
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep only unique values
|
||||
$values = array_unique($values);
|
||||
$values = array_map(function ($x) use (&$db) {
|
||||
return $db->q($x);
|
||||
}, $values);
|
||||
|
||||
// Get the foreign keys from the glue table
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->qn($this->pivotLocalKey), $db->qn($this->pivotForeignKey)])
|
||||
->from($db->qn($this->pivotTable))
|
||||
->where($db->qn($this->pivotLocalKey) . ' IN(' . implode(',', $values) . ')');
|
||||
$db->setQuery($query);
|
||||
$foreignKeysUnmapped = $db->loadRowList();
|
||||
|
||||
$this->foreignKeyMap = [];
|
||||
$foreignKeys = [];
|
||||
|
||||
foreach ($foreignKeysUnmapped as $unmapped)
|
||||
{
|
||||
$local = $unmapped[0];
|
||||
$foreign = $unmapped[1];
|
||||
|
||||
if (!isset($this->foreignKeyMap[$local]))
|
||||
{
|
||||
$this->foreignKeyMap[$local] = [];
|
||||
}
|
||||
|
||||
$this->foreignKeyMap[$local][] = $foreign;
|
||||
|
||||
$foreignKeys[] = $foreign;
|
||||
}
|
||||
|
||||
// Keep only unique values. However, the array keys are all screwed up. See below.
|
||||
$foreignKeys = array_unique($foreignKeys);
|
||||
|
||||
// This looks stupid, but it's required to reset the array keys. Without it where() below fails.
|
||||
$foreignKeys = array_merge($foreignKeys);
|
||||
|
||||
// Apply the filter
|
||||
if (!empty($foreignKeys))
|
||||
{
|
||||
$foreignModel->where($this->foreignKey, 'in', $foreignKeys);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Lazy loaded relation; get the single local key
|
||||
$localKey = $this->parentModel->getFieldValue($this->localKey, null);
|
||||
|
||||
if (is_null($localKey) || ($localKey === ''))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->qn($this->pivotForeignKey))
|
||||
->from($db->qn($this->pivotTable))
|
||||
->where($db->qn($this->pivotLocalKey) . ' = ' . $db->q($localKey));
|
||||
$db->setQuery($query);
|
||||
$foreignKeys = $db->loadColumn();
|
||||
|
||||
$this->foreignKeyMap[$localKey] = $foreignKeys;
|
||||
|
||||
// If there are no foreign keys (no foreign items assigned to our item) we return false which then causes
|
||||
// the relation to return null, marking the lack of data.
|
||||
if (empty($foreignKeys))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$foreignModel->where($this->foreignKey, 'in', $this->foreignKeyMap[$localKey]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ForeignModelNotFound extends Exception
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NewNotSupported extends Exception
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class PivotTableNotFound extends Exception
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class RelationNotFound extends Exception
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class RelationTypeNotFound extends Exception
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SaveNotSupported extends Exception
|
||||
{
|
||||
}
|
||||
174
libraries/fof30/Model/DataModel/Relation/HasMany.php
Normal file
174
libraries/fof30/Model/DataModel/Relation/HasMany.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Model\DataModel;
|
||||
use FOF30\Model\DataModel\Relation;
|
||||
use JDatabaseQuery;
|
||||
|
||||
/**
|
||||
* HasMany (1-to-many) relation: this model is a parent which has zero or more children in the foreign table
|
||||
*
|
||||
* For example, parentModel is Users and foreignModel is Articles. Each user has zero or more articles.
|
||||
*/
|
||||
class HasMany extends Relation
|
||||
{
|
||||
/**
|
||||
* Public constructor. Initialises the relation.
|
||||
*
|
||||
* @param DataModel $parentModel The data model we are attached to
|
||||
* @param string $foreignModelName The name of the foreign key's model in the format
|
||||
* "modelName@com_something"
|
||||
* @param string $localKey The local table key for this relation, default: parentModel's ID field
|
||||
* name
|
||||
* @param string $foreignKey The foreign key for this relation, default: parentModel's ID field name
|
||||
* @param string $pivotTable IGNORED
|
||||
* @param string $pivotLocalKey IGNORED
|
||||
* @param string $pivotForeignKey IGNORED
|
||||
*/
|
||||
public function __construct(DataModel $parentModel, $foreignModelName, $localKey = null, $foreignKey = null, $pivotTable = null, $pivotLocalKey = null, $pivotForeignKey = null)
|
||||
{
|
||||
parent::__construct($parentModel, $foreignModelName, $localKey, $foreignKey, $pivotTable, $pivotLocalKey, $pivotForeignKey);
|
||||
|
||||
if (empty($this->localKey))
|
||||
{
|
||||
$this->localKey = $parentModel->getIdFieldName();
|
||||
}
|
||||
|
||||
if (empty($this->foreignKey))
|
||||
{
|
||||
$this->foreignKey = $this->localKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the count sub-query for DataModel's has() and whereHas() methods.
|
||||
*
|
||||
* @param string $tableAlias The alias of the local table in the query. Leave blank to use the table's name.
|
||||
*
|
||||
* @return JDatabaseQuery
|
||||
*/
|
||||
public function getCountSubquery($tableAlias = null)
|
||||
{
|
||||
// Get a model instance
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
|
||||
$db = $foreignModel->getDbo();
|
||||
|
||||
if (empty($tableAlias))
|
||||
{
|
||||
$tableAlias = $this->parentModel->getTableName();
|
||||
}
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from($db->qn($foreignModel->getTableName(), 'reltbl'))
|
||||
->where($db->qn('reltbl') . '.' . $db->qn($foreignModel->getFieldAlias($this->foreignKey)) . ' = '
|
||||
. $db->qn($tableAlias) . '.'
|
||||
. $db->qn($this->parentModel->getFieldAlias($this->localKey)));
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new item of the foreignModel type, pre-initialised to fulfil this relation
|
||||
*
|
||||
* @return DataModel
|
||||
*
|
||||
* @throws DataModel\Relation\Exception\NewNotSupported when it's not supported
|
||||
*/
|
||||
public function getNew()
|
||||
{
|
||||
// Get a model instance
|
||||
$foreignModel = $this->getForeignModel();
|
||||
$foreignModel->setIgnoreRequest(true);
|
||||
|
||||
// Prime the model
|
||||
$foreignModel->setFieldValue($this->foreignKey, $this->parentModel->getFieldValue($this->localKey));
|
||||
|
||||
// Make sure we do have a data list
|
||||
if (!($this->data instanceof DataModel\Collection))
|
||||
{
|
||||
$this->getData();
|
||||
}
|
||||
|
||||
// Add the model to the data list
|
||||
$this->data->add($foreignModel);
|
||||
|
||||
return $this->data->last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the relation filters to the foreign model when getData is called
|
||||
*
|
||||
* @param DataModel $foreignModel The foreign model you're operating on
|
||||
* @param DataModel\Collection $dataCollection If it's an eager loaded relation, the collection of loaded
|
||||
* parent records
|
||||
*
|
||||
* @return boolean Return false to force an empty data collection
|
||||
*/
|
||||
protected function filterForeignModel(DataModel $foreignModel, DataModel\Collection $dataCollection = null)
|
||||
{
|
||||
// Decide how to proceed, based on eager or lazy loading
|
||||
if (is_object($dataCollection))
|
||||
{
|
||||
// Eager loaded relation
|
||||
if (!empty($dataCollection))
|
||||
{
|
||||
// Get a list of local keys from the collection
|
||||
$values = [];
|
||||
|
||||
/** @var $item DataModel */
|
||||
foreach ($dataCollection as $item)
|
||||
{
|
||||
$v = $item->getFieldValue($this->localKey, null);
|
||||
|
||||
if (!is_null($v))
|
||||
{
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep only unique values. This double step is required to re-index the array and avoid issues with
|
||||
// Joomla Registry class. See issue #681
|
||||
$values = array_values(array_unique($values));
|
||||
|
||||
// Apply the filter
|
||||
if (!empty($values))
|
||||
{
|
||||
$foreignModel->where($this->foreignKey, 'in', $values);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Lazy loaded relation; get the single local key
|
||||
$localKey = $this->parentModel->getFieldValue($this->localKey, null);
|
||||
|
||||
if (is_null($localKey) || ($localKey === ''))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$foreignModel->where($this->foreignKey, '==', $localKey);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
46
libraries/fof30/Model/DataModel/Relation/HasOne.php
Normal file
46
libraries/fof30/Model/DataModel/Relation/HasOne.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\Model\DataModel\Relation;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Model\DataModel;
|
||||
use FOF30\Model\DataModel\Collection;
|
||||
|
||||
/**
|
||||
* HasOne (straight 1-to-1) relation: this model is a parent which has exactly one child in the foreign table
|
||||
*
|
||||
* For example, parentModel is Users and foreignModel is Phones. Each uses has exactly one Phone.
|
||||
*/
|
||||
class HasOne extends HasMany
|
||||
{
|
||||
/**
|
||||
* Get the relation data.
|
||||
*
|
||||
* If you want to apply additional filtering to the foreign model, use the $callback. It can be any function,
|
||||
* static method, public method or closure with an interface of function(DataModel $foreignModel). You are not
|
||||
* supposed to return anything, just modify $foreignModel's state directly. For example, you may want to do:
|
||||
* $foreignModel->setState('foo', 'bar')
|
||||
*
|
||||
* @param callable $callback The callback to run on the remote model.
|
||||
* @param Collection $dataCollection
|
||||
*
|
||||
* @return Collection|DataModel
|
||||
*/
|
||||
public function getData($callback = null, Collection $dataCollection = null)
|
||||
{
|
||||
if (is_null($dataCollection))
|
||||
{
|
||||
return parent::getData($callback, $dataCollection)->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::getData($callback, $dataCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user