<?php
/**
* Elements DeMI
*
* This source file is available under the elements DeMI license version 1
*
* @copyright Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at/)
* @license elements DeMI Lizenz Version 1 (https://www.elements.at/de/demi-lizenz)
*/
namespace Elements\Demi;
use Elements\Demi\Deskline\Config;
use Elements\Demi\Helper\Misc;
use Exception;
use Pimcore\Cache;
use Pimcore\Cache\Runtime;
use Pimcore\Db;
use Pimcore\Model\DataObject\ClassDefinition\Data\Fieldcollections;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Model\DataObject\Exception\InheritanceParentNotFoundException;
use Pimcore\Model\DataObject\PreGetValueHookInterface;
abstract class AbstractObject extends Concrete implements PreGetValueHookInterface
{
public const DEMI_PREFIX = 'demi';
protected $adapter;
public function setAdapter($adapter): void
{
$this->adapter = $adapter;
}
public function getAdapter()
{
if (!$this->adapter) { //cache
$ownClass = get_class($this);
$ownClassArr = explode('\\', $ownClass);
$adapterAbstractClass = '\\Elements\\Demi\\DataObject\\Adapter\\Abstract' . $ownClassArr[count($ownClassArr) - 1];
$system = $this->getSystemIdentifier();
$adapterclass = '';
if (!empty($system)) {
$adapterclass = '\\Elements\\Demi\\' . $system . '\\DataObject\\Adapter\\' . $ownClassArr[count($ownClassArr) - 1];
}
if (!@class_exists($adapterclass)) {
return;
}
$adapter = new $adapterclass($this);
if (!($adapter instanceof $adapterAbstractClass)) {
throw new Exception('Adapter class ' . $adapterclass . ' not found (' . $adapterAbstractClass . ')');
}
$this->adapter = $adapter;
}
return $this->adapter;
}
public function __construct()
{
\Elements\Demi\Deskline\Init::initDefines();
//pimcore abstract object does not have a constructor before pimcore 10.5
if(method_exists('Pimcore\Model\DataObject\AbstractObject','__construct')){
parent::__construct();
}
}
public function __call($method, $args)
{
$name = $method;
if (str_starts_with($method, self::DEMI_PREFIX)) {
$name = lcfirst(substr($method, strlen(self::DEMI_PREFIX)));
}
$adapter = $this->getAdapter();
if ($adapter && method_exists($adapter, $name)) {
return call_user_func_array([$adapter, $name], $args);
}
if (method_exists($this, $name)) {
return call_user_func_array([$this, $name], $args);
}
return parent::__call($name, $args);
}
/**
* @param string $o_key
*
* @return $this
*/
public function setKey($o_key): static
{
parent::setKey(\Pimcore\Model\Element\Service::getValidKey($o_key, 'object'));
return $this;
}
public function preGetValue(string $key)
{
if (property_exists($this, $key) && $key !== 'dates' && $key !== 'startTimes' && \Pimcore\Model\DataObject\AbstractObject::doGetInheritedValues() && $this->getClass()?->getAllowInherit() && (($this->getClass()?->getFieldDefinition($key) instanceof Fieldcollections))
) {
try {
return $this->getValueFromParent($key);
} catch (InheritanceParentNotFoundException $e) {
// no data from parent available, continue ...
}
}
}
public static function getByFid(string $fid, bool $withUnpublished = false, array $objectTypes = [\Pimcore\Model\DataObject\AbstractObject::OBJECT_TYPE_OBJECT]): AbstractObject|null
{
//when importing, we ALWAYS want to get unpublished objects too, override $withUnpublished
//this override was added much later (since actually the isImporting()-flag was not available)
//and the corresponding getByFid's sets the $withUnpublished = true --> put out some logging in this case
if (Config::getInstance()->isImporting() && !$withUnpublished) {
$withUnpublished = true;
//\Elements\Demi\Log::info("getByFid withUnpublished was overridden and set to true");
}
$result = parent::getList(['orderKey' => 'o_published', 'order' => 'DESC', 'objectTypes' => $objectTypes, 'condition' => 'fid=' . self::quote(strtolower($fid)), 'unpublished' => $withUnpublished, 'ignoreLocalizedFields' => true, 'limit' => 2]);
$result = $result->getObjects();
if (isset($result[0]) && ($result[0] instanceof self)) {
if (count($result) > 1) {
if ($result[0] instanceof Model\PriceTemplate) {
Log::notice('there are multiple items with fid=' . $fid . ' but its just a PriceTemplate, so who cares.');
} else {
Log::alert('there are multiple items with fid=' . $fid);
}
}
$object = $result[0];
//check for parent inconsistency (but only when importing)
if (Config::getInstance()->isImporting() && !Misc::checkParent($object)) {
Log::critical('deleting inconsistent object ' . $object->getPath() . $object->getKey());
$object->delete();
return null;
}
return $object;
}
return null;
}
/**
* @static
*
* @param string $string
* @param mixed $type
*
* @return string
*/
public static function quote(string $string, mixed $type = null): string
{
return Db::get()->quote($string, $type);
}
/**
* @param string $propertyName
* @param $translatedProperties
*
* @return void
*
* @internal param AbstractObject $object
* @internal param \SimpleXMLElement $translationData
*/
public function setMultilangProperty(string $propertyName, $translatedProperties): void
{
if (is_array($translatedProperties)) {
$method = 'set' . ucfirst($propertyName);
if (method_exists($this, $method)) {
foreach ($translatedProperties as $language => $data) {
$this->$method($data, $language);
}
}
}
}
/**
* @return $this|void
*
* @throws Exception
*/
public function save($params = [])
{
//TODO move that to event listeners?
//set objects with an "active" flag to unpublished
//we don't want to get objects by the search-services and lists that are inactive
//(but the importer is aware of this ;) )
try {
if (Config::getInstance()->isImporting() && method_exists($this, 'getActive')) {
if (!$this->active) {
$this->setPublished(false);
} else {
$this->setPublished(true);
}
}
} catch (Exception $e) {
//do nothing
}
try {
if (method_exists($this, 'setSystemIdentifier') && method_exists($this, 'getSystemIdentifier')) {
$system = $this->getSystemIdentifier();
if (empty($system)) {
$this->setSystemIdentifier(Constant::DESKLINE_IDENTIFIER);
}
}
parent::save();
} catch (Exception $e) {
throw $e;
}
//a performance "improvement" - this forces the object to be immediately written into the cache
//since this object may be used further used during the importing process and may be kicked out of the registry
//due to the continuously call of \Pimcore::collectGarbage() while importing
//so, do only when importing and enabled in config
if (Config::getInstance()->isImporting() && Misc::stringToBool(Config::getInstance()->getSynchronizationConfig()['useImmediateCacheWrite'])
) {
Cache::getHandler()->writeSaveQueue(); //write items dependent to this object
Runtime::set('object_' . $this->getId(), null); //remove object from registry, that it can be (re-)set with a newer object
self::getById($this->getId(), true); //let pimcore load and put object into saveStack
Cache::getHandler()->writeSaveQueue(); //write loaded object into cache
}
}
}