Добрый вечер, сегодня я уже задавал вопрос и у меня появился еще пару после ознакомления с интернет магазином… 1)В каталоге есть Ноутбуки и при выборе ноутбука там есть описание(в админке) почему оно не отображается в описании товара ? 2)При нажатии на картинку товара она открывается в странице (чисто картинка ) это как то не правильно мне кажется, как можно сделать так чтобы картинка открывалась в сплывающем окне ? (окно на фоне сайта и чтобы его можно было закрыть на крестик)
Понят но дело что под каждую задачу выбирается свой инструмент. Для списка пользователей работа с объектам вообще не обязательна (в смысле, с объектами пользователей), просто выполнил запрос к БД и вывел данные. Конечно же в данном случае join-ы в помощь.
В случаи работы с update пользователя и его профиля очень удобно, а вот если список пользователей вывести нужно, не лучше ли это через join делать?
Материал для экспертов. Сразу говорю, что материал довольно объемный и сумбурно написанный, так как очень много взаимосвязей здесь и сложностей, каждая из которых тянет на отдельные топики. Про какие-то из них я писал (и буду на них ссылаться), а какие-то являются только недавно изученными, но буду описывать их кратко. Практической пользы от этого материала скорее всего маловато, ибо мало кто это будет применять, но если кто-то все-таки столкнется, скорее всего это поможет сэкономить очень много времени. Для начала практический пример, чтобы понимать сразу о чем речь и куда мы будем копать. У Ильи Уткина есть хорошая статья, описывающая принципы методов xPDOObject::getMany() и xPDOObject::getOne(). Методы эти держатся на связях xPDO-объектов, прописанных в их мап-файлах. К примеру, есть класс SocietyTopic (расширенный modResource). Есть класс SocietyBlogTopic (для связи Блог-Топик). Все примеры здесь и далее из реальной практики на основе сайта MODX-Клуба. Итак, у топика может быть несколько связей Блог-Топик, то есть топик может находиться в нескольких блогах одновременно. В мап-файле топика прописаны эти связи: 'composites' =>
array (
// ....
'TopicBlogs' =>
array (
'class' => 'SocietyBlogTopic',
'local' => 'id',
'foreign' => 'topicid',
'cardinality' => 'many',
'owner' => 'local',
),
), Здесь TopicBlogs - это алиас (псевдоним) связи, class - имя класса связанного объекта, local - имя колонки первичного ключа в текущем объекте, foreign - имя колонки вторичного ключа в связанном объекте, cardinality - тип связи (one - один-к-одному, many - один-ко-многим), owner - "владелец" первичного ключа. Вот "владелец" - это как раз и будет наш главный объект текущих исследований, и поговорим о нем плотно чуть дальше. Итак, связи у нас прописаны. Что же это нам дает? Посмотрим вот на этот код: $topic = $modx->getObject('SocietyTopic', $id);
foreach($topic->getMany('TopicBlogs') as $topicBlog){
print_r($topicBlog->toArray());
} В данном случае мы получили объект нужного нам топика, после чего получили связанные с ним объекты по алиасу TopicBlogs. xPDO выполнил в этом случае xPDO::getCollection(), в котором на основе данных из мап-файла подставил имя класса и условие поиска по первичному-вторичному ключу. На самом деле очень удобно. Этот код можно написать и более лаконично: $topic = $modx->getObject('SocietyTopic', $id);
foreach($topic->TopicBlogs as $topicBlog){
print_r($topicBlog->toArray());
} Про данную магию я писал здесь. Советую тот топик изучить очень внимательно, так как от понимания его очень сильно зависит понимание дальнейшего материала в этом топике. Итак, двинем дальше к нашей цели. Для этого рассмотрим вот такой код: $topic = $modx->newObject('SocietyTopic', $topicdata);
$blog = $modx->newObject('SocietyBlog', $blogdata);
$topic_blog = $modx->newObject('SocietyBlogTopic');
$topic_blog->Blog = $blog;
$topic->TopicBlogs = $topic_blog;
$topic->save(); Что здесь происходит?
Создаем новый объект топика.
Создаем новый объект блога.
Создаем новый (пока еще пустой) объект связки Блог-Топик.
Добавляем в объект-связку объект блога, как связанный объект.
Добавляем этот объект-связку к объекту топика, опять-таки как связанный объект.
Сохраняем объект топика. Обратите внимание, что сохраняем мы только один объект - топик. А остальные объекты? А остальные объекты сохраняются как связанные с ним автоматически. Давайте чуть подробней на этом остановимся, и за одно выясним главные преимущества этого метода. Смотрите, когда мы только еще создаем новые объекты, нам не известны их id-шники (так как они еще не сохранены в базу данных). Конечно, мы могли бы выполнить запрос к БД, чтобы получить значения максимальных id-шников из этих таблиц, но это все равно не круто. Итак, вот у нас есть объект $topic_blog, в нем, пока еще объекты не сохранены в БД и нам не известны их id-шники, вторичные ключи не имеют значений, то есть topicid = null и blogid = null. По логике мы должны здесь сначала сохранить объект топика, потом сохранить объект блога, затем их айдишники присвоить объекту связки Блог-Топик, после чего уже и сохранить объект связки Блог-топик. Так-то оно так, но вот вопрос в том, в какой момент сохранить этот объект блога? Если у нас вот такой вот локальный код, то проблемы в этом нет, а если это у нас, к примеру, расширяемый create-процессор? То есть мы там прописали сохранение блога, сохранили, а этот процессор расширили, добавили дополнительные проверки и решили прервать выполнение процессора по какой-то причине. А объект блога уже создан... А связки его с топиком нет... Вот как раз механизм связанных объектов эту проблему и решает. То есть только тогда, когда основной объект отправляется на сохранение, тогда уже механизм xPDO обеспечивает автоматическое сохранение всех связанных в нем объектов. Здесь я писал, что за это отвечает метод xPDOObject::_saveRelatedObjects(), вызываемый внутри метода xPDOObject::save(), при чем дважды. Для чего дважды? Давайте пошагово: Сохраняем объект топика (то есть вызываем $topic->save()). У топика еще нет id-шника, пока его данные не были записаны в базу данных, а в начале метода $this->save() они еще не записаны, там еще только в первый раз выполняется метод $this->_saveRelatedObjects(), который должен сохранить объект связки Блог-Топик. Итак, этот объект связки Блог-Топик сохраняется, при этом работает тот же самый механизм сохранения связанных объектов, который прежде сохранения самого объекта связки Блог-Топик сохранит связанный с ним объект блога. Блог сохранится (в нем в данный момент нет связанных объектов, поэтому он сразу записывается в базу данных), и у блога есть свой id-шник. Далее, по ходу выполнения функции сохранения связки Блог-Топик, этот объект получает значение первичного ключа объекта блога и присваивает себе в качестве вторичного ключа (в нашем случае это $this->blogid = $blog->id). Таким образом у объекта связки Блог-Топик уже есть id-шник Блога. Но у него пока еще нет значения id топика, ведь топик не является его связанным объектом в текущий момент, а сам топик еще не сохранен. В текущий момент объект связки Блог-Топик записывается в БД с ключами blogid => "id блога", topicid => 0 (так как в колонке не разрешены null-значения, а реального значения еще нет). Идем дальше по процессу сохранения объекта топика. Его связанный объект Блог-Топик уже сохранен, и в данный момент выполняется сохранение в базу данных самого объекта Топика. Как только он сохранился, у него есть свой ID-шник. И вот в этот момент выполняется повторное сохранение связанных объектов (то есть выполнение метода $this->_saveRelatedObjects()). И вот теперь, когда у топика есть свой id, топик присваивает его объекту связки Блог-Топик в качестве вторичного ключа topicid и сохраняет этот связанный объект (выполняет update уже имеющейся в базе данных записи). И вот теперь у нас в базе данных все три объекта со всеми первичными и вторичными ключами :) Но все это я объяснил в простой разговорной форме, и у наблюдательного читателя (как это часто пишут в книгах :)) должен возникнуть вопрос "а на основании чего вообще объект связки Блог-Топик решает, что ему надо получить значение id блога, чтобы присвоить его себе в качестве blogid, а объект топика решает, что свой id-шник надо принудительно присвоить в качестве topicid объекту Блог-Топик?". А вот за это как раз и отвечает мап-файл и в частности значение переменной owner в описании связей с другими объектами. И с этим надо очень серьезно разобраться, так как неверное указание значения этой переменной может повлиять на то, что значения вторичных ключей вообще не будут установлены, и связанные с этим коварные последствия мы как раз и рассмотрим чуть ниже. Вообще, по задумке разработчиков MODX-а, можно было бы в большинстве случаев вообще не указывать значение переменной owner, но с этим есть бага, которая выставляет прямопротивоположные значения)). Пуллреквест я уже отправил. Итак, правило довольно простое: "Если это главный объект, содержащий первичный ключ, и значение этого ключа должно быть присвоено вторичному объекту, то owner=>local. А если наоборот, объект при сохранении должен принять id-шник связанного объекта и присвоить себе в качестве вторичного ключа, то тогда owner=>foreign". Если это правило не соблюсти, то при сохранении связанного объекта вторичный ключ может вообще не присвоиться. А вот сейчас перейдем к самой главной заморочке, из-за которой мне и пришлось так подробно изучить весь этот хоть и удобный, но крайне сложный механизм, ибо у меня при сохранении объектов бушевал Ктулху))) Итак, ситуация, которая на несколько часов меня заморочила: есть у нас уже готовый топик, отнесенный к некоему блогу. И вот при редактировании этого топика (здесь, на странице редактирования), я хочу ему сменить блог, в который его занесли. Все ОК, обновление топика проходит успешно и без ошибок, но вот только связка Блог-Топик не меняется. При чем самое интересное то, что раньше работало, а тут "вдруг" перестало работать. Раньше код в update-процессоре был примерно следующий (когда работать перестало): foreach($TopicBlogs as & $TopicBlog){
$TopicBlog->blogid = $blogid;
} И вот объект топика сохранялся нормально, а связка Блог-Топик нет. При чем уже доходило до смешного. Делал вот так: foreach($TopicBlogs as & $TopicBlog){
$TopicBlog->blogid = $blogid;
print_r($TopicBlog->toArray()); // Здесь выводятся корректные данные
$TopicBlog->save();
print_r($TopicBlog->toArray()); // А вот здесь уже опять данные с id исходного блога
exit;
} То есть перед самым сохранением данные нужные, а сразу после сохранения объекта связки ключ блога в ней восстанавливается. Я уже думал, что где-нибудь выше по коду текущего или расширяемого процессора я добавил связи и что они и перебиваю все, и сделал так: $topic = $modx->getObject('SocietyTopic', $id);
foreach($topic->TopicBlogs as & $TopicBlog){
$TopicBlog->blogid = $blogid;
print_r($TopicBlog->toArray()); // Здесь выводятся корректные данные
$TopicBlog->save();
print_r($TopicBlog->toArray()); // А вот здесь уже опять данные с id исходного блога
exit;
} Вот здесь связка TopicBlogs вообще чистая, без лишних связанных объектов (я никаких объектов к ней не добавлял и не пытался их получить), но эффект тот же самый... Как же так? Но как оказалось, я только думал, что эта связка чистая. А на самом деле... Совсем недавно я написал замечательный топик про проверку доступов к xPDO-объектам, и там демонстрировал расширение этих классов и продемонстрировал свой класс топика, в котором прописана кастомная проверка прав к объекту. Нет, ошибки в том топике нет, и проверки все прописаны корректно, но как раз в том коде и крылась разгадка всей этой заморочки, а именно вот в этих строчках: foreach((array)$this->TopicBlogs as $topicblog){
if(
$blog = $topicblog->Blog
AND $blog->checkPolicy($criteria, $targets, $user)
){
$hasBlogAccess = true;
break;
}
} То есть еще в момент получения топика $topic = $modx->getObject('SocietyTopic', $id), когда выполняется проверка прав на этот объект, уже тогда подгружаются объекты связок Блог-Топик этого топика и их объекты блогов. И вот когда я в обновлении топика менял значения blogid в связках Блог-Топик, то при сохранении эти значения перезаписывались id-шниками уже имеющихся связанных объектов блогов, ибо owner=>"foreign", и есть в наличии связанный объект. Вот в этом и крылась разгадка восстановления значений в объекте-связке при сохранении :) А как же тогда в таких случаях менять значения вторичных ключей? А здесь просто надо перетирать связанный объект. В нашем случае код будет выглядеть так: foreach($TopicBlogs as & $TopicBlog){
$TopicBlog->Blog = $this->modx->getObject('SocietyBlog', $blogid);
} Вот такой получился квест... Один из самых сложных за мою практику.
Вполне возможно. Я уже добавил апдейт в нее.
Поверьте, эту статью и спустя год читают. Думаю, что далеко не я один.
Статья была написана больше года назад. На тот момент там даже на бесплатных аккаунтах sftp работало. Сейчас да, не актуально. Добавлю пометку в топик.
Хост modxcloud конечно классный, но хорошо бы было обозначить тот момент, что в бесплатном варианте он абсолютно бесполезен. Разве что только посмотреть как там, без проблем, устанавливается ShopModxBox. Кроме дампа БД оттуда ничего больше не заберешь. Даже файлы не скачать. Через панель файловой системы в админке они видны, а FTP менеджером их хрен скачаешь. Не видит их менеджер и все.
Вот и здорово :) Только ht.access тут не при чем. Он с таким названием вообще не учитывается и не используется. Просто лежит для примера (поставляется вместе с дистрибутивом MODX-а). А вот когда вы его переименовываете в .htaccess, то этот файл уже подхватывается сервером Apache и используются прописанные в нем конфигурации, в том числе и правила подмены УРЛов.
Спасибо ! так и было До ht.access после исправления на .htaccess все за работало !