init
This commit is contained in:
878
mysyde/common/traits/genericCollectionTrait.php
Normal file
878
mysyde/common/traits/genericCollectionTrait.php
Normal file
@@ -0,0 +1,878 @@
|
||||
<?php
|
||||
namespace DynCom\mysyde\common\traits;
|
||||
use DynCom\mysyde\common\interfaces\CriteriaHelperInterface;
|
||||
use DynCom\mysyde\common\interfaces\GenericCollectionInterface;
|
||||
use DynCom\mysyde\common\interfaces\ModelDBConfigInterface;
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Micha
|
||||
* Date: 14.01.2015
|
||||
* Time: 17:38
|
||||
* @TODO: Rewrite from getByCriteria to end for SplObjectStorage
|
||||
*/
|
||||
trait genericCollectionTrait
|
||||
{
|
||||
|
||||
protected $allowedComparisonOperations = array('IS NULL', 'IS NOT NULL', '=', '!=', '<', '>', '>=', '<=', 'IN', 'LIKE');
|
||||
protected $criteriaValidationService;
|
||||
/**
|
||||
* @var ModelDBConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
protected $elements;
|
||||
protected $hashObjectMap = [];
|
||||
protected $hashesByID = [];
|
||||
protected $hashesByAltPrimary = [];
|
||||
protected $hashList = [];
|
||||
protected $fields;
|
||||
protected $altPrimary;
|
||||
protected $entryClassName;
|
||||
protected $currIndex = '';
|
||||
protected $currIndexPos = null;
|
||||
|
||||
/**
|
||||
* @param ModelDBConfigInterface $config
|
||||
* @param CriteriaHelperInterface $criteriaValidationService
|
||||
*/
|
||||
public function __construct(ModelDBConfigInterface $config, CriteriaHelperInterface $criteriaValidationService)
|
||||
{
|
||||
$this->elements = new \SplObjectStorage();
|
||||
$this->config = $config;
|
||||
$this->criteriaValidationService = $criteriaValidationService;
|
||||
$this->entryClassName = $config->getModelClassName();
|
||||
$this->altPrimary = $config->getAltPrimary();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseTableName()
|
||||
{
|
||||
return $this->config->getBaseTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Array of fields (optionally with DB-Type) of the class for entries in the collection
|
||||
*/
|
||||
public function getFieldsArray()
|
||||
{
|
||||
return $this->config->getMappedFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Implements Countable interface
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
//return count($this->elements);
|
||||
return count($this->hashObjectMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \IteratorIterator
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \IteratorIterator(new \ArrayIterator($this->hashObjectMap));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instance An instance of the collection-entry class
|
||||
* @param bool $idCheck Flag whether comparisons should be id-only, default FALSE
|
||||
*
|
||||
* @return bool Success or failure
|
||||
*/
|
||||
public function remove($instance, $idCheck = false)
|
||||
{
|
||||
return $this->_remove($instance, $idCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instance An instance of the collection-entry class
|
||||
* @param bool $idCheck Flag whether comparisons should be id-only, default FALSE
|
||||
*
|
||||
* @return bool Success or failure
|
||||
*/
|
||||
protected function _remove($instance, $idCheck = false)
|
||||
{
|
||||
$info = $this->getIndexInfo($instance);
|
||||
if (
|
||||
($idCheck && (empty($info['id']) || !array_key_exists((string)$info['id'], $this->hashesByID)))
|
||||
|| (!array_key_exists($info['hash'], $this->hashObjectMap))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
$this->removeInstance($instance);
|
||||
return true;
|
||||
|
||||
if (!$idCheck && $this->elements->contains($instance)) {
|
||||
$this->elements->detach($instance);
|
||||
return true;
|
||||
}
|
||||
$c = $this->elements;
|
||||
$c->rewind();
|
||||
$found = false;
|
||||
while ($c->valid() && !$found) {
|
||||
$object = $c->current();
|
||||
$currID = $object->id;
|
||||
if ($instance->id === $currID) {
|
||||
$found = true;
|
||||
$foundEntity = $object;
|
||||
}
|
||||
$c->next();
|
||||
}
|
||||
$c->rewind();
|
||||
if ($found) {
|
||||
$this->elements->detach($foundEntity);
|
||||
return true;
|
||||
}
|
||||
$c->rewind();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array The entire collection as array
|
||||
*/
|
||||
public function getAllAsArray()
|
||||
{
|
||||
return array_values($this->hashObjectMap);
|
||||
$newArray = array();
|
||||
$this->elements->rewind();
|
||||
while ($this->elements->valid()) {
|
||||
$newArray[] = $this->elements->current();
|
||||
$this->elements->next();
|
||||
}
|
||||
$this->elements->rewind();
|
||||
return $newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array Array containing instances of the class for entries in the collection
|
||||
*
|
||||
* @param bool $idCheck
|
||||
* @return bool Success or failure
|
||||
*/
|
||||
protected function _resetEntriesFromArray(array $array, $idCheck = false)
|
||||
{
|
||||
$this->hashesByID = [];
|
||||
$this->hashesByAltPrimary = [];
|
||||
$this->hashObjectMap = [];
|
||||
$className = $this->getEntryClassName();
|
||||
//$newCollection = new SplObjectStorage();
|
||||
foreach ($array as $instance) {
|
||||
if ($instance instanceof $className) {
|
||||
//$newCollection->attach($instance);
|
||||
$this->add($instance, $idCheck);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//$this->elements = $newCollection;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEntryClassName()
|
||||
{
|
||||
return $this->entryClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return mixed An instance of the collection-entry class (or Null-Object)
|
||||
*/
|
||||
public function getByID($id)
|
||||
{
|
||||
return $this->_getByID($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return mixed An instance of the collection-entry class
|
||||
*/
|
||||
protected function _getByID($id)
|
||||
{
|
||||
$obj = $this->getNullObject();
|
||||
if (!$this->hasInstanceForID($id)) {
|
||||
return $obj;
|
||||
}
|
||||
return $this->getInstanceByID($id);
|
||||
foreach ($this->elements as $instance) {
|
||||
if (isset($instance->id) && ($instance->id == (int)$id)) {
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
return $this->getNullObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed Empty (unset) instance of the class for entries in the collection
|
||||
* !MUST! be overriden in classes with different constructor
|
||||
*/
|
||||
public function getNullObject()
|
||||
{
|
||||
return new $this->entryClassName($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $uniqueKeyArray An array specifying an alternative primary key, of the form:
|
||||
* array('keyField1Name'=>'keyField1Value','keyField2Name'=>'keyField2Value'...);
|
||||
*
|
||||
* @return mixed An instance of the collection-entry class
|
||||
*/
|
||||
public function getByAltPrimary(array $uniqueKeyArray)
|
||||
{
|
||||
return $this->getInstanceByAltPrimary($uniqueKeyArray);
|
||||
return $this->_getByAltPrimary($uniqueKeyArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $uniqueKeyArray
|
||||
* @return mixed
|
||||
* @throws \DomainException
|
||||
*/
|
||||
protected function _getByAltPrimary(array $uniqueKeyArray)
|
||||
{
|
||||
$altPrimaryValues = array();
|
||||
foreach ($this->altPrimary as $name) {
|
||||
if (isset($uniqueKeyArray[$name])) {
|
||||
$altPrimaryValues[$name] = $uniqueKeyArray[$name];
|
||||
} else {
|
||||
throw new \DomainException('Paramter enthält keinen Wert für Schlüsselfeld \'' . $name . '\'');
|
||||
return $this->getNullObject();
|
||||
}
|
||||
}
|
||||
|
||||
$all = $this->getAllAsArray();
|
||||
foreach ($all as $instance) {
|
||||
$instanceAltPrimary = array();
|
||||
foreach ($this->altPrimary as $key => $value) {
|
||||
$instanceAltPrimary[$key] = $instance->$key;
|
||||
}
|
||||
if ($instanceAltPrimary == $uniqueKeyArray) {
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
return $this->getNullObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $criteria Filtering-criteria as array in disjunctive normal form:
|
||||
* array(
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue')
|
||||
* ...
|
||||
* ),
|
||||
* **OR**
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue')
|
||||
* ...
|
||||
* )
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* @return GenericCollectionInterface $collection Subset of the current collection as instance of own concrete
|
||||
* collection class
|
||||
*/
|
||||
public function getByCriteria(array $criteria)
|
||||
{
|
||||
return $this->_getByCriteria($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $criteria Filtering-criteria as array in disjunctive normal form:
|
||||
* array(
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue')
|
||||
* ...
|
||||
* ),
|
||||
* **OR**
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue')
|
||||
* ...
|
||||
* )
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* @return GenericCollectionInterface $collection Subset of the current collection as instance of own concrete
|
||||
* collection class
|
||||
*/
|
||||
protected function _getByCriteria(array $criteria)
|
||||
{
|
||||
$resultCollection = new static($this->config, $this->criteriaValidationService);
|
||||
|
||||
if (!$this->criteriaValidationService->validateCriteria($this->config, $criteria)) {
|
||||
return $resultCollection;
|
||||
}
|
||||
|
||||
//foreach ($this->elements as $instance) {
|
||||
foreach ($this->hashObjectMap as $instance) {
|
||||
foreach ($criteria as $disjunctCriteria) {
|
||||
$isValidDisjunct = true;
|
||||
foreach ($disjunctCriteria as $conjunctCriterion) {
|
||||
$fieldName = $conjunctCriterion[0];
|
||||
$comparator = $conjunctCriterion[1];
|
||||
$compareValue = isset($conjunctCriterion[2]) ? $conjunctCriterion[2] : '';
|
||||
|
||||
if ($comparator === 'IS NULL') {
|
||||
if (!(is_null($instance->$fieldName))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === 'IS NOT NULL') {
|
||||
if (is_null($instance->$fieldName)) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '=') {
|
||||
if (!(isset($instance->$fieldName) && $instance->$fieldName == $compareValue)) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '!=') {
|
||||
if (!($instance->$fieldName != $compareValue)) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '>') {
|
||||
if (!(isset($instance->$fieldName) && ($instance->$fieldName > $compareValue))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '<') {
|
||||
if (!(isset($instance->$fieldName) && ($instance->$fieldName < $compareValue))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '<=') {
|
||||
if (!(isset($instance->$fieldName) && !($instance->$fieldName <= $compareValue))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === '>=') {
|
||||
if (!(isset($instance->$fieldName) || ($instance->$fieldName >= $compareValue))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === 'IN') {
|
||||
if (!(in_array($instance->$fieldName, $compareValue))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
} elseif ($comparator === 'LIKE') {
|
||||
//SQL-Wildcard durch fnmatch-Wildcard ersetzen
|
||||
$compareValue = str_replace('%', '*', $compareValue);
|
||||
if (!(fnmatch($compareValue, $instance->$fieldName))) {
|
||||
$isValidDisjunct = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($isValidDisjunct) {
|
||||
$resultCollection->add($instance, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $resultCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instance An instance of the collection-entry class
|
||||
* @param bool $idCheck Flag whether comparisons should be id-only, default FALSE
|
||||
*
|
||||
* @return bool Success or failure
|
||||
*/
|
||||
public function add($instance, $idCheck = false)
|
||||
{
|
||||
return $this->_add($instance, $idCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $instance An instance of the collection-entry class
|
||||
* @param bool $idCheck Flag whether comparisons should be id-only, default FALSE
|
||||
*
|
||||
* @return bool Success or failure
|
||||
* @throws \DomainException
|
||||
*/
|
||||
protected function _add($instance, $idCheck = false)
|
||||
{
|
||||
$info = $this->getIndexInfo($instance);
|
||||
|
||||
if ((!$idCheck && array_key_exists($info['hash'],$this->hashObjectMap)) || $this->hasInstanceForID($info['id'])) {
|
||||
$this->updateByID($instance);
|
||||
} else {
|
||||
$this->addNewInstance($instance);
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
$className = $this->getEntryClassName();
|
||||
$id = null;
|
||||
$hash = $this->elements->getHash($instance);
|
||||
if (!($instance instanceof $className)) {
|
||||
throw new \DomainException(
|
||||
'Parameter \'instance\' is not an instance of class \'' . $className . '\', instead is ' . get_class(
|
||||
$instance
|
||||
)
|
||||
);
|
||||
}
|
||||
if (property_exists($instance, 'id')) {
|
||||
$idRefl = new \ReflectionProperty($instance, 'id');
|
||||
$idRefl->setAccessible(true);
|
||||
$id = $idRefl->getValue($instance);
|
||||
}
|
||||
if (!$idCheck) {
|
||||
if (!($this->elements->offsetExists($instance))) {
|
||||
$this->elements->attach($instance);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (count($this->elements) > 0) {
|
||||
$this->elements->rewind();
|
||||
|
||||
if (!(property_exists($this->config->getModelClassName(), 'id') && isset($instance->id))) {
|
||||
throw new \DomainException(
|
||||
'idCheck is Set but either given instance or collection content doesn\'t have id-field'
|
||||
);
|
||||
}
|
||||
$c = $this->elements;
|
||||
$c->rewind();
|
||||
$found = false;
|
||||
while ($c->valid() && !$found) {
|
||||
$object = $c->current();
|
||||
$currID = $object->id;
|
||||
if ($instance->id === $currID) {
|
||||
$found = true;
|
||||
$foundEntity = $object;
|
||||
}
|
||||
$c->next();
|
||||
}
|
||||
$c->rewind();
|
||||
if ($found) {
|
||||
$this->elements->detach($foundEntity);
|
||||
$this->elements->attach($instance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->elements->attach($instance);
|
||||
$this->elements->rewind();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $criteria Filtering-criteria as array in disjunctive normal form:
|
||||
* array(
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* ...
|
||||
* ),
|
||||
* **OR**
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* ...
|
||||
* ),
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* @return array $collection Subset of the current collection as instance of own concrete
|
||||
* collection class
|
||||
*/
|
||||
public function getByCriteriaAsArray(array $criteria)
|
||||
{
|
||||
return $this->_getByCriteriaAsArray($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $criteria Filtering-criteria as array in disjunctive normal form:
|
||||
* array(
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* ...
|
||||
* ),
|
||||
* **OR**
|
||||
* array(
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* **AND**
|
||||
* array('fieldName','comparator','fieldValue'),
|
||||
* ...
|
||||
* ),
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* @return array $collection Subset of the current collection as instance of own concrete
|
||||
* collection class
|
||||
*/
|
||||
protected function _getByCriteriaAsArray(array $criteria)
|
||||
{
|
||||
return $this->_getByCriteria($criteria)->getAllAsArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function getEmptyCollection()
|
||||
{
|
||||
return new static($this->config, $this->criteriaValidationService);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr
|
||||
*
|
||||
* @return genericCollectionTrait
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function mapArrayToNewCollection(array $arr)
|
||||
{
|
||||
$newCollection = $this->getEmptyCollection();
|
||||
foreach ($arr as $instanceRow) {
|
||||
$newInstance = $this->getNullObject();
|
||||
if (!$newInstance->isArrayPartiallyMappable($instanceRow)) {
|
||||
throw new \DomainException(
|
||||
'At least one entry in the array cannot be mapped to an object of the given instance.'
|
||||
);
|
||||
}
|
||||
$newInstance->mapArray($instanceRow);
|
||||
$newCollection->add($newInstance, true);
|
||||
}
|
||||
return $newCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getFieldData(array $fields)
|
||||
{
|
||||
$validFieldsArr = [];
|
||||
foreach ($fields as $index => $fieldName) {
|
||||
if (!is_string($fieldName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Only strings are allowed as fieldsNames. Array-index $index is not a string."
|
||||
);
|
||||
}
|
||||
if ($this->config->fieldExists($fieldName)) $validFieldsArr[] = $fieldName;
|
||||
}
|
||||
$dataArr = [];
|
||||
$i = 0;
|
||||
//for ($this->elements->rewind(); $this->elements->valid(); $this->elements->next()) {
|
||||
// $el = $this->elements->current();
|
||||
foreach ($this->hashObjectMap as $el) {
|
||||
foreach ($validFieldsArr as $validFieldName) {
|
||||
$dataArr[$i][$validFieldName] = $el->{$validFieldName};
|
||||
}
|
||||
++$i;
|
||||
}
|
||||
return $dataArr;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if($this->count() > 0) {
|
||||
$this->currIndex = array_keys($this->hashObjectMap)[0];
|
||||
$this->currIndexPos = 0;
|
||||
} else {
|
||||
$this->currIndex = '';
|
||||
$this->currIndexPos = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return array_key_exists($this->currIndex,$this->hashObjectMap) && !empty($this->hashObjectMap[$this->currIndex]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->hashObjectMap[$this->currIndex];
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
if ($this->count() > 0) {
|
||||
$this->currIndexPos++;
|
||||
if ($this->currIndexPos > (count($this->hashList) - 1)) {
|
||||
$this->currIndexPos = null;
|
||||
$this->currIndex = '';
|
||||
} else {
|
||||
$this->currIndex = $this->hashList[$this->currIndexPos];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|object
|
||||
*/
|
||||
public function getFirst()
|
||||
{
|
||||
$this->rewind();
|
||||
if (!empty($this->hashObjectMap)) {
|
||||
return $this->hashObjectMap[$this->hashList[0]];
|
||||
}
|
||||
return $this->getNullObject();
|
||||
$this->elements->rewind();
|
||||
return $this->elements->valid() ? $this->elements->current() : $this->getNullObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|object
|
||||
*/
|
||||
public function getNext()
|
||||
{
|
||||
$this->next();
|
||||
return $this->valid() ? $this->current() : $this->getNullObject();
|
||||
$this->elements->next();
|
||||
return $this->elements->valid() ? $this->elements->current() : $this->getNullObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCurrValid()
|
||||
{
|
||||
return $this->valid();
|
||||
return $this->elements->valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $instance
|
||||
*/
|
||||
private function addNewInstance($instance)
|
||||
{
|
||||
$initEmpty = (0 === count($this->hashObjectMap));
|
||||
$info = $this->getIndexInfo($instance);
|
||||
if (!isset($info['id']) || $info['id'] === 0 || $info['id'] === '0') {
|
||||
throw new \InvalidArgumentException('Cannot update by id if instance has no non-null, non-zero id-value');
|
||||
}
|
||||
if (array_key_exists((string)$info['id'], $this->hashesByID)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Cannot add. Instance with id ' . $info['id'] . ' already exists in collection.'
|
||||
);
|
||||
}
|
||||
$hash = (string)$info['hash'];
|
||||
$hashedAltPrimary = (string)$info['hashed_alt_primary'];
|
||||
$this->hashObjectMap[$hash] = $instance;
|
||||
$this->hashesByID[(string)$info['id']] = $info['hash'];
|
||||
if ($info['hashed_alt_primary'] !== '') {
|
||||
$this->hashesByAltPrimary[$hashedAltPrimary] = $info['hash'];
|
||||
}
|
||||
$this->hashList[] = $info['hash'];
|
||||
if ($initEmpty) {
|
||||
$this->currIndexPos = 0;
|
||||
$this->currIndex = $info['hash'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $instance
|
||||
*/
|
||||
private function updateByID($instance)
|
||||
{
|
||||
$info = $this->getIndexInfo($instance);
|
||||
if (!isset($info['id']) || $info['id'] === 0 || $info['id'] === '0') {
|
||||
throw new \InvalidArgumentException('Cannot update by id if instance has no non-null, non-zero id-value');
|
||||
}
|
||||
if (!array_key_exists((string)$info['id'], $this->hashesByID)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Cannot update by id. No instance with id ' . $info['id'] . ' in collection.'
|
||||
);
|
||||
}
|
||||
$oldHash = $this->hashesByID[(string)$info['id']];
|
||||
$newHash = (string)$info['hash'];
|
||||
$hashedAltPrimary = (string)$info['hashed_alt_primary'];
|
||||
if($oldHash !== $newHash) {
|
||||
$pos = array_search($oldHash,$this->hashList,true);
|
||||
$this->hashList[$pos] = $newHash;
|
||||
if ($pos === $this->currIndexPos) {
|
||||
$this->currIndex = $newHash;
|
||||
}
|
||||
unset($this->hashObjectMap[$oldHash]);
|
||||
}
|
||||
$this->hashObjectMap[$newHash] = $instance;
|
||||
$this->hashesByID[(string)$info['id']] = $info['hash'];
|
||||
if ($hashedAltPrimary !== '') {
|
||||
$this->hashesByAltPrimary[$hashedAltPrimary] = $info['hash'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*/
|
||||
private function removeByID($id)
|
||||
{
|
||||
if (!array_key_exists((string)$id, $this->hashesByID)) {
|
||||
throw new \InvalidArgumentException('Cannot remove by id. No instance with id ' . $id . ' in collection.');
|
||||
}
|
||||
$instance = $this->hashObjectMap[$this->hashesByID[$id]];
|
||||
$this->removeInstance($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $altPrimary
|
||||
*/
|
||||
private function removeByAltPrimary(array $altPrimary)
|
||||
{
|
||||
if (!$this->hasInstanceForAltPrimary($altPrimary)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Cannot remove instance. No instance with given alt_primary in collection.'
|
||||
);
|
||||
}
|
||||
$instance = $this->getInstanceByAltPrimary($altPrimary);
|
||||
$this->removeInstance($instance);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $instance
|
||||
*/
|
||||
private function removeInstance($instance)
|
||||
{
|
||||
$info = $this->getIndexInfo($instance);
|
||||
unset($this->hashObjectMap[(string)$info['hash']], $this->hashesByID[(string)$info['id']], $this->hashesByAltPrimary[(string)$info['hashed_alt_primary']]);
|
||||
$hashListPos = array_search((string)$info['hash'],$this->hashList,true);
|
||||
unset($this->hashList[$hashListPos]);
|
||||
$this->hashList = array_values($this->hashList);
|
||||
if ($this->currIndexPos >= $hashListPos) {
|
||||
$this->currIndexPos--;
|
||||
if ($this->currIndexPos < 0) {
|
||||
$this->currIndexPos = 0;
|
||||
}
|
||||
}
|
||||
if (array_key_exists($this->currIndexPos,$this->hashList) && !empty($this->hashList[$this->currIndexPos])) {
|
||||
$this->currIndex = $this->hashList[$this->currIndexPos];
|
||||
} else {
|
||||
$this->currIndex = '';
|
||||
$this->currIndexPos = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
private function hasInstanceForID($id)
|
||||
{
|
||||
return array_key_exists((string)$id, $this->hashesByID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $altPrimary
|
||||
* @return bool
|
||||
*/
|
||||
private function hasInstanceForAltPrimary(array $altPrimary)
|
||||
{
|
||||
$altPrimaryHash = $this->hashAltPrimary($altPrimary);
|
||||
return array_key_exists($altPrimaryHash, $this->hashesByAltPrimary);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $instance
|
||||
* @return bool
|
||||
*/
|
||||
private function hasInstance($instance)
|
||||
{
|
||||
$info = $this->getIndexInfo($instance);
|
||||
return array_key_exists($info['hash'], $this->hashObjectMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
private function getInstanceByID($id)
|
||||
{
|
||||
if (!$this->hasInstanceForID($id)) {
|
||||
throw new \InvalidArgumentException('Cannot get Instance. No instance with id ' . $id . ' in collection.');
|
||||
}
|
||||
return $this->hashObjectMap[$this->hashesByID[(string)$id]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $altPrimary
|
||||
* @return mixed
|
||||
*/
|
||||
private function getInstanceByAltPrimary(array $altPrimary)
|
||||
{
|
||||
if (!$this->hasInstanceForAltPrimary($altPrimary)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Cannot get Instance. No instance with given alt_primary in collection.'
|
||||
);
|
||||
}
|
||||
$hashedAltPrimary = $this->hashAltPrimary($altPrimary);
|
||||
return $this->hashObjectMap[$this->hashesByAltPrimary[$hashedAltPrimary]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $instance
|
||||
* @return array
|
||||
*/
|
||||
private function getIndexInfo($instance)
|
||||
{
|
||||
$hash = spl_object_hash($instance);
|
||||
$id = null;
|
||||
$altPrimary = [];
|
||||
$hashedAltPrimary = '';
|
||||
if (property_exists($instance, 'id')) {
|
||||
$idRefl = new \ReflectionProperty($instance, 'id');
|
||||
$idRefl->setAccessible(true);
|
||||
$id = $idRefl->getValue($instance);
|
||||
}
|
||||
if (null === $id) {
|
||||
$id = $hash;
|
||||
}
|
||||
if (is_array($this->altPrimary)) {
|
||||
foreach ($this->altPrimary as $fieldName) {
|
||||
if (property_exists($instance, $fieldName)) {
|
||||
$propRefl = new \ReflectionProperty($instance, $fieldName);
|
||||
$propRefl->setAccessible(true);
|
||||
$altPrimary[$fieldName] = $propRefl->getValue($instance);
|
||||
}
|
||||
}
|
||||
$hashedAltPrimary = $this->hashAltPrimary($altPrimary);
|
||||
}
|
||||
$info = ['hash' => $hash, 'id' => $id, 'alt_primary' => $altPrimary, 'hashed_alt_primary' => $hashedAltPrimary];
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $altPrimary
|
||||
* @return string
|
||||
*/
|
||||
private function hashAltPrimary(array $altPrimary)
|
||||
{
|
||||
return md5(json_encode($altPrimary));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user