MODX REVO API как при добавлении ресурсов из массива пропустить дубликаты?
Приветствую, подскажите пожалуйста, вопрос скорее про php больше чем API modx revo, но только учусь, и не могу понять как пропустить дубли ресурсов при добавлении через API.
Есть некий массив $usersMedia['data'] с полями.
Через API MODX REVO добавляю ресурсы в цикле, все ок, но встречаются одинаковые страницы в массиве.
Я их решил исключить по уникальному ID которое при создании сохраняю в TV поле idpost
Сделал так.
Как исключить добавление уже добавленных страниц? По уникальному IDPOST
Есть некий массив $usersMedia['data'] с полями.
Через API MODX REVO добавляю ресурсы в цикле, все ок, но встречаются одинаковые страницы в массиве.
Я их решил исключить по уникальному ID которое при создании сохраняю в TV поле idpost
Сделал так.
if(!$docs = $modx->getCollection('modResource', array(
'parent' => 2, //родитель где уже есть добавленные ресурсы
'published' => 1,
'deleted' => 0,
'searchable' => 1
))){return;}
foreach($usersMedia['data'] as $media){
foreach($docs as $doc){
$issetidpost = $doc->getTVValue('idpost'); //получаю TV с уникальным id записи в уже созданных страницах
if($issetidpost != $media['id']){ //проверяю если в уже существующих страницах в TV поле idpost есть поле новой страницы, то ее не добавляю, пропускаю.
//добавляю ресурс
$rss = $modx->newObject('modResource');
$rss->set('template', 2); // Назначаем ему нужный шаблон
$rss->set('isfolder', 1); // Указываем, что это не контейнер
$rss->set('published', 1); // Неопубликован
$rss->set('createdon', time()); // Время создания
$rss->set('pagetitle', $media['title']); // Заголовок
$rss->set('content', $media['caption']); // Контент
$rss->set('alias', strtolower($media['username'].'-'.$media['id'])); // Псевдоним
$rss->set('parent', 2); // Родительский ресурс
$rss->save();
$nid = $rss->get('id'); //получаем ID созданного ресурса
$idpost = $modx->getObject('modTemplateVar',array('name'=>'idpost')); // Указываем имя нужного TV
$idpost->setValue($nid, $media['idpost']); // Записываем в TV значение
$idpost->save();
unset($rss);
unset($idpost); // Удаляем переменные
$modx->cacheManager->clearCache(); // Кэш тоже чистим
////
}
}
}
Но к сожалению моя проверка IDPOST в существующих страницах и сравнения со добавляемой страницей не работает, страницы добавляются повторно. Как исключить добавление уже добавленных страниц? По уникальному IDPOST
Комментарии: 39
Так $idpost содержит всего одно значение и это всегда значение предыдущей страницы, т.е. вероятность того, что у вас подряд идут два одинаковых id крайне мала. Далее, зачем вообще вам idpost, если гораздо логичнее перед добавлением нового ресурса проверять есть ли ресурс с таким pagetitle и если есть, то не добавлять? И getCollection лучше заменить на getIterator так как вам все объекты разом не нужны. И ещё, чистить кеш всего сайта в цикле не кажется мне хорошей идеей.
Вы все правильно понимаете, да, но как правильно проверить на pagetitle или idpost???
Это все уникальные поля. idpost в этом поле id с другого сервиса, он уникальный так же как и pagetitle. НО pagetitle может и повториться теоретически.
Это все уникальные поля. idpost в этом поле id с другого сервиса, он уникальный так же как и pagetitle. НО pagetitle может и повториться теоретически.
Если у вас будет повторяться pagetitle, то modx будет ругаться, оно вам надо? Думаю, нет. А проверить элементарно. Если я правильно понял, $usersMedia['data'] содержит массив полей, из которых вы создаёте ресурс, значит надо в цикле делать прямой запрос в БД через newQuery, где в условии ставить pagetitle=$usersMedia['data'][поле которое помещается в заголовок ресурса]. Если запрос вернёт хотя бы одно значение значит, такой ресурс уже есть и надо его либо обновить, либо пропустить и продолжить выполнение цикла. Как сделать запрос в БД подскажет Гугл ключевые слова modx xpdo sql. Ну а дальше уже всё как сейчас. Либо можно поступить проще, но если ресурсов много, то это может быть неоптимальным решением с точки зрения потребления ресурсов, просто попытаться получить объект
$resource=$modx->getObject ('modResource', array('pagetitle'=>$usersMedia['data']['fieldname']));
if(!$resource){
//Создаём новый ресурс
}
<code>
к сожалению не работает, на странице где вызываю сниппет, обновил страницу два раза, добавились страницы одни и те же два раза
сделал так
сделал так
foreach($usersMedia['data'] as $media){
$resource=$modx->getObject ('modResource', array('pagetitle'=>$media['title']));
if(!$resource){
//Создаём новый ресурс
$rss = $modx->newObject('modResource');
$rss->set('template', 2); // Назначаем ему нужный шаблон
$rss->set('isfolder', 1); // Указываем, что это не контейнер
$rss->set('published', 1); // Неопубликован
$rss->set('createdon', time()); // Время создания
$rss->set('pagetitle', $media['title']); // Заголовок
$rss->set('content', $media['caption']); // Контент
$rss->set('alias', strtolower($media['username'].'-'.$media['id'])); // Псевдоним
$rss->set('parent', 2); // Родительский ресурс
$rss->save();
////
}
}
Вообще-то должно работать. Проверьте что находится в $media['title'] и в $resource->get('pagetitle'), может там пробелы какие или спецсимволы или ещё что-то и значения не совпадают. Я в коде ошибки не вижу, а то что проверка должна работать это факт.
А можно вместо title все таки сравнивать в существующих страницах с полем TV idpost а в новых $media['id']?
Просто в этом поле уникальных номер такой например 18073012534211706
Просто в этом поле уникальных номер такой например 18073012534211706
Да можно, в принципе, но получить ресурс по TV сложнее. Где-то у вас ошибка, и вам нужно её найти. Выведите в лог входные данные и пришлите сюда, посмотрим.
Но мне не нужно получать ресурс по TV, смысл такой, при создании в цикле, я смотрю в папку parent 2 ВСЕРЕСУРСЫ, смотрю tv idpost, и сравниваю его с новым добавляющимся ресурсом с таким же полем. Если среди ресурсов есть ресурс с таким же значением, пропустить.
Так вот, для чего вы получали $docs. Это конечно ваш код, но на мой делетантский взгляд, такой подход нерационален. Вам нужно создать TV, в цикле его получать, преобразовывать в массив, проверять есть ли в массиве текущий id, если нет, то создавать ресурс и добавлять новый id в массив, массив преобразовывать а строку, строку записывать в tv и сохранять изменения. Вам не кажется что это избыточный путь?
Да да да, я тоже сейчас понимаю что два цикла это неправильно, основной цикл перебор массива полей для новых ресурсов, и в нем я еще раз запускаю цикл, который смотрит все ресурсы и сравнивает поле нового ресурса со старым, и решает если нет ресурса с таким же значением в поле то добавлять. Поэтому думаю и не работает. Одна итерация, с одной записью.
НО я НЕ ЗНАЮ как в массиве через in_array проверить значение в TV поле. Не так силен в php
НО я НЕ ЗНАЮ как в массиве через in_array проверить значение в TV поле. Не так силен в php
Да не нужно вам это TV, выше уже написал почему))
Вот весь код который нужен
Вот весь код который нужен
foreach($usersMedia['data'] as $media){
$resource=$modx->getObject ('modResource', array('pagetitle'=>$media['title']));
if(!$resource){
//Создаём новый ресурс
$rss = $modx->newObject('modResource');
$rss->set('template', 2); // Назначаем ему нужный шаблон
$rss->set('isfolder', 1); // Указываем, что это не контейнер
$rss->set('published', 1); // Неопубликован
$rss->set('createdon', time()); // Время создания
$rss->set('pagetitle', $media['title']); // Заголовок
$rss->set('content', $media['caption']); // Контент
$rss->set('alias', strtolower($media['username'].'-'.$media['id'])); // Псевдоним
$rss->set('parent', 2); // Родительский ресурс
$rss->save();
////
}
}
Понял :) так работает, но все таки как при таком варианте ограничить по parent можно? И все таки сравнивать не title a tv.
Там где получаете ресурс в массив добавьте ещё один элемент с ключом parent вот и будет вам ограничение по родителю. А про tv умоляю вас, забудьте, они не для этого, для программной работы с ресурсами используйте поля описанные в модели их обычно хватает, а tv это для дополнительной информации когда прям без вариантов. В вашем случае лучше писать уникальный id в pagetitle.
Спасибо большое, но не могу id писать в pagetitle, это индексируется поисковиками, не должно быть лишнего в заголовке.
с ключом parent не понял, в modResource можно только id указать, написал так
$resource=$modx->getObject ('modResource', 2, array('pagetitle'=>$media['title']));
с ключом parent не понял, в modResource можно только id указать, написал так
$resource=$modx->getObject ('modResource', 2, array('pagetitle'=>$media['title']));
$resource=$modx->getObject ('modResource', array('pagetitle'=>$media['title'], 'parent' => 2));
Индексируется страница, а на странице можно вывести например longtitle.
Индексируется страница, а на странице можно вывести например longtitle.
$userMedia откуда берётся?
Это из сервиса другого, такой массив прилетает, там просто поля с данными, я просто его распечатываю foreach и все. Тут проблем нет, эти поля записываю уже в MODX, например [id] => 17866422587162642 записываю в TV idpost при создании ресурса
Array
(
[data] => Array
(
[0] => Array
(
[id] => 17866422587162642
[media_url] =>
)
[1] => Array
(
[id] => 18073012534211706
[media_url] =>
)
[2] => Array
(
[id] => 17878486537701170
[media_url] =>
)
)
)
Если так хочется использовать уникальный id, то записывайте его в pagetitle, поскольку это поле должно быть уникальным, как я уже говорил и делайте проверку, о которой я уже писал, не усложняйте. Я понимаю, что сейчас это не работает, но нужно искать ошибку, а не усложнять решение.
Я бы вначале удалил дубли из самого массива $usersMedia['data'], а результат, который заведомо без дублей, уже перебирал бы форычем, вот тут хороший пример.
Дело в том что дублей как раз в $usersMedia нет, дубли получаются при добавлении в MODX, я вызываю снипет на странице. Если обновлю страницу два раза, страницы добавятся одни и те же. Вот пытаюсь при добавлении пропускать уже добавленные страницы. Сравнивая поле у новых страниц с таким же молем у старых, и что то не получается моя проверка не срабатывает :(
Я понял) Внутренний форыч по существующим ресурсам с проверкой внутри не подходит. Нужно на каждой итерации массива $usersMedia['data'] одним запросом проверить, есть ли такое TV- поле в ресурсах указанного родителя. К примеру, через newQuery составить запрос. И если поля нет, то создавать ресурс.
Да, я тоже подозреваю что в foreach при добавлении я запускаю еще один foreach пробегая по существующим ресурсам это не правильно как то. Можно пример с newQuery?
Я думаю надо как то смотреть наличие поля в массиве в целом, но не понимаю как tv в массиве посмотреть без цикла :(
Я думаю надо как то смотреть наличие поля в массиве в целом, но не понимаю как tv в массиве посмотреть без цикла :(
Пришлите целиком код сниппета
Вот код сниппета, убрал код API другого ресурса откуда массив заполняется, он не нужен, сам массив для примера оставлю, но тут все хорошо, ресурсы добавляются поля заполняются
Array
(
[data] => Array
(
[0] => Array
(
[id] => 17866422587162642
[media_url] =>
)
[1] => Array
(
[id] => 18073012534211706
[media_url] =>
)
[2] => Array
(
[id] => 17878486537701170
[media_url] =>
)
)
)
foreach($usersMedia['data'] as $media){
////
$rss = $modx->newObject('modResource');
$rss->set('template', 2); // Назначаем ему нужный шаблон
$rss->set('isfolder', 1); // Указываем, что это не контейнер
$rss->set('published', 1); // Неопубликован
$rss->set('createdon', time()); // Время создания
$rss->set('pagetitle', $media['title'); // Заголовок
$rss->set('content', $media['caption']); // Контент
$rss->set('alias', strtolower($media['username'].'-'.$media['id'])); // Псевдоним
$rss->set('parent', 2); // Родительский ресурс
$rss->save();
$nid = $rss->get('id'); //получаем ID созданного ресурса
$idpost = $modx->getObject('modTemplateVar',array('name'=>'idpost')); // Указываем имя нужного TV
$idpost->setValue($nid, $media['id']); // Записываем в TV значение
$idpost->save();
unset($rss);
unset($idpost);
$modx->cacheManager->clearCache(); // Кэш тоже чистим
////
}
А где проверка? Удалили? Или и не добавляли?
Да, удалил свой второй цикл в основном цикле.
Какой второй цикл, его там быть не должно. Надо перебрать только $userMedia['data']
Я сейчас не у компа, а код писать со смартфона — так себе занятие… Завтра постараюсь пример набросать. Если ещё будет актуально)
Пока что предлагаю такой вариант: отдельным циклом пройтись по всем ресурсам родителя, все значения их tv -полей забить в отдельный массив. И потом уже — перебирая основной массив с данными сервиса — проверять через in_array, есть ли в массиве tv-шек значение элемента $media['id']. Соответственно, если нет — создаем новый ресурс.
Обращаю внимание, что массив всех tv-шек извлекаем в цикле ДО начала цикла с данными сервиса.
Обращаю внимание, что массив всех tv-шек извлекаем в цикле ДО начала цикла с данными сервиса.
В общем, как-то так:
Не проверял! По идее, должно сработать.
<?php
$parent_id = 2; // выносим id родителя в переменную
$tv_id = 6; // тут указать id своего tv-поля
// проверяем наличие ресурсов в родителе
$c = $modx->newQuery('modResource');
$c->where(['parent' => $parent_id, 'published' => 1, 'deleted' => 0, 'searchable' => 1]);
$count = $modx->getCount('modResource', $c);
if($count == 0) return;
// вытаскиваем массив значений tv-полей ресурсов указанного родителя
$q = $modx->newQuery('modResource');
$q->leftJoin('modTemplateVarResource', 'TVS', 'modResource.id = TVS.contentid AND TVS.tmplvarid = '.$tv_id);
$q->select('TVS.value');
$q->where(['parent' => $parent_id]);
if ($q->prepare() && $q->stmt->execute()) {
$tvs = $q->stmt->fetchAll(PDO::FETCH_COLUMN);
}
//убираем пустые элементы массива tv-полей
$tvs = array_diff($tvs, array(''));
foreach($usersMedia['data'] as $media){
// проверка наличия $media['id'] в массиве $tvs
if (in_array($media['id'], $tvs)) {
//добавляю ресурс
.......
}
}
//очистку кеша выносим из цикла
$modx->cacheManager->clearCache();
Не проверял! По идее, должно сработать.
Ошибочка:
так должно быть
if (!in_array($media['id'], $tvs)) {
//добавляю ресурс
.......
}
так должно быть
Может быть вы мне объясните, зачем tv и зачем проверять наличие ресурсов в родителе?
«зачем проверять наличие ресурсов в родителе?»
Ну, в исходном скрипте есть проверка через getCollection, я ХЗ зачем она, спросите автора топика.
«зачем tv»?
А чем не вариант? Есть много реализаций, к примеру, импорт из 1С, где в отдельную тивиху сохраняли ID товара из файла импорта, как уникальное поле — skrinshoter.ru/s/250121/tgpRylds
Ну, в исходном скрипте есть проверка через getCollection, я ХЗ зачем она, спросите автора топика.
«зачем tv»?
А чем не вариант? Есть много реализаций, к примеру, импорт из 1С, где в отдельную тивиху сохраняли ID товара из файла импорта, как уникальное поле — skrinshoter.ru/s/250121/tgpRylds
Ну вариант, конечно, когда полей много и стандартных не хватает, а тут-то зачем? Ну да ладно, хочется автору через tv пусть будет так))
На самом деле, я тоже стараюсь не плодить TV без надобности. Но многие клиенты прямо настаивают, чтобы в отдельной вкладочке все настройки ресурса были, привыкли к доп. полям с категориями.
Есть такие)))
Да, именно, у меня такая же ситуация, сторонний сервис как 1C, и приходиться в tv отдельную писать уникальные их id.
Пишите, если приходится.
Благодарю!
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.