<?php
 namespace App\Entity; abstract class SelectAbstract implements SelectInterface { const cacheTtl=7200; protected $id; protected $tablePrimaryKey='id'; protected $primaryKeyType='numeric'; protected $selectForUpdate=false; protected $fields=[]; protected $recordExists=false; protected $tableName; protected $operation=null; final protected function __construct($operation, $id, $forUpdateFlag=false){ $this->operation=$operation; if ($forUpdateFlag) { $this->selectForUpdate=true; } $this->id=$id; $this->manageDbTable(); $this->initialize(); } protected function manageDbTable() :void { $this->setTableName(); if (!$this->tableName) { throw new \Exception('The table name was NOT set for class `'.get_called_class().'` - the setTableName() method should have filled in the attribute `this->tableName`.'); } } abstract protected function setTableName(); protected function initialize() { $this->populate(); } static public function select($idEntity, $forUpdateFlag=false) { if ($forUpdateFlag) { return static::selectForUpdate($idEntity); } $className=stripClassNamespace(get_called_class()); $cachedObject=\App\Entity\Cache::getInstance()->get($className, $idEntity); if ($cachedObject) return $cachedObject; $entityObj=new static('select', $idEntity); \App\Entity\Cache::getInstance()->set($entityObj); return $entityObj; } static public function selectForUpdate($idEntity) { if (!\DB::isInsideTransaction()) { return static::select($idEntity); } $className=stripClassNamespace(get_called_class()); $cachedObject=\App\Entity\Cache::getInstance()->getInternal($className, $idEntity); if ($cachedObject) return $cachedObject; $entityObj=new static('select', $idEntity, true); \App\Entity\Cache::getInstance()->setInternal($entityObj); return $entityObj; } protected function populate() { if ($this->primaryKeyType=='numeric' and (!is_numeric($this->id) or $this->id<=0) ) { return ; } if ($this->primaryKeyType=='string' and !strlen((string)$this->id) ) { return ; } $db=\DB::getInstance(); $entityDetSQL = "SELECT * FROM `{$this->tableName}` WHERE `{$this->tablePrimaryKey}`=?"; if ($this->selectForUpdate) $entityDetSQL .= " FOR UPDATE"; $entityDetEx = $db->Execute( $entityDetSQL, [$this->id]); if (!$entityDetEx) { \Log::getInstance()->error("Could not get entity details for table `{$this->tableName}`; '{$this->id}' Error: {$db->ErrorMsg()} [{$db->ErrorNo()}]."); throw new \DBException("Could not get entity details for table `{$this->tableName}`; '{$this->id}'."); } $entityDet = $entityDetEx->FetchRow(); if (!$entityDet) $entityDet = []; if ($entityDet) $this->recordExists=true; $this->fields = $entityDet; } public function getFields() { return $this->fields; } public function getId(){ return $this->id; } public function getTableName() { return $this->tableName; } public function recordExists() { if ($this->operation!='select') throw new \Exception("You can check if a record exists only for `select` operation. Called for Entity - `{$this->tableName}`"); return $this->recordExists; } public function __get($var) { if ($this->operation!='select') { throw new \Exception('You can call `'.__METHOD__.'` only for `select` operations. You used it for `'.$this->operation.'` on `'.get_called_class().'` class on `'.$var.'` attribute.'); } $className = stripClassNamespace(get_class($this)); foreach(\App\Entity\Utils\ExtensionsManager::getInstance($className)->getExtensions('\App\Entity\Utils\Extension_GetAttributeAbstract') as $extClass) { $extObj = new $extClass($this); $value = $extObj->getAttribute($var); $extObj->destroy(); if ($value!==null) { return $value; } } return $this->getAttribute($var); } protected function getAttribute($var) { if (array_key_exists($var, $this->fields)) { return $this->fields[$var]; } else { if ($this->recordExists) { throw new \Exception(sprintf("The field '%s' doesn't exist in entity %s. Please check if this attribute is actually defined in the DB (it its a real attribute) or in the entity (if its a virtual attribute)", $var, get_called_class())); } else { return null; } } } protected function getSerializedProcessedRemarks() { if (is_array($this->fields['processedRemarks']) and $this->fields['processedRemarks']) { return array2string($this->fields['processedRemarks']); } else { return ''; } } protected function getUnserializedProcessedRemarks() { if ($this->fields['processedRemarks']) { return string2array($this->fields['processedRemarks']); } else { return []; } } public function getSelectForUpdateFlag() { return $this->selectForUpdate; } } 