Проблемы с переопределением метода get
Давеча появилась у меня тут работенка. Суть заключается в следующем: у нас есть компонент который при установке создает наследника в том числе и msProduct. Загвоздка появилась при переопределении метода get, в нашем классе он имеет следующий вид:
PS Покопавшись еще немного пришел к тому что проблема в классе xpdoobject в методе getOne:
Решено: там была самая обычная зацикленность.
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;
}
И еще раз напоминаю это происходит ТОЛЬКО в одном методе и классе, в остальных все работает.Решено: там была самая обычная зацикленность.
Комментарии: 6
Можете показать схему таблицы этой модели? И еще конструктор (метод __construct). Есть подозрение, что неверно устанавливаются связи.
Схема:
<?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/, единственное я понятия не имею как это отдебажить или проверить свою догадку.
Если не ошибаюсь, то модель 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 указаны связи с одинаковыми алиасами.
Если убрать связи то выходит такое:
[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 и тд).
попробуй сюда 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);
}
Черт побери, как лаконично. Я пытался в get это учесть. У меня работает. Насколько я понимаю, проблема в чем:
1) Вызывается метод get класса acProduct, в нем есть вызов loadData
2) В loadData вызывается метод getOne
3) В getOne класса msProduct вызывается родительский метод getOne класса xPDOObject
4) В getOne класса xPDOObject в этом куске кода
Дмитрий, касательно того, что не проставляются связи без указания их в схеме. Я полагаю, что вы подключаете файл класса через require? Если так, то стоит в главном классе компонента вручную загрузить класс msProduct и тогда acProduct наследует все связи.
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');
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.