Проблемы с переопределением метода get

Давеча появилась у меня тут работенка. Суть заключается в следующем: у нас есть компонент который при установке создает наследника в том числе и msProduct. Загвоздка появилась при переопределении метода get, в нашем классе он имеет следующий вид:
public function get($k, $format = null, $formatTemplate = null) {
        return isset(array_merge($this->loadData()->_fieldMeta,$this->_originalFieldMeta)[$k])
            ? parent::get($k, $format = null, $formatTemplate = null)
            : $this->loadChars(false)[$k];
    }
При вызове метода в таком виде скрипт просто падает(вызываю во всем известном компоненте Console), и дает информацию о нехватки памяти. Путем несложного копания — «где проблема», пришел в метод loadData() все того же класса msProduct:
public function loadData()
    {
        if (!is_object($this->Data) || !($this->Data instanceof msProductData)) {
            if (!$this->Data = $this->getOne('Data')) {//виснет как оказалось в этом условии
                $this->Data = $this->xpdo->newObject('msProductData');
                parent::addOne($this->Data);
            }
        }
        return $this->Data;
    }
При чем если вызвать этот кусок кода
!$this->Data = $this->getOne('Data')
выше, то ничего не виснет, получается проблема ТОЛЬКО в методе get нашего класса, в остальных все работает отлично. Суть проблемы вроде описал нормально, будут вопросы — задавайте. И конечно же буду рад любой помощи)

PS Покопавшись еще немного пришел к тому что проблема в классе xpdoobject в методе getOne:
public function & getOne($alias, $criteria= null, $cacheFlag= true) {
        $object= null;
        if ($fkdef= $this->getFKDefinition($alias)) {
            $k= $fkdef['local'];
            $fk= $fkdef['foreign'];
            die(var_dump($this->_relatedObjects[$alias]));//вот здесь отдается NULL
            if (isset ($this->_relatedObjects[$alias])) {//а здесь если закомментировать строчку выше, то виснет
                if (is_object($this->_relatedObjects[$alias])) {
                    $object= & $this->_relatedObjects[$alias];
                    return $object;
                }
            }
            if ($criteria === null) {
                $criteria= array ($fk => $this->get($k));
                if (isset($fkdef['criteria']) && isset($fkdef['criteria']['foreign'])) {
                    $criteria= array($fkdef['criteria']['foreign'], $criteria);
                }
            }
            if ($object= $this->xpdo->getObject($fkdef['class'], $criteria, $cacheFlag)) {
                $this->_relatedObjects[$alias]= $object;
            }
        } else {
            $this->xpdo->log(xPDO::LOG_LEVEL_WARN, "Could not getOne: foreign key definition for alias {$alias} not found.");
        }
        return $object;
    }
И еще раз напоминаю это происходит ТОЛЬКО в одном методе и классе, в остальных все работает.

Решено: там была самая обычная зацикленность.
Дмитрий Зарубин
08 августа 2018, 12:22
modx.pro
1 435
0

Комментарии: 6

Денис
08 августа 2018, 14:21
0
Можете показать схему таблицы этой модели? И еще конструктор (метод __construct). Есть подозрение, что неверно устанавливаются связи.
    Дмитрий Зарубин
    08 августа 2018, 14:28
    0
    Схема:
    <?xml version="1.0" encoding="UTF-8"?>
    <model package="addchar" baseClass="xPDOObject" platform="mysql" defaultEngine="InnoDB" phpdoc-package="addchar" version="0.2">
    
        <object class="acChar" table="ac_characteristics" extends="xPDOObject">
            <field key="key" dbtype="varchar" precision="250" phptype="string" null="false" index="pk" />
            <field key="title" dbtype="varchar" precision="255" phptype="string" null="false" default="" />
            <field key="type" dbtype="varchar" precision="255" phptype="string" null="false" default="" />
    
            <index alias="key" name="key" primary="false" unique="false" type="BTREE">
                <column key="key" length="" collation="A" null="false" />
            </index>
    
            <composite alias="Value" class="acProductChar" local="key" foreign="key_char" cardinality="many" owner="local" />
        </object>
    
        <object class="acProductChar" table="ac_product_characteristics" extends="xPDOObject">
            <field key="key_char" dbtype="varchar" precision="250" phptype="string" null="false" />
            <field key="product_id" dbtype="int" precision="10" phptype="integer" attributes="unsigned" null="false" />
            <field key="value" dbtype="text" phptype="string" null="false" default="" />
    
            <index alias="key_char" name="key_char" primary="true" unique="false" type="BTREE">
                <column key="key_char" length="" collation="A" null="false" />
            </index>
    
            <index alias="product_id" name="product_id" primary="false" unique="false" type="BTREE">
                <column key="product_id" length="" collation="A" null="false" />
            </index>
    
            <aggregate alias="Char" class="acChar" local="key_char" foreign="key" cardinality="one" owner="foreign" />
            <aggregate alias="Product" class="acProduct" local="product_id" foreign="id" cardinality="one" owner="foreign"/>
        </object>
    
        <object class="acProduct" extends="msProduct">
            <field key="class_key" dbtype="varchar" precision="100" phptype="string" null="false" default="acProduct"/>
    
            <aggregate alias="Category" class="msCategory" local="parent" foreign="id" cardinality="one" owner="foreign"/>
            <composite alias="Chars" class="acProductChar" local="id" foreign="product_id" cardinality="many" owner="local"/>
            <composite alias="Data" class="msProductData" local="id" foreign="id" cardinality="one" owner="local"/>
            <composite alias="Categories" class="msCategoryMember" local="id" foreign="product_id" cardinality="many"
                       owner="local"/>
            <composite alias="Options" class="msProductOption" local="id" foreign="product_id" cardinality="many"
                       owner="local"/>
        </object>
    
    </model>
    Конструктор:
    function __construct(xPDO & $xpdo) {
    
            parent::__construct($xpdo);
            parent::set('class_key', 'acProduct');
    
        }
    Как я понял проблема действительно в модели, так как ошибки на который виснет это вызов $this->loadClass в классе xpdo.
    Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 262144 bytes) in F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\xpdo.class.php on line 596
    
    Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 262144 bytes) in Unknown on line 0
    
    Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 262144 bytes) in Unknown on line 0
    Плюс 596 строчка в xpdo это:
    $typePos= strrpos($fqn, '_' . $this->config['dbtype']);
    Как я понимаю сюда попадает файл класса acproduct.class.php из папки model/<name_component>/, а должен попадать из папки model/<name_component>/mysql/, единственное я понятия не имею как это отдебажить или проверить свою догадку.
      Денис
      08 августа 2018, 14:58
      0
      Если не ошибаюсь, то модель acProduct при расширении msProduct должна получить все её связи, т.е. эти четыре связи:
      <aggregate alias="Category" class="msCategory" local="parent" foreign="id" cardinality="one" owner="foreign"/>
      <composite alias="Data" class="msProductData" local="id" foreign="id" cardinality="one" owner="local"/>
      <composite alias="Categories" class="msCategoryMember" local="id" foreign="product_id" cardinality="many" owner="local"/>
      <composite alias="Options" class="msProductOption" local="id" foreign="product_id" cardinality="many" owner="local"/>
      не нужны, поскольку они уже указаны в msProduct, и их нужно удалить из схемы и перегенерировать модель. Возможно возникает конфликт из-за того, что в acProduct и в родительском msProduct указаны связи с одинаковыми алиасами.
        Дмитрий Зарубин
        08 августа 2018, 15:15
        0
        Если убрать связи то выходит такое:
        [2018-08-08 15:11:10] (ERROR @ F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\xpdo.class.php : 1828)
        
        No foreign key definition for parentClass: acProduct using relation alias: Data
        
        [2018-08-08 15:11:10] (WARN @ F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\om\xpdoobject.class.php : 1129)
        
        Could not getOne: foreign key definition for alias Data not found.
        
        [2018-08-08 15:11:10] (ERROR @ F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\xpdo.class.php : 1828)
        
        No foreign key definition for parentClass: acProduct using relation alias: msProductData
        
        [2018-08-08 15:11:10] (WARN @ F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\om\xpdoobject.class.php : 1250)
        
        Foreign key definition for class , alias msProductData not found, or cardinality is not 'one'.
        
        [2018-08-08 15:11:10] (WARN @ F:\server\bin\OpenServer\domains\rework-addchar.loc\core\xpdo\om\xpdoobject.class.php : 1256)
        
        Could not add related object! Array
        (
            [id] => 
            [article] => 
            [price] => 0
            [old_price] => 0
            [weight] => 0
            [image] => 
            [thumb] => 
            [vendor] => 0
            [made_in] => 
            [new] => 
            [popular] => 
            [favorite] => 
            [tags] => 
            [color] => 
            [size] => 
            [source] => 1
        )
        И невозможность достать что либо из msProductData (price, color и тд).
    Володя
    08 августа 2018, 20:52
    +1
    попробуй сюда github.com/bezumkin/miniShop2/blob/master/core/components/minishop2/model/minishop2/msproduct.class.php#L237
    добавить идентификатор, как
    if (!$this->Data = $this->getOne('Data',  parent::get('id'))) {
        $this->Data = $this->xpdo->newObject('msProductData');
        parent::addOne($this->Data);
    }
      Денис
      09 августа 2018, 08:43
      0
      Черт побери, как лаконично. Я пытался в get это учесть. У меня работает. Насколько я понимаю, проблема в чем:
      1) Вызывается метод get класса acProduct, в нем есть вызов loadData
      2) В loadData вызывается метод getOne
      3) В getOne класса msProduct вызывается родительский метод getOne класса xPDOObject
      4) В getOne класса xPDOObject в этом куске кода
      if ($criteria === null) {
          $criteria= array ($fk => $this->get($k));
          if (isset($fkdef['criteria']) && isset($fkdef['criteria']['foreign'])) {
              $criteria= array($fkdef['criteria']['foreign'], $criteria);
          }
      }
      вызывается снова метод get из класса acProduct, в котором вызывается loadData и все уходит в цикл.

      Дмитрий, касательно того, что не проставляются связи без указания их в схеме. Я полагаю, что вы подключаете файл класса через require? Если так, то стоит в главном классе компонента вручную загрузить класс msProduct и тогда acProduct наследует все связи.
      $this->modx->getService('miniShop2');
      $this->modx->loadClass('msProduct');
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      6