Fi1osof 04 ноября 2013 1 61
Материал для экспертов.

Заметка: будут использоваться примеры кода из minishop2 от bezumkin. Пусть никто не ищет подвоха, его здесь нет. Просто материал предметный, а проверить примеры может всякий, скачав его из репозитория.
Кто захочет поиграться с примерами, лучше устанавливайте Console.

В свое время у нас уже был очень сложный диалог по поводу xPDO::addDerivativeCriteria(), и вот только сейчас я разобрался со всей этой системой на 100%, и могу четко все разложить по полочкам и описать.

В статье рассматривается поведение xPDO, когда у вас в одной таблице, в которой есть колонка class_key, хранятся записи нескольких производных классов. Эта ситуация широко известна. К примеру в таблице site_content хранятся записи производных modResource классов modDocument, modWebLink и т.п. Подробней обо всем этом можно прочитать здесь.

Коротко: когда в таблице есть колонка class_key, то xPDO, получая записи из такой таблицы методами getObject(), getCollection() и т.п., возвращает конечные объекты именно тех классов, имена которых указаны в этих колонках. То есть, к примеру, сделав выборку трех записей из таблицы site_content, значения class_key которых будут modDocument, modWebLink и modSymLink, на выходе мы получим не 3 объекта modResource, а три уникальных объекта от соответствующих классов.

Собственно, на этом и строятся CRC. Мы добавляем свой собственный класс, расширяя modResource, и при выборке $modx->getCollection('modResource'), вместе со всеми прочими документами, получаем и собственные объекты (чисто локальный пример).

Но здесь есть очень много всяких тонкостей. И чтобы было проще их понять, рассмотрим на реальных примерах с использованием кастомного класса msProduct из пакета minishop2.
Сразу уточню, что у меня документ с id=100 — это как раз документ с class_key=msProduct. Это важно запомнить, чтобы четко понимать результаты примеров.

Пример
$q = $modx->newQuery('msProduct', 100);
$docs = $modx->getCollection('msProduct', $q);


Вот здесь у нас с выполнением никаких проблем не возникло. Результирующий объект — инстанс класса msProduct, и все ОК.

Теперь уберем id из условия, и выполним запрос, который вернет нам все документы.

$q = $modx->newQuery('msProduct');
$docs = $modx->getCollection('msProduct', $q);


И получим вот такие ошибки в лог:

Instantiated a derived class modDocument that is not a subclass of the requested class msProduct


Что это за ошибки и почему они происходят?
Для этого стоит изучить метод xPDOObject::_loadInstance()

.......
$instance= $xpdo->newObject($actualClass);
if (is_object($instance) && $instance instanceof xPDOObject) {
    ....... 
    $parentClass = $className;
    $isSubPackage = strpos($className,'.');
    if ($isSubPackage !== false) {
        $parentClass = substr($className,$isSubPackage+1);
    }
    if (!$instance instanceof $parentClass) {
        $xpdo->log(xPDO::LOG_LEVEL_ERROR, 
             "Instantiated a derived class {$actualClass} that 
                is not a subclass of the requested class {$className}");
    }


То есть, если реальный инстанс полученного объекта не является инстансом запрашиваемого в getCollection() класса, то xPDO пишет ошибку.
Следует отметить, что он все равно вернет полученный объект, но логи будут расти.

То есть если мы заменим msProduct на modResource, то этих ошибок не будет.

$q = $modx->newQuery('msProduct');
$docs = $modx->getCollection('modResource', $q);


В данном случае мы запросили коллекцию объектов modResource, и так как все они — производные от modResource, то и ошибки нет. Но это еще совсем не все. Как в мультике — «Стрижка только началась»…

Вот здесь стоит рассмотреть более внимательно код, и еще жду ответа от Джейсона Коварда о возможном баге. Собственно, ответ уже есть. Да, это бага. Тикет создан и он его обещал пофиксить прямо сейчас. Ну да ладно, баг — багом, но он нам не мешает дальнейшему рассмотрению поднятой темы.

Итак, дело в том, что существует метод xPDOObject::addDerivativeCriteria(), который автоматически добавляет условие class_key в запрос. Давайте посмотрим код.

public function addDerivativeCriteria($className, $criteria) {
    if ($criteria instanceof xPDOQuery && !isset($this->map[$className]['table'])) {
        if (isset($this->map[$className]['fields']['class_key']) && 
            !empty($this->map[$className]['fields']['class_key'])) {
            $criteria->where(array('class_key' => $this->map[$className]['fields']['class_key']));
            if ($this->getDebug() === true) {
                $this->log(xPDO::LOG_LEVEL_DEBUG, "#1: Automatically 
                    adding class_key criteria for derivative query of class {$className}");
            }
        } else {
            foreach ($this->getAncestry($className, false) as $ancestor) {
                if (isset($this->map[$ancestor]['table']) 
                    && isset($this->map[$ancestor]['fields']['class_key'])) {
                    $criteria->where(array('class_key' => $className));
                    if ($this->getDebug() === true) {
                        $this->log(xPDO::LOG_LEVEL_DEBUG, "#2: Automatically adding class_key criteria 
                            for derivative query of class {$className} from base table class {$ancestor}");
                    }
                    break;
                }
            }
        }
    }
    return $criteria;
}


То есть, если в описании запрошенного класса нет указания таблицы (что с большой вероятностью говорит о том, что запрошенный класс — производный), то в условие автоматически добавляется условие class_key=$className.

К слову о баге: дело в том, что класс modResource наследуется не напрямую от класса xPDOObject, а от его производного modAccessibleObject, в котором метод loadCollection() переопределяется, без вызова родительского, и в этом методе не прописано $xpdo->addDerivativeCriteria($className, $criteria); То есть у нас не происходит автоматического добавления условия class_key. Если бы эта бага отсутствовала, то при запросе $modx->getCollection('msProduct', $q) xPDO автоматически бы добавил условие class_key=msProduct, и сделал бы выборку только записей с этим class_key. Это позволило бы избежать необходимости каждый раз прописывать $where = array('class_key' => 'msProduct'), как это сейчас делается в minishop2. При чем это касается как сниппетов, так и процессоров на выборки и т.п. (кстати, там есть тоже бага, о которой скажу чуть позже).

Василий, бери на заметку, это тебе скорее всего пригодится: баг пофиксят, но не все сразу обновятся. Чтобы не писать во всех местах условие $where = array('class_key' => 'msProduct'), можно добавить два статических метода в класс msProduct

public static function load(xPDO & $xpdo, $className, $criteria= null, $cacheFlag= true){
    if (!is_object($criteria)) {
        $criteria= $xpdo->getCriteria($className, $criteria, $cacheFlag);
    }
    $xpdo->addDerivativeCriteria($className, $criteria);
    return parent::load($xpdo, $className, $criteria, $cacheFlag);
}
public static function loadCollection(xPDO & $xpdo, $className, $criteria= null, $cacheFlag= true){
    if (!is_object($criteria)) {
        $criteria= $xpdo->getCriteria($className, $criteria, $cacheFlag);
    }
    $xpdo->addDerivativeCriteria($className, $criteria);
    return parent::loadCollection($xpdo, $className, $criteria, $cacheFlag);
}


Тогда при явных запросах $modx->getCollection('msProduct') условие class_key=msProduct будет автоматически добавлено, и будут возвращены только объекты msProduct. А при выборке $modx->getCollection('modResource') будут возвращены все объекты без разбора, включая msProduct.
Но при формировании чистого SQL-я это не поможет, так как эти методы просто не будут вызваны. Но можно формировать запросы так (правда это уж совсем на заметку):

$q = $modx->newQuery('msProduct');
$modx->addDerivativeCriteria('msProduct', $q);
$docs = $modx->getCollection('msProduct', $q);


Баг №2.
Второй баг касается метода xPDO::getCount(). Этот метод так же формирует запрос без учета метода xPDO::addDerivativeCriteria(), в результате чего можно получить неверное количество найденных строк. Это особенно критично для GetList — процесоров. Когда первый баг пофиксят, не надо будет в List-процессорах дописывать условия where class_key=$className, как это сейчас используется в minishop2. Но при этом, скорее всего процессор вернет правильное количество объектов, но неправильное число найденных строк, так как он сначала выполнит подсчет строк без учета class_key= (и просто найдет все строки по критерию), а уже потом выполнит запрос с учетом class_key.
Этот баг тоже будет пофиксен в ближайшее время.
Момент 3. Наследование
Итак, считаем, что у нас баги все пофиксены. Давайте теперь более внимательно рассмотрим наследование, и что это нам может дать (в том числе и ошибки).

Мы уже отметили, что делая выборку $modx->getCollection('modResource'), мы получим все объекты с различными class_key, а делая выборку $modx->getCollection('modDocument'), мы получаем только объекты с class_key=modDocument (напоминаю, что сейчас это не так из-за багов, но мы договорились считать, что баги пофиксены).
Такое поведение обусловлено тем, что в модели класс modResource четко описана таблица, и метод xPDO::addDerivativeCriteria() не добавляет условия class_key=$className, а в классе modDocument таблица не указана, и потому условие class_name=modDocument было автоматически создано.

К слову, если добавить в описание класса modDocument 'table'=>'site_content', то xPDO вернет все записи, и создаст положенные записи об ошибках в лог. Ну да ладно, это так, уточнение.

Итак, мы получаем довольно хороший механизм: мы можем создать единую таблицу для нескольких кастомных классов, хранить их записи в единой таблице, все объекты будут иметь уникальные ID, и нам не придется париться с написанием условий для выборки, все будет создаваться автоматически, и указывая в запросе базовый класс, мы будем получать все объекты, а указывая конкретный класс, будем получать объекты только этого класса. Просто обалденно! Но здесь есть еще один маленький момент. Рассмотрим его на примере все того же msProduct. Он у нас унаследован от класса modResource. Выполним вот такой запрос:

$q = $modx->newQuery('msProduct');
$modx->addDerivativeCriteria('msProduct', $q);
$docs = $modx->getCollection('modDocument', $q);


Получаем все ту же ошибку

Instantiated a derived class msProduct that is not a subclass of the requested class modDocument


Дело в том, что и modDocument, и msProduct — дочерние классы от modResource, но msProduct не является дочерним классом от modDocument. Это очень важно понимать, чтобы правильно планировать свою структуру наследуемых классов.

На этом пожалуй все. Надеюсь, материал кому-то был полезен.
61 комментарий
K
Kutuz27 26 августа 2014г в 09:43 #
Здравствуйте, это все понятно , а вот если мы захотим создать 2 класса наследуемые от 1 главного, да вот делать это все так чтобы поля в 2 производных ссылались на gxBox..
XPDO генерирует 3 таблицы 1 gxBox ,а в другие 2 таблицы просто унаследовались поля от родительской, а нам то надо чтобы gxBox была частью gxBoxWater или gxBoxAutomobil типо авто Join`ы, тут получилось мы наплодили таблицы а они не централизованы
как в такой ситуации поступать? есть конечно альтернатива создать 1 таблицу gxBox и 2 дополняющих (уже без наследования) в gxBox добавить 2 composite по 1 на таблицу и обозвать их соответствующим именем класса, создать колонку в gxBox говорящую какой класс join`ить
$box = $getObject('gxBox',1);
$target_class_object = $getObject($box->class_name,1)
K
Kutuz27 26 августа 2014г в 09:45 #
блок кода не отображается
Fi1osof1
Fi1osof 26 августа 2014г в 09:48 #
Выложите код на http://gist.github.com/
Fi1osof1
Fi1osof 26 августа 2014г в 09:48 #
А зачем вам разные таблицы?
И наследовать надо последовательно, а не два разных класса от одного родителя.
K
Kutuz27 26 августа 2014г в 09:56 #
Спасибо за ответы, Пример кода
тут скорее видно зачем разные таблици, просто опись полей разная , вот в чем дело, а таким путем ходим только потому что хотим централизованную таблицу, все же возможные вариации полей не всунеш в один gxBox, на деле полей более 30 только у центрального класса , у производных от 15 полей, все это дело должно иметь одну уникальную строку
Fi1osof1
Fi1osof 26 августа 2014г в 10:04 #
Понятно почему не сохранялся код. Теги вырезаются методом strip_tags(), только разрешенные проходят, то есть используется метод "что не разрешено - то запрещено". Теги из вашего XML-а не были в списке разрешенных. Добавил. Потом механизм поменяем на принцип "что не запрещено - то разрешено".

Кстати, советую вообще XML-описание модели не использовать. Создаете таблицы в базе данных и генерите модель пакетом CMPGenerator. Гораздо рульней получается.

Да, модели у вас разные, но вы тогда пытаетесь совместить несовместимое. У вас разные объекты, но пытаетесь вы их наследовать от одного класса, еще и таблицы разные используете... Я бы все-таки создал общую таблицу со всеми уникальными полями и рулил свойством class_key различные типы объектов.
K
Kutuz27 26 августа 2014г в 10:21 #
Да, модели у вас разные, но вы тогда пытаетесь совместить несовместимое. У вас разные объекты, но пытаетесь вы их наследовать от одного класса, еще и таблицы разные используете... Я бы все-таки создал общую таблицу со всеми уникальными полями и рулил свойством class_key различные типы объектов.

c 1 общей таблицей , страшно за расширяемость в дальнейшем
Fi1osof1
Fi1osof 26 августа 2014г в 10:26 #
страшно за расширяемость в дальнейшем

А это уже от конечной реализации зависит. Несколько дочерних классов от modResource вполне уживаются в одной таблице, хотя и поведение конечных объектов может местами сильно отличаться.
K
Kutuz27 26 августа 2014г в 10:18 #
Понятно почему не сохранялся код. Теги вырезаются методом strip_tags(), только разрешенные проходят, то есть используется метод "что не разрешено - то запрещено". Теги из вашего XML-а не были в списке разрешенных. Добавил. Потом механизм поменяем на принцип "что не запрещено - то разрешено".

мелочи такие а мозг затрахивают))
CMPGenerator крутая штука когда связей минимум, он связи вроде не генерирует, XML тоже неплох когда нужно видеть все и сразу в одном файле, потом просто распарсить схему, вот сейчас более 500 строк схемы в том числе конструктор планировок(зем уч-> строение(тип стен,материал крыши) -> помещения внутри(кв/м,тип ремонта,пол,потолок)/снаружи(балкон,терраса,виранда,мансарда) -> оборудование/комфорт ) и все поля типов ссылаются на одну таблицу с терминами и типами, там даже ссылка планируется на wiki описание, эксперементирую с компонентом недвижимости, там опись объектов(недвижимости) дикая , можно было конечно просто в поле description/content задать описание квартиры/зем.участка и т.д, делаю ориентируясь на автоматику , чтобы и выборка по критериям была мощной , а критериев уже не мало
Fi1osof1
Fi1osof 26 августа 2014г в 10:24 #
CMPGenerator крутая штука когда связей минимум, он связи вроде не генерирует

Да, связи не генерирует, приходится вручную прописывать. Но не вижу особой разницы между ручным прописыванием в XML и в уже конечный мап-файл. Хотя каждому свое. Все-таки да, перед глазами все видеть - хорошая штука. Было бы круто накидать визуальный редактор схем, типа как в редакторе phpMyAdmin, автоматизация тут просматривается :)

Недвига... О да, там связей и параметров хватает... Я вон http://www.aska-realty.ru/ программировал, насмотрелся.
Давно убедился - крупные проекты только вручную все, и только хардкод. Там одними готовыми решениями не обойтись.
K
Kutuz27 26 августа 2014г в 11:34 #
Хороший сайт, возьму на заметку), мне вручную писать больше нравиться нежели изучать готовое решение, зато там подглядеть можно, для спицифики думаю часто приходится вручную делать,
все-таки с таблицами с этими головняк, можно просто без наследования Git
как-то я выставил поле class_key(альтернатива class_alias в приведенном примере) у головной таблицы, так-вот все было супер выборка была сразу join`ом на указанную таблицу(класс) class_key, но были ошибки в логе, это и правильно т.к второстепенные классы не наследуются от головного, зато выбираются адекватно
K
Kutuz27 26 августа 2014г в 11:36 #
тоесть получается с class_key возможно решить такой вот нюанс с вторичными таблицами, но
Instantiated a derived class msProduct that is not a subclass of the requested class modDocument
меня убивает)
Fi1osof1
Fi1osof 26 августа 2014г в 13:19 #
Объясню суть ошибки:
msProduct расширяет класс modResource. Соответственно и запрос должен строиться с modResource:
$o = $modx->getObject('modDocument');

Если в данном случае будет получен объект msProduct, то будет эта ошибка, так как msProduct не является наследником modDocument.
K
Kutuz27 26 августа 2014г в 13:48 #
не совсем правильно вы меня поняли, msProduct не причем и вообще компонент minishop не причем

то что вы пишете было всегда ясно , "откуда в контейнере содержимое если его туда не положили" 'modDocument' 'msProduct'

я про то что добавляя поле class_key ,при получении объекта GetObject(target_class) xpdo найдя этот class_key независимо наследуется таблица или ни наследуется - без разницы , возьмет то что там написано и постарается join`ить автоматом этот класс если он сущевствует и дополнит набор полей в target_class с class_key класса, по target_class.id = class_key.id(в противном случае вообще выдаст фатал еррор о том что класса не сущевствует)

обратите внимание на схему:
<model package="gxTest" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">

	<object class="gxBox" table="gx_box" extends="xPDOSimpleObject">
		<field key="title" dbtype="varchar" precision="255" phptype="string" null="false"/>
		<field key="properties" dbtype="text" phptype="string" null="false"/>

		<field key="class_alias" dbtype="varchar" precision="255" phptype="string" null="false"/>

		<composite alias="gxBoxWater"       class="gxBoxWater"      local="id" foreign="id" cardinality="one" owner="local"/>
		<composite alias="gxBoxAutomobil"   class="gxBoxAutomobil"  local="id" foreign="id" cardinality="one" owner="local"/>
	</object>

	<object class="gxBoxWater" table="gx_box_water" extends="xPDOSimpleObject">
		<field key="pressure" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="speed" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="beasts" dbtype="varchar" precision="255" phptype="string" null="false"/>

		<aggregate alias="gxBox" class="gxBox" local="id" foreign="id" cardinality="one" owner="foreign"/>
	</object>

	<object class="gxBoxAutomobil" table="gx_box_automobil" extends="xPDOSimpleObject">
		<field key="wheels" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="has_truck" dbtype="tinyint" precision="1" phptype="boolean" null="false"/>
		<field key="truck_volume" dbtype="int" precision="11" phptype="integer" null="false"/>

		<aggregate alias="gxBox" class="gxBox" local="id" foreign="id" cardinality="one" owner="foreign"/>
	</object>

	<object class="gdBox" table="gd_box" extends="xPDOSimpleObject">
		<field key="title" dbtype="varchar" precision="255" phptype="string" null="false"/>
		<field key="properties" dbtype="text" phptype="string" null="false"/>

		<field key="class_key" dbtype="varchar" precision="255" phptype="string" null="false"/>

		<composite alias="gdBoxWater"       class="gdBoxWater"      local="id" foreign="id" cardinality="one" owner="local"/>
		<composite alias="gdBoxAutomobil"   class="gdBoxAutomobil"  local="id" foreign="id" cardinality="one" owner="local"/>
	</object>

	<object class="gdBoxWater" table="gd_box_water" extends="xPDOSimpleObject">
		<field key="pressure" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="speed" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="beasts" dbtype="varchar" precision="255" phptype="string" null="false"/>

		<aggregate alias="gdBox" class="gdBox" local="id" foreign="id" cardinality="one" owner="foreign"/>
	</object>

	<object class="gdBoxAutomobil" table="gd_box_automobil" extends="xPDOSimpleObject">
		<field key="wheels" dbtype="int" precision="11" phptype="integer" null="false"/>
		<field key="has_truck" dbtype="tinyint" precision="1" phptype="boolean" null="false"/>
		<field key="truck_volume" dbtype="int" precision="11" phptype="integer" null="false"/>

		<aggregate alias="gdBox" class="gdBox" local="id" foreign="id" cardinality="one" owner="foreign"/>
	</object>

</model>


в ней есть 6 классов по 3 , и того 2 варианта исполнения(gx/gd) такой структуры

при запросе:
$modx->getObject('gxBox')

мы получим только набор полей этой таблицы gx_box
для joina надо проделать:
$modx->getObjectGraph('gxBox','{gxBoxWater:{},gxBoxAutomobil:{}}')

тоесть присоединить к gxBox можно и water и automobil ,потому-что class_alias не имеет магии
при запросе:
$modx->getObject('gdBox')

нам вернется набор полей:
Array
(
[id] => 2
[wheels] =>
[has_truck] =>
[truck_volume] =>
[title] => Auto
[properties] =>
[class_key] => gdBoxAutomobil
)

обратите внимание на то что они спарены в месте, связи aggregate и Composite здесь ни при чем они просто помогают нам при добавлении addOne(), class_key - только это поле (правильно заполненное) повлияло на слияние, значит в нем есть магия
и пофигу что выборка происходит не от наследников и вообще здесь этого нет , но всеравно все ок

Instantiated a derived class gdBoxAutomobil that is not a subclass of the requested class gdBox
Fi1osof1
Fi1osof 26 августа 2014г в 14:07 #
Я честно скажу: как-то все очень сложно (во всяком случае при поверхностном осмотре). Вдаваться всерьез не стал, так как не вижу для себя практического применения. В тех схемах, которые я применяю и с теми SQL-запросами, которые в итоге формируются, у меня подобных ошибок не возникает.
K
Kutuz27 26 августа 2014г в 14:34 #
магия class_key поражает, жаль только что это не документировано
я подумал и склоняюсь больше к примеру с gxBox
K
Kutuz27 26 августа 2014г в 13:51 #
C
Codenator 26 августа 2014г в 12:52 #
http://schemaviewer.dev.kenters.com в помощ неплохо сделано для тех кто как я пишет xml schema ))))
Fi1osof1
Fi1osof 26 августа 2014г в 13:12 #
юзабельно :)
Fi1osof1
Fi1osof 26 августа 2014г в 14:42 #
магия class_key поражает, жаль только что это не документировано

Там много недокументированных возможностей :)
Вот, к примеру, меня вообще прёт:
$user = $modx->newObject('modUser');
$user->Profile = $modx->newObject('modUserProfile');
$user->save();

Без всяких ->addOne() и т.п.
K
Kutuz27 26 августа 2014г в 14:52 #
Это повод для раздела "Не документированное"))

меня больше поражает , для чего это
Fi1osof1
Fi1osof 26 августа 2014г в 15:02 #
Это повод для раздела "Не документированное"))

Для этого есть раздел Эксперименты и исследования

меня больше поражает , для чего это

Оооо, а это ппц как удобно бывает. Особенно не на создание, а на чтение. К примеру
$modx->getObject('modUser', $id)->Profile->email;

В любом месте на сайте можно писать $modx->user->Profile->$key или типа того, и вообще не париться был запрошен ранее объект профиля пользователя или нет. Если не был, xPDO сам выполнит $modx->user->Profile = $modx->user->getOne('Profile');
Если это не удобно, то что же тогда вообще удобно? А с учетом того, что мы все фигачим на modSmarty и у нас в Smarty доступен объект $modx, то тут удобства через край.
K
Kutuz27 26 августа 2014г в 15:07 #
Прямо из smarty такой строчкой, вау
Fi1osof1
Fi1osof 26 августа 2014г в 15:08 #
Вот именно.
K
Kutuz27 26 августа 2014г в 14:57 #
ваш фильтр тегов все режет
http://php.net/manual/ru/function.htmlentities.php
вот такое в XML что значит, видел пару раз , залез в документацию - там нету
Fi1osof1
Fi1osof 26 августа 2014г в 15:06 #
htmlentities нам здесь не совсем подходит, так как есть разрешенные HTML-теги, и если мы сейчас все без разбору будем преобразовывать в сущности, то у нас все будет выводиться как текст, а не HTML.
K
Kutuz27 26 августа 2014г в 15:11 #
я на это обратил внимание , и сразу подумал про замену и мини парсер вводимых пользователем разрешенных тегов типа [tagname blabla="" blaha=""]view this text here...![/tagname] так устроено в ModxTalks`е, а угловые скобки все в сущности
Fi1osof1
Fi1osof 26 августа 2014г в 15:15 #
Как я и говорил, с редакторами и т.п. - это мы чуть позже будем разбираться. Это вопрос, который надо будет изучать со всех сторон.
Сырой исходный передаваемый код тоже сохраняется, так что если что, я комменты подредактирую.
K
Kutuz27 26 августа 2014г в 15:21 #
баловство
Fi1osof1
Fi1osof 26 августа 2014г в 15:25 #
За такое баловство буду блочить :)
K
Kutuz27 26 августа 2014г в 14:58 #
[left bracket]param name="wmode" value="opaque"/[right bracket]
K
Kutuz27 26 августа 2014г в 16:22 #
так что же это за тег param в модели
Fi1osof1
Fi1osof 26 августа 2014г в 16:24 #
param name="wmode" value="opaque"

Вообще такие параметры прописывают во встраиваемых flash-объектах на страницах, влияет на поведение окна ролика.
K
Kutuz27 26 августа 2014г в 17:35 #
интересно, я про модель
K
Kutuz27 26 августа 2014г в 17:35 #
схему
C
Codenator 26 августа 2014г в 18:04 #
На самом деле если на schema руку набить то всё довольно быстро делается с помощи MIGXdb.
$user->Profile = $modx->newObject('modUserProfile');


Тут надо уже не MODX а сам PHP и ООП понимать.
Например:

class My {
public $var;
//в функции пользуемся так
function myfunc($text){
$this->var = $text;
}
}

$my= new My();
$my->myfunc('Мой текст');
echo $this->var;
// выведет Мой текст

$this->mystatic = "Статическая переменка";
// здесь мы види м что она нигде не прописана но создаётся автоматически и принадлежит класу.

всё просто
K
Kutuz27 26 августа 2014г в 18:12 #
это магические методы ООП php
<php class Test{
public $_fields = array();
public $_composites= array(
'Alias' => array(
//addition
),
);

public function __call(){}
public function __get($varname){
return $this->_cmposites[$varname]?$this->_cmposites[$varname]:$this->_fields[$varname];
}
public function __set($varname){

//Some....logic for add relationship object
}
}

$test = new Test();
$test->Alias = $object;
Fi1osof1
Fi1osof 27 августа 2014г в 07:12 #
$this->mystatic = "Статическая переменка";

Вот это совсем не статическая переменная. Статическая определяется параметром static и давно уже в php можно обращаться только через ::
class My {
public static $var;
function myfunc($text){
self::$var = $text;
}
}

$my = new My;
$my->myfunc("sdfsdf");

print $my->var; // PHP notice: Undefined property: My::$var
print $my::$var; // OK
C
Codenator 27 августа 2014г в 13:14 #
Может и правда я просто термин не нашёл для той переменки классовая? Глобальная?
Fi1osof1
Fi1osof 27 августа 2014г в 14:27 #
Это просто свойство объекта, не глобальное и ничего такого.
C
Codenator 27 августа 2014г в 15:50 #
спасибо так и запишем "свойство обьекта" )))))
Fi1osof1
Fi1osof 27 августа 2014г в 15:53 #
Не за что :)
Fi1osof1
Fi1osof 27 августа 2014г в 14:27 #
Вообще, можно еще уточнить что публичная переменная. Бывают еще protected и private.
C
Codenator 26 августа 2014г в 18:05 #
кажись я не разобрался как код вставлять правильно
C
Codenator 26 августа 2014г в 18:06 #
или просто в code достаточьно?
C
Codenator 26 августа 2014г в 18:16 #
<php 
//test
$born = naw Born();
?>

извиняюсь за спам просто чтото не получается код писать
K
Kutuz27 26 августа 2014г в 18:20 #
все нормально, просто редактор поста не до ума, избегай код писать , пока не поправят
C
Codenator 26 августа 2014г в 18:21 #
Так я на другом языке не говорю))) Вон по русски и то с ошибками ))))
K
Kutuz27 13 ноября 2014г в 07:32 #
как получить список классов packages`а?
Fi1osof1
Fi1osof 13 ноября 2014г в 08:21 #
Через API никак. Только если проходиться поиском по файловой системе. Но есть в корне пакета meta-файл, в котором могут быть перечислены классы, его вот можно использовать.
K
Kutuz27 13 ноября 2014г в 09:26 #
Спасибо николай, решилось парсингом schema файла , все это нужно было для remove/create ObjectContainer для облегчения редактирования schema (в целевом компоненте все отталкивается от schema) и в случае каких либо умышленных изменений схемы, быстрой синхронизации schema с XPDO мапами и mysql таблицами через API компонента.
А уже на этапе работы в рамках самого компонента, можно использовать сгенерированый из той же схемы $xpdo_meta_map массива
мой велосипед выглядит так.
K
Kutuz27 13 ноября 2014г в 09:27 #
все-же беда тут с кодом у вас))
Fi1osof1
Fi1osof 13 ноября 2014г в 13:23 #
Подправил коммент, выложил код на гист.
Fi1osof1
Fi1osof 13 ноября 2014г в 13:24 #
Да, это велосипед :)
Я, к примеру, вообще XML-схему не составляю и не прикладываю к пакету.
M
MisterN 13 ноября 2014г в 13:30 #
вообще XML-схему не составляю и не прикладываю к пакету.

К полному моему охереванию.
Fi1osof1
Fi1osof 13 ноября 2014г в 17:06 #
Антон, давай постараемся без выражений.
По делу: XML-схема не имеет обязательного назначения. Она используется только для генерации Map-файлов. Если я эти файлы создаю сам (в чем успешно помогает CMPGenerator), то мне этот XML не нужен. А в процессе работы MODX Revo его для себя никак не использует.
K
Kutuz27 13 ноября 2014г в 17:13 #
согласен, схема больше носит описывающий характер
K
Kutuz27 13 ноября 2014г в 17:12 #
схема удобно когда пакет объектов не маленький(много связей) , по моему схема для меня один из приоритетных файлов описывающий абстрактно весь компонент, я только от нее отталкиваюсь когда осматриваю в общем весь компонент в целом
K
Kutuz27 13 ноября 2014г в 17:14 #
т.к с нее произвожу регенерацию мапы и таблиц =)
K
Kutuz27 13 ноября 2014г в 10:56 #
копаюсь и немогу разобраться , допустим у нас есть 10 таблиц они все между собой связаны,
1 таблица является главной , остальные это обстрактно часть иерархии к этой главной таблице,
так вот задача такая что когда мы создаем 1 строку в главной таблице, мы отсылаем с формы данные в сумме состовляющие структуру данных этих 10 таблиц, нам надо обработать , проверить эти данные и уже потом сейвить главный объект и всю под иерархию,
простные связи Aggregate`сы главного объекта забитые в addOne addMany не могут сейваться через $main->save(),
с этим и вся проблема, приходится под иерархию сохранять а потом только главный объект вставляя айдишники на детя в материнские объекты,
решение было бы в использовании транзакцию во время валидации структуры, но как мы знаем modX не любит innoDB и транзакции нам труднодоступны
Fi1osof1
Fi1osof 13 ноября 2014г в 13:27 #
простные связи Aggregate`сы главного объекта забитые в addOne addMany не могут сейваться через $main->save(),
с этим и вся проблема, приходится под иерархию сохранять а потом только главный объект вставляя айдишники на детя в материнские объекты,

Очень даже могут. Вы просто что-то не так в своих связях прописали. Скорее всего напутали с owner-ом. Изучайте внимательно этот топик.

P.S. Пошел оффтоп. Пишите свой топик с описанием всех вопросов и задач и там уже общение давайте наводить, так как здесь мы вполне конкретную статью сейчас загружаем неконкретными комментариями.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.