Files
awo-hamburg-intranet/mysyde/common/traits/genericRepositoryTrait.php
2026-02-17 14:56:23 +01:00

1098 lines
38 KiB
PHP

<?php
namespace DynCom\mysyde\common\traits;
use DynCom\mysyde\common\interfaces\CriteriaHelperInterface;
use DynCom\mysyde\common\interfaces\Entity;
use DynCom\mysyde\common\interfaces\GenericCollectionInterface;
use DynCom\mysyde\common\interfaces\GenericDBModelInterface;
use DynCom\mysyde\common\interfaces\GenericDBQueryWrapperInterface;
use DynCom\mysyde\common\interfaces\ModelDBConfigInterface;
/**
* Created by PhpStorm.
* User: Micha
* Date: 14.01.2015
* Time: 03:53
*/
/**
* Class genericRepositoryTrait
* Provides properties and methods that constitute a facade for data-access to the entities of the concrete repository class using this trait
* via findByID, findByAltPrimary, findByCriteria, updateAll, updateSingle, createInDB.
* Concrete repository class must overwrite constructor to require specific interface for Config and specific class for Collection.
* For example, repositories for document-classes must require DocumentModelDBConfigInterface and
* Allows addition and removal by consumers *
*/
trait genericRepositoryTrait
{
private $allowedComparisonOperators = array('IS NULL', 'IS NOT NULL', '=', '!=', '<', '>', '>=', '<=', 'IN', 'LIKE');
protected $db;
protected $config;
protected $criteriaValidationService;
protected $collection;
protected $collectionEntryClassName;
protected $cacheAll;
private $lockedRecordIDs = array();
protected $lastDateTimeAllCached = '2000-01-01 00:00:00';
/**
* @param GenericDBQueryWrapperInterface $db
* @param ModelDBConfigInterface $config
* @param CriteriaHelperInterface $criteriaValidationService
* @param GenericCollectionInterface $collection
* @param $cacheAll
*/
public function __construct(GenericDBQueryWrapperInterface $db, ModelDBConfigInterface $config, CriteriaHelperInterface $criteriaValidationService, GenericCollectionInterface $collection, $cacheAll=false)
{
$this->db = $db;
$this->config = $config;
$this->criteriaValidationService = $criteriaValidationService;
$this->collection = $collection;
$this->collectionEntryClassName = $this->collection->getEntryClassName();
$this->cacheAll = $cacheAll;
}
protected function _cacheAll()
{
if ($this->_isTableUpdated()) {
$allRowsCollection = $this->_getFullTableAsCollection();
$this->collection = $allRowsCollection;
}
}
/**
* @return bool
*/
protected function _isTableUpdated()
{
$referenceDateTime = new \DateTime($this->lastDateTimeAllCached);
$tableName = $this->config->getBaseTableName();
$query = '
SELECT (
CASE
WHEN
(
(`CREATE_TIME` > \'' . $referenceDateTime->format(\DateTime::ATOM) . '\')
OR
(`UPDATE_TIME` > \'' . $referenceDateTime->format(\DateTime::ISO8601) . '\')
)
THEN
1
ELSE
0
END
) AS \'TableIsNewer\'
FROM
`information_schema`.`TABLES`
WHERE
`TABLE_NAME` = \'' . $tableName . '\'
';
$this->db->setQuery($query);
$this->db->doQuery();
$resArr = $this->db->getResultArray();
return (bool)$resArr[0]['TableIsNewer'];
}
/**
* @return \DynCom\mysyde\common\interfaces\GenericCollectionInterface
*/
protected function _getFullTableAsCollection()
{
$tableName = $this->config->getBaseTableName();
$query = 'SELECT * FROM `' . $tableName . '`';
$this->db->setQuery($query);
$this->db->doQuery();
$resultArray = $this->db->getResultArray();
$collection = $this->collection->mapArrayToNewCollection($resultArray);
return $collection;
}
/**
* @param array $dataArray
* @return mixed
*/
protected function _mapArrayToObject(array $dataArray)
{
$newInstance = $this->_getNullObject();
$newInstance->mapFromArray($dataArray);
return $newInstance;
}
/**
* @param $instance
* @param bool $idCheck
*
* @return bool
*/
public function add($instance, $idCheck = FALSE)
{
return $this->_add($instance, $idCheck);
}
/**
* @param $instance
* @param bool $idCheck
*
* @return bool
*/
protected function _add($instance, $idCheck = FALSE)
{
return $this->collection->add($instance, $idCheck);
}
/**
* @param $instance
* @param bool $idCheck
*
* @return bool
*/
public function remove($instance, $idCheck = FALSE)
{
return $this->collection->remove($instance, $idCheck);
}
/**
* @return \DynCom\mysyde\common\interfaces\GenericCollectionInterface
*/
public function getAll()
{
return $this->_getAll();
}
/**
* @return \DynCom\mysyde\common\interfaces\GenericCollectionInterface
*/
protected function _getAll()
{
return $this->collection;
}
/**
* @param $id
*
* @return mixed
*/
public function findByID($id)
{
return $this->_findByID($id);
}
/**
* @param $id
*
* @return mixed
*/
protected function _findByID($id)
{
$id = (int)$id;
$tableName = $this->config->getBaseTableName();
$returnObject = $this->_getNullObject();
//try from collection
foreach ($this->collection as $existingInstance) {
if ($existingInstance->id === (int)$id) {
return $existingInstance;
}
}
//have cache refreshed if needed
if ($this->cacheAll) {
$this->_cacheAll();
}
//try from DB
if ($this->_existsIDInTable($id)) {
$resArr = $this->_getTableRowAsArrayByID(($id));
$dataArr = $this->_filterArrForMappedFields($resArr[0]);
$returnObject->mapFromArray($dataArr);
$this->_add($returnObject, TRUE);
}
return $returnObject;
}
/**
* @param $id
* @return bool
*/
protected function _existsIDInTable($id)
{
$id = (int)$id;
$tableName = $this->config->getBaseTableName();
$query = "SELECT EXISTS (SELECT `id` FROM `{$tableName}` WHERE `id` = '{$id}')";
$this->db->setQuery($query);
$this->db->doQuery();
if (!($this->db->getNoOfReturnedRows()) === 1) {
return FALSE;
}
$resArr = $this->db->getResultArray();
$retVal = (bool)$resArr[0][0];
return $retVal;
}
/**
* @param $id
* @return array
* @throws \Exception
*/
protected function _getTableRowAsArrayByID($id)
{
$id = (int)$id;
$tableName = $this->config->getBaseTableName();
$query = "SELECT * FROM `" . $tableName . "` WHERE `id` = '" . $id."'";
$this->db->setQuery($query);
$this->db->doQuery();
if (!($this->db->getNoOfReturnedRows() === 1)) {
throw new \Exception("Table {$tableName} does not have exactly 1 entry for id {$id}");
}
$resArr = $this->db->getResultArray();
$this->db->closeStatement();
return $resArr;
}
/**
* @return mixed Null (unset) instance of collection-element class
*/
protected function _getNullObject()
{
return $this->collection->getNullObject();
}
/**
* @param array $arr
*
* @return array
*/
protected function _filterArrForMappedFields(array $arr)
{
$output = array();
foreach ($this->config->getMappedFields() as $fieldArr) {
$name = $fieldArr['name'];
if (array_key_exists($name, $arr)) {
$output[$name] = $arr[$name];
}
}
return $output;
}
/**
* @return string
*/
protected function _getCollectionEntryClassName()
{
return $this->collection->getEntryClassName();
}
/**
* @return string
*/
public function getCollectionEntryClassName()
{
return $this->_getCollectionEntryClassName();
}
/**
* @param array $altPrimary
*
* @return mixed
*/
public function findByAltPrimary(array $altPrimary)
{
return $this->_findByAltPrimary($altPrimary);
}
/**
* @param array $searchAltPrimary
* @return mixed
* @throws \BadMethodCallException
*/
protected function _findByAltPrimary(array $searchAltPrimary)
{
//Try from collection
foreach ($this->collection as $instance) {
$instanceAltPrimary = array();
foreach ($searchAltPrimary as $key => $value) {
$instanceAltPrimary[$key] = $instance->$key;
}
if ($instanceAltPrimary === $searchAltPrimary) {
return $instance;
}
}
//else try from db
if ($this->cacheAll) {
$this->_cacheAll();
}
$arr = $this->getFindByAltPrimaryQueryAndValueMappingArray($searchAltPrimary);
if (empty($arr['valueMappingArray'])) {
return $this->getNullObject();
//throw new \DomainException('No mapping of data to defined alt-primary. Data-Arr: ' . print_r($searchAltPrimary,1) . ' | Def-Arr: ' . print_r($arr,1));
}
$valueMappingArray = $arr['valueMappingArray'];
$query = $arr['query'];
$this->db->setQuery($query);
if (!$this->db->prepareQuery()) {
throw new \BadMethodCallException('Could not prepare query. DB-Error: ' . $this->db->getErrorMessage() . ' || Query: ' . $query);
}
if (!$this->db->bindParameters($valueMappingArray)) {
throw new \BadMethodCallException('Could not bind parameters. DB-Error: ' . $this->db->getErrorMessage() . ' || Query: ' . $query . ' || Param-array: ' . print_r($valueMappingArray, 1));
}
if (!$this->db->executePreparedStatement()) {
throw new \BadMethodCallException('Could not execute prepared statement. DB-Error: ' . $this->db->getErrorMessage() . ' || Query: ' . $query);
}
if (!($this->db->getNoOfReturnedRows() === 1)) {
//throw new \Exception('Query did not return (unique) result. DB-Error: ' . $this->db->getErrorMessage() . ' || Query: ' . $query . ' || Results: ' . $this->db->getNoOfReturnedRows());
return $this->_getNullObject();
}
$resArr = $this->db->getResultArray();
$this->db->closeStatement();
$dataArr = $this->_filterArrForMappedFields($resArr[0]);
$instance = $this->_getNullObject();
$instance->mapFromArray($dataArr);
$this->_add($instance, TRUE);
return $instance;
}
/**
* @param array $searchAltPrimary
* @return array
*/
public function getFindByAltPrimaryQueryAndValueMappingArray(array $searchAltPrimary)
{
$altPrimary = $this->config->getAltPrimary();
$altPrimaryValues = array();
$altPrimaryTypes = array();
foreach ($altPrimary as $name) {
if (array_key_exists($name, $searchAltPrimary)) {
$altPrimaryValues[$name] = $searchAltPrimary[$name];
} else {
return [];
//throw new \DomainException('Paramter doesn\'t contain a value for primary-key-field \'' . $name . '\'');
}
foreach ($this->config->getMappedFields() as $fieldArr) {
if ($fieldArr['name'] === $name && array_key_exists('type', $fieldArr)) {
$altPrimaryTypes[$name] = $fieldArr['type'];
} elseif ($fieldArr['name'] === $name) {
return [];
//throw new \DomainException('Unique Key Field \'' . $name . '\' has no type in config->mappedFields');
}
}
}
$query = 'SELECT * FROM `' . $this->config->getTableName() . '` WHERE ';
$i = 0;
$valueMappingArray = array();
foreach ($altPrimaryValues as $key => $value) {
$type = $altPrimaryTypes[$key];
$paramPlaceholder = ':' . $key;
if ($i > 0) {
$query .= 'AND ';
}
if (MySQLTypeIsText($type)) {
$valueMappingArray[] = array($paramPlaceholder, $value, \PDO::PARAM_STR);
$query .= '`' . $key . '` = ' . $paramPlaceholder . ' ';
} elseif ($type === 'DECIMAL' || $type === 'FLOAT' || $type === 'DOUBLE') {
$valueMappingArray[] = array($paramPlaceholder, (string)((float)$value), \PDO::PARAM_STR);
$query .= '`' . $key . '` = ' . $paramPlaceholder . ' ';
} elseif (stringEndsWith($type, 'INT')) {
$valueMappingArray[] = array($paramPlaceholder, $value, \PDO::PARAM_INT);
$query .= '`' . $key . '` = ' . $paramPlaceholder . ' ';
} elseif (MySQLTypeIsDate($type)) {
$valueMappingArray[] = array($paramPlaceholder, (string)$value, \PDO::PARAM_STR);
$query .= '`' . $key . '` = ' . $paramPlaceholder . ' ';
}
++$i;
}
$arr = array('query' => $query, 'valueMappingArray' => $valueMappingArray);
return $arr;
}
/**
* @param array $criteria
* @param int $offset
* @param int $limit
* @return GenericCollectionInterface
* @throws \Exception
*/
public function findByCriteria(array $criteria, $offset = 0, $limit = 0)
{
return $this->_findByCriteria($criteria, $offset, $limit);
}
/**
* @param array $criteria
* @param int $offset
* @param int $limit
* @return GenericCollectionInterface
* @throws \InvalidArgumentException
*/
protected function _findByCriteria(array $criteria, $offset = 0, $limit = 0)
{
$offset = (int)$offset;
$limit = (int)$limit;
$resultCollection = $this->collection->getEmptyCollection();
if (!$this->criteriaValidationService->validateCriteria($this->config, $criteria)) {
throw new \InvalidArgumentException('Criteria-Array invalid');
}
if ($this->cacheAll) {
$this->_cacheAll();
}
$query = $this->_criteriaToQuery($criteria);
if (($limit !== 0) || ($offset !== 0)) {
$query .= " LIMIT $offset,$limit";
}
$this->db->setQuery($query);
if (!$this->db->doQuery()) {
throw new \ErrorException('Could not execute query. DB-Error: ' . $this->db->getErrorMessage() . ' Query: ' . $query);
//return $resultCollection;
}
if (!($this->db->getNoOfReturnedRows() > 0)) {
return $resultCollection;
}
$resArr = $this->db->getResultArray();
$this->db->closeStatement();
foreach ($resArr as $dataArr) {
$instance = $this->getNullObject();
$noOfMappedFields = $instance->mapFromArray($dataArr);
if ($noOfMappedFields > 0) {
$this->_add($instance, TRUE);
$resultCollection->add($instance, TRUE);
}
}
return $resultCollection;
}
/**
* @param array $criteria
* @return string
*/
public function getFindByCriteriaQuery(array $criteria)
{
return $this->_criteriaToQuery($criteria);
}
/**
* @param array $criteria
* @return string
* @throws \InvalidArgumentException
*/
protected function _criteriaToQuery(array $criteria)
{
if (!$this->criteriaValidationService->validateCriteria($this->config, $criteria)) {
throw new \InvalidArgumentException('Criteria-Array invalid');
}
$fieldNames = array();
$fieldTypes = array();
foreach ($this->config->getMappedFields() as $fieldArr) {
$fieldNames[] = $fieldArr['name'];
$fieldTypes[$fieldArr['name']] = $fieldArr['type'];
}
$query = 'SELECT * FROM `' . $this->config->getTableName() . '` WHERE ';
$i = 0;
foreach ($criteria as $disjunctCriteria) {
if ($i > 0) {
$query .= 'OR ';
}
$query .= '( ';
$j = 0;
foreach ($disjunctCriteria as $conjunctCriterion) {
if ($j > 0) {
$query .= 'AND ';
}
$fieldName = $conjunctCriterion[0];
$fieldType = $fieldTypes[$fieldName];
$upperFieldType = strtoupper($fieldType);
$comparator = $conjunctCriterion[1];
if (!in_array($comparator, $this->allowedComparisonOperators, TRUE)) {
throw new \InvalidArgumentException('At least one criterion has invalid comparison-operator: ' . (string)$comparator);
}
$compareValue = NULL;
if (array_key_exists(2, $conjunctCriterion)) {
$compareValue = $conjunctCriterion[2];
}
if ($comparator === 'IS NULL') {
$query .= '`' . $fieldName . '` IS NULL';
} elseif ($comparator === 'IS NOT NULL') {
$query .= '`' . $fieldName . '` IS NOT NULL';
} elseif ($comparator === '=') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` = ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType === 'FLOAT' || $upperFieldType === 'DOUBLE') {
$query .= '`' . $fieldName . '` = \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` = \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` = \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === '!=') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` != ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType=== 'FLOAT' || $upperFieldType === 'DOUBLE') {
$query .= '`' . $fieldName . '` != \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` != \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` != \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === '>') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` > ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType === 'FLOAT' || $upperFieldType === 'DOUBLE') {
$query .= '`' . $fieldName . '` > \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` > \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` > \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === '<') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` < ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType === 'FLOAT' || $upperFieldType === 'DOUBLE') {
$query .= '`' . $fieldName . '` < \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` < \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` < \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === '<=') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` <= ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType === 'FLOAT' || $upperFieldType === 'DOUBLE') {
$query .= '`' . $fieldName . '` <= \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` <= \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` <= \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === '>=') {
if (MySQLTypeIsText($fieldType)) {
$query .= '`' . $fieldName . '` >= ' . $this->db->escapeString($compareValue) . ' ';
} elseif ($upperFieldType === 'DECIMAL' || $upperFieldType === 'FLOAT' || $upperFieldType=== 'DOUBLE') {
$query .= '`' . $fieldName . '` >= \'' . $compareValue . '\' ';
} elseif (stringEndsWith($fieldType, 'INT')) {
$query .= '`' . $fieldName . '` >= \'' . $compareValue . '\' ';
} elseif (MySQLTypeIsDate($fieldType)) {
$query .= '`' . $fieldName . '` >= \'' . (string)$compareValue . '\'';
}
} elseif ($comparator === 'IN') {
$query .= '`' . $fieldName . '` IN [';
$z = 0;
foreach ($compareValue as $val) {
if ($z > 0) {
$query .= ',';
}
$query .= '\'' . $val . '\'';
++$z;
}
} elseif ($comparator === 'LIKE') {
//fnmatch-Wildcard durch SQL-Wildcard ersetzen
$compareValue = str_replace('*', '%', $compareValue);
$query .= '`' . $fieldName . '` LIKE ' . $this->db->escapeString($compareValue) . ' ';
}
++$j;
}
$query .= ') ';
++$i;
}
return $query;
}
/**
* @return int
*/
public function updateAll()
{
return $this->_updateAll();
}
/**
* @return int
*/
protected function _updateAll()
{
$count = count($this->collection);
$successes = 0;
foreach ($this->collection as $instance) {
if ($this->updateSingle($instance)) {
++$successes;
}
}
return ($count - $successes);
}
/**
* @param $instance
*
* @return bool
*/
public function updateSingle(GenericDBModelInterface $instance)
{
return $this->_updateSingle($instance);
}
/**
* @param GenericDBModelInterface $instance
* @return bool
* @throws \ErrorException
*/
protected function _updateSingle(GenericDBModelInterface $instance)
{
if (isset($instance->id) && $instance->id > 0 && $this->isRecordLocked($instance->id)) {
throw new \DomainException('Entity is locked and cannot be updated');
}
$this->lockRecordByID($instance->id);
$query = $this->getUpdateSingleQuery($instance);
$this->db->setQuery($query);
if (!$this->db->doQuery()) {
throw new \ErrorException('Could not execute query. DB-Error: ' . $this->db->getErrorMessage() . ' Query: ' . $query);
}
$this->db->closeStatement();
$this->_add($instance, TRUE);
$this->releaseRecordLock($instance->id);
return TRUE;
}
/**
* @param GenericDBModelInterface $instance
* @return string
* @throws \DomainException
*/
public function getUpdateSingleQuery(GenericDBModelInterface $instance)
{
$className = $this->getCollectionEntryClassName();
if (!$instance instanceof $className) {
throw new \DomainException('Parameter \'instance\' is not an instance of type \'' . $className . '\'');
}
$primary = array();
if (property_exists($instance, 'id')) {
$primary[] = 'id';
}
if (is_array($this->config->getAltPrimary()) && (count($this->config->getAltPrimary()) > 0)) {
$primary = $this->config->getAltPrimary();
}
if (count($primary) < 1) {
throw new \DomainException('No primary key available');
}
$mappedFieldsArr = $this->config->getMappedFields();
$primaryArr = array();
foreach ($primary as $keyFieldName) {
if (null === ($instance->$keyFieldName)) {
throw new \DomainException('Instance lacks value for unique key field \'' . $keyFieldName . '\'');
} else {
$primaryArr[] = array('name' => $keyFieldName, 'value' => $instance->$keyFieldName);
}
}
$query = 'UPDATE `' . $this->config->getBaseTableName() . '` SET ';
$i = 0;
foreach ($mappedFieldsArr as $fieldArr) {
$propName = $fieldArr['name'];
if (null !== $instance->$propName && !in_array($propName, $primary, TRUE)) {
if ($i > 0) {
$query .= ',';
}
if (MySQLTypeIsText($fieldArr['type'])) {
$query .= '`' . $propName . '` = ' . $this->db->escapeString($instance->$propName) . ' ';
} elseif ($fieldArr['type'] === 'DECIMAL' || $fieldArr['type'] === 'FLOAT' || $fieldArr['type'] === 'DOUBLE') {
$query .= '`' . $propName . '` = ' . (float)$instance->$propName . ' ';
} elseif (stringEndsWith($fieldArr['type'], 'INT')) {
$query .= '`' . $propName . '` = ' . (int)$instance->$propName . ' ';
} elseif (MySQLTypeIsDate($fieldArr['type'])) {
if ($instance->$propName !== 'NULL') {
$query .= '`' . $propName . '` = \'' . $instance->$propName . '\' ';
} else {
$query .= '`' . $propName . '` = NULL';
}
} else {
$query .= '`' . $propName . '` = ' . $this->db->escapeString($instance->$propName) . ' ';
}
++$i;
}
}
$query .= 'WHERE ';
$i = 0;
foreach ($primaryArr as $primaryFieldArr) {
$name = $primaryFieldArr['name'];
$value = $primaryFieldArr['value'];
foreach ($mappedFieldsArr as $fieldArr) {
if ($fieldArr['name'] === $name) {
$type = $fieldArr['type'];
break;
}
}
if (null === $type || $type === '' || !is_string($type)) {
throw new \DomainException('No type for primary key field \'' . $name . '\'');
}
if ($i > 0) {
$query .= 'AND ';
}
if (MySQLTypeIsText($type)) {
$query .= '`' . $name . '` = ' . $this->db->escapeString($value) . ' ';
} elseif ($type === 'DECIMAL' || $type === 'FLOAT' || $type === 'DOUBLE') {
$query .= '`' . $name . '` = \'' . (float)$value . '\' ';
} elseif (stringEndsWith($type, 'INT')) {
$query .= '`' . $name . '` = \'' . (int)$value . '\' ';
} elseif (MySQLTypeIsDate($type)) {
$query .= '`' . $name . '` = ' . $value . ' ';
}
++$i;
}
$query .= 'LIMIT 1';
return $query;
}
/**
* @param $instance
*
* @return bool|int
*/
public function createInDB(GenericDBModelInterface $instance)
{
return $this->_createInDB($instance);
}
/**
* @param GenericDBModelInterface $instance
* @return bool
* @throws \ErrorException
*/
protected function _createInDB(GenericDBModelInterface $instance)
{
$query = $this->getCreateInDBQuery($instance);
$this->db->setQuery($query);
if (!$this->db->doQuery()) {
throw new \ErrorException('Could not execute query. DB-Error: ' . $this->db->getErrorMessage() . ' Query: ' . $query);
}
$affectedRows = $this->db->getNoOfAffectedRows();
if (!($affectedRows === 1)) {
$this->db->closeStatement();
return FALSE;
}
$id = $this->db->getLastInsertId();
$this->db->closeStatement();
$instance = $this->_findByID($id);
$this->_add($instance, TRUE);
return $instance->id;
}
/**
* @param GenericDBModelInterface $instance
* @return string
* @throws \DomainException
*/
public function getCreateInDBQuery(GenericDBModelInterface $instance)
{
$className = $this->getCollectionEntryClassName();
if (!($instance instanceof $className)) {
throw new \DomainException('Parameter \'instance\' is not an instance of class \'' . $className . '\'');
}
$query = 'INSERT INTO `' . $this->config->getTableName() . '` SET ';
$i = 0;
foreach ($this->config->getMappedFields() as $fieldArr) {
$name = $fieldArr['name'];
$type = strtoupper($fieldArr['type']);
if ($name !== 'id') {
if ($i > 0) {
$query .= ',';
}
if (MySQLTypeIsText($type)) {
$query .= '`' . $name . '` = ' . $this->db->escapeString($instance->$name) . ' ';
} elseif ($type === 'DECIMAL' || $type === 'FLOAT' || $type === 'DOUBLE') {
$query .= '`' . $name . '` = \'' . (float)$instance->$name . '\' ';
} elseif (stringEndsWith($type, 'INT')) {
$query .= '`' . $name . '` = \'' . (int)$instance->$name . '\' ';
} elseif (MySQLTypeIsDate($fieldArr['type'])) {
if((null !== $instance->$name) && ($instance->$name !== 'NULL')) {
$query .= '`' . $name . '` = \'' . $instance->$name . '\' ';
} else {
$query .= '`' . $name . '` = NULL';
}
}
++$i;
}
}
return $query;
}
/**
* @param GenericDBModelInterface $instance
* @return string
* @throws \InvalidArgumentException
*/
public function getDeleteByIDQuery(GenericDBModelInterface $instance)
{
$className = $this->getCollectionEntryClassName();
if (!($instance instanceof $className)) {
throw new \DomainException('Parameter \'instance\' is not an instance of class \'' . $className . '\'');
}
if (!((int)$instance->getID() > 0)) {
throw new \InvalidArgumentException('Instance has no positive value for field \'id\'');
}
$query = 'DELETE FROM `' . $this->config->getBaseTableName() . '` WHERE id = ' . (int)$instance->id;
return $query;
}
/**
* @param GenericDBModelInterface $instance
* @return bool
* @throws \DomainException
*/
public function deleteByID(GenericDBModelInterface $instance)
{
if ($this->isRecordLocked($instance->getID())) {
throw new \DomainException("Entity with id {$instance->getID()} is locked and cannot be deleted");
}
$query = $this->getDeleteByIDQuery($instance);
$this->lockRecordByID($instance->getID());
$this->remove($instance, true);
$this->db->setQuery($query);
if (!$this->db->doQuery()) {
throw new \BadMethodCallException('Could not execute query. DB-Error: ' . $this->db->getErrorMessage() . ' Query: ' . $query);
}
$affectedRows = $this->db->getNoOfAffectedRows();
$this->db->closeStatement();
$this->releaseRecordLock($instance->id);
if (!($affectedRows === 1)) {
return false;
}
return true;
}
/**
* @return Entity Null (unset) instance of the class of elements in the collection
*/
public function getNullObject()
{
return $this->_getNullObject();
}
/**
* @param array $arr
*
* @return array
*/
public function filterArrForMappedFields(array $arr)
{
return $this->_filterArrForMappedFields($arr);
}
/**
* @param $instance
* @param bool $idCheck
*/
protected function _remove($instance, $idCheck = FALSE)
{
$this->collection->remove($instance, $idCheck);
}
/**
* @return \DynCom\mysyde\common\interfaces\ModelDBConfigInterface
*/
public function getConfig()
{
return $this->config;
}
/**
* @return string
*/
public function getObjectClass()
{
return $this->config->getModelClassName();
}
/**
* @param $id
*/
public function lockRecordByID($id)
{
if (!array_key_exists((int)$id, $this->lockedRecordIDs)) {
$this->lockedRecordIDs[(int)$id] = (int)$id;
}
}
/**
* @param $id
*/
public function releaseRecordLock($id)
{
if (array_key_exists((int)$id, $this->lockedRecordIDs)) {
unset($this->lockedRecordIDs[(int)$id]);
}
}
/**
* @param $id
* @return bool
*/
public function isRecordLocked($id)
{
return array_key_exists((int)$id, $this->lockedRecordIDs);
}
/**
* @param GenericDBModelInterface $entity
*/
public function removeEntityFromCache(GenericDBModelInterface $entity)
{
if (isset($entity->id) && ((int)$entity->id > 0)) {
$this->collection->remove($entity, true);
} else {
$this->collection->remove($entity, false);
}
}
/**
* @param $id
*/
public function recacheEntityFromDBByID($id)
{
$this->findByID((int)$id);
}
/**
* @param array $selectionCriteria
* @param array $fields
* @param int $offset
* @param int $limit
* @return array
* @throws \ErrorException
*/
public function getFieldData(array $selectionCriteria, array $fields = [], $offset = 0, $limit = 0)
{
$resultCollection = $this->_findByCriteria($selectionCriteria,$offset,$limit);
return $resultCollection->getFieldData($fields);
}
/**
* @return bool
*/
public function startTransaction()
{
return $this->db->startTransaction();
}
/**
* @return bool
*/
public function commitTransaction()
{
return $this->db->commitTransaction();
}
/**
* @return bool
*/
public function rollbackTransaction()
{
return $this->db->rollbackTransaction();
}
/**
* @return bool
*/
public function inTransaction()
{
return $this->db->inTransaction();
}
/**
* @param $query
* @return array
*/
public function getAllByQueryAsArray($query)
{
$result = [];
$this->db->setQuery($query);
$this->db->doQuery();
$noRows = $this->db->getNoOfReturnedRows();
if($noRows > 0) {
$resArr = $this->db->getResultArray();
foreach($resArr as $res) {
$filtered = $this->_filterArrForMappedFields($res);
$instance = $this->getNullObject();
$noOfMappedFields = $instance->mapFromArray($filtered);
if ($noOfMappedFields > 0) {
$this->_add($instance, TRUE);
$result[] = $instance;
}
}
}
return $result;
}
/**
* @param $query
* @return GenericCollectionInterface
*/
public function getAllByQueryAsCollection($query)
{
$arr = $this->getAllByQueryAsArray($query);
$coll = $this->collection->getEmptyCollection();
foreach ($arr as $el) {
$coll->add($el,false);
}
return $coll;
}
/**
* @param array $resultArray
* @return GenericCollectionInterface
*/
public function getCollectionForResultArray(array $resultArray)
{
$collection = $this->collection->getEmptyCollection();
foreach ($resultArray as $entityRow) {
$entity = $this->getNullObject();
$entity->mapFromArray($entityRow);
$this->collection->add($entity);
}
return $collection;
}
}