MODX REVO API как при добавлении ресурсов из массива пропустить дубликаты?

Приветствую, подскажите пожалуйста, вопрос скорее про php больше чем API modx revo, но только учусь, и не могу понять как пропустить дубли ресурсов при добавлении через API.

Есть некий массив $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
Роман
24 января 2021, 20:08
modx.pro
1 120
0

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

Артур Шевченко
24 января 2021, 21:27
0
Так $idpost содержит всего одно значение и это всегда значение предыдущей страницы, т.е. вероятность того, что у вас подряд идут два одинаковых id крайне мала. Далее, зачем вообще вам idpost, если гораздо логичнее перед добавлением нового ресурса проверять есть ли ресурс с таким pagetitle и если есть, то не добавлять? И getCollection лучше заменить на getIterator так как вам все объекты разом не нужны. И ещё, чистить кеш всего сайта в цикле не кажется мне хорошей идеей.
    Роман
    24 января 2021, 23:43
    0
    Вы все правильно понимаете, да, но как правильно проверить на pagetitle или idpost???
    Это все уникальные поля. idpost в этом поле id с другого сервиса, он уникальный так же как и pagetitle. НО pagetitle может и повториться теоретически.
      Артур Шевченко
      25 января 2021, 00:02
      1
      +1
      Если у вас будет повторяться pagetitle, то modx будет ругаться, оно вам надо? Думаю, нет. А проверить элементарно. Если я правильно понял, $usersMedia['data'] содержит массив полей, из которых вы создаёте ресурс, значит надо в цикле делать прямой запрос в БД через newQuery, где в условии ставить pagetitle=$usersMedia['data'][поле которое помещается в заголовок ресурса]. Если запрос вернёт хотя бы одно значение значит, такой ресурс уже есть и надо его либо обновить, либо пропустить и продолжить выполнение цикла. Как сделать запрос в БД подскажет Гугл ключевые слова modx xpdo sql. Ну а дальше уже всё как сейчас. Либо можно поступить проще, но если ресурсов много, то это может быть неоптимальным решением с точки зрения потребления ресурсов, просто попытаться получить объект
      $resource=$modx->getObject ('modResource', array('pagetitle'=>$usersMedia['data']['fieldname']));
      if(!$resource){
      //Создаём новый ресурс
      }
      <code>
        Роман
        25 января 2021, 00:44
        0
        к сожалению не работает, на странице где вызываю сниппет, обновил страницу два раза, добавились страницы одни и те же два раза
        сделал так

        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(); 
        ////
        
        }
        }
          Артур Шевченко
          25 января 2021, 00:57
          0
          Вообще-то должно работать. Проверьте что находится в $media['title'] и в $resource->get('pagetitle'), может там пробелы какие или спецсимволы или ещё что-то и значения не совпадают. Я в коде ошибки не вижу, а то что проверка должна работать это факт.
            Роман
            25 января 2021, 01:02
            0
            А можно вместо title все таки сравнивать в существующих страницах с полем TV idpost а в новых $media['id']?
            Просто в этом поле уникальных номер такой например 18073012534211706
              Артур Шевченко
              25 января 2021, 01:09
              0
              Да можно, в принципе, но получить ресурс по TV сложнее. Где-то у вас ошибка, и вам нужно её найти. Выведите в лог входные данные и пришлите сюда, посмотрим.
                Роман
                25 января 2021, 01:13
                0
                Но мне не нужно получать ресурс по TV, смысл такой, при создании в цикле, я смотрю в папку parent 2 ВСЕРЕСУРСЫ, смотрю tv idpost, и сравниваю его с новым добавляющимся ресурсом с таким же полем. Если среди ресурсов есть ресурс с таким же значением, пропустить.
                  Артур Шевченко
                  25 января 2021, 01:21
                  0
                  Так вот, для чего вы получали $docs. Это конечно ваш код, но на мой делетантский взгляд, такой подход нерационален. Вам нужно создать TV, в цикле его получать, преобразовывать в массив, проверять есть ли в массиве текущий id, если нет, то создавать ресурс и добавлять новый id в массив, массив преобразовывать а строку, строку записывать в tv и сохранять изменения. Вам не кажется что это избыточный путь?
                    Роман
                    25 января 2021, 01:26
                    0
                    Да да да, я тоже сейчас понимаю что два цикла это неправильно, основной цикл перебор массива полей для новых ресурсов, и в нем я еще раз запускаю цикл, который смотрит все ресурсы и сравнивает поле нового ресурса со старым, и решает если нет ресурса с таким же значением в поле то добавлять. Поэтому думаю и не работает. Одна итерация, с одной записью.

                    НО я НЕ ЗНАЮ как в массиве через in_array проверить значение в TV поле. Не так силен в php
                      Артур Шевченко
                      25 января 2021, 01:30
                      1
                      +1
                      Да не нужно вам это 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(); 
                      ////
                      
                      }
                      }
                      Роман
                      25 января 2021, 01:39
                      0
                      Понял :) так работает, но все таки как при таком варианте ограничить по parent можно? И все таки сравнивать не title a tv.
                      Артур Шевченко
                      25 января 2021, 01:53
                      0
                      Там где получаете ресурс в массив добавьте ещё один элемент с ключом parent вот и будет вам ограничение по родителю. А про tv умоляю вас, забудьте, они не для этого, для программной работы с ресурсами используйте поля описанные в модели их обычно хватает, а tv это для дополнительной информации когда прям без вариантов. В вашем случае лучше писать уникальный id в pagetitle.
                      Роман
                      25 января 2021, 02:09
                      0
                      Спасибо большое, но не могу id писать в pagetitle, это индексируется поисковиками, не должно быть лишнего в заголовке.

                      с ключом parent не понял, в modResource можно только id указать, написал так
                      $resource=$modx->getObject ('modResource', 2, array('pagetitle'=>$media['title']));
                      Артур Шевченко
                      25 января 2021, 02:12
                      1
                      +1
                      $resource=$modx->getObject ('modResource', array('pagetitle'=>$media['title'], 'parent' => 2));
                      Индексируется страница, а на странице можно вывести например longtitle.
                      Артур Шевченко
                      25 января 2021, 01:31
                      0
                      $userMedia откуда берётся?
                      Роман
                      25 января 2021, 01:46
                      0
                      Это из сервиса другого, такой массив прилетает, там просто поля с данными, я просто его распечатываю 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] => 
                                      )
                              )
                      )
                  Артур Шевченко
                  25 января 2021, 01:24
                  0
                  Если так хочется использовать уникальный id, то записывайте его в pagetitle, поскольку это поле должно быть уникальным, как я уже говорил и делайте проверку, о которой я уже писал, не усложняйте. Я понимаю, что сейчас это не работает, но нужно искать ошибку, а не усложнять решение.
    Alexey
    25 января 2021, 00:52
    0
    Я бы вначале удалил дубли из самого массива $usersMedia['data'], а результат, который заведомо без дублей, уже перебирал бы форычем, вот тут хороший пример.
      Роман
      25 января 2021, 00:57
      0
      Дело в том что дублей как раз в $usersMedia нет, дубли получаются при добавлении в MODX, я вызываю снипет на странице. Если обновлю страницу два раза, страницы добавятся одни и те же. Вот пытаюсь при добавлении пропускать уже добавленные страницы. Сравнивая поле у новых страниц с таким же молем у старых, и что то не получается моя проверка не срабатывает :(
        Alexey
        25 января 2021, 01:11
        0
        Я понял) Внутренний форыч по существующим ресурсам с проверкой внутри не подходит. Нужно на каждой итерации массива $usersMedia['data'] одним запросом проверить, есть ли такое TV- поле в ресурсах указанного родителя. К примеру, через newQuery составить запрос. И если поля нет, то создавать ресурс.
          Роман
          25 января 2021, 01:15
          0
          Да, я тоже подозреваю что в foreach при добавлении я запускаю еще один foreach пробегая по существующим ресурсам это не правильно как то. Можно пример с newQuery?
          Я думаю надо как то смотреть наличие поля в массиве в целом, но не понимаю как tv в массиве посмотреть без цикла :(
            Артур Шевченко
            25 января 2021, 01:24
            0
            Пришлите целиком код сниппета
              Роман
              25 января 2021, 01:33
              0
              Вот код сниппета, убрал код 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();      // Кэш тоже чистим
              ////
               
              }
                Артур Шевченко
                25 января 2021, 01:35
                0
                А где проверка? Удалили? Или и не добавляли?
                  Роман
                  25 января 2021, 01:39
                  0
                  Да, удалил свой второй цикл в основном цикле.
              Артур Шевченко
              25 января 2021, 01:26
              0
              Какой второй цикл, его там быть не должно. Надо перебрать только $userMedia['data']
                Alexey
                25 января 2021, 01:42
                0
                Я сейчас не у компа, а код писать со смартфона — так себе занятие… Завтра постараюсь пример набросать. Если ещё будет актуально)
                  Alexey
                  25 января 2021, 02:11
                  0
                  Пока что предлагаю такой вариант: отдельным циклом пройтись по всем ресурсам родителя, все значения их tv -полей забить в отдельный массив. И потом уже — перебирая основной массив с данными сервиса — проверять через in_array, есть ли в массиве tv-шек значение элемента $media['id']. Соответственно, если нет — создаем новый ресурс.

                  Обращаю внимание, что массив всех tv-шек извлекаем в цикле ДО начала цикла с данными сервиса.
          Alexey
          25 января 2021, 09:39
          1
          +1
          В общем, как-то так:

          <?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();

          Не проверял! По идее, должно сработать.
            Alexey
            25 января 2021, 10:04
            0
            Ошибочка:

            if (!in_array($media['id'], $tvs)) {
                    //добавляю ресурс
                    .......
                }

            так должно быть
              Артур Шевченко
              25 января 2021, 10:32
              0
              Может быть вы мне объясните, зачем tv и зачем проверять наличие ресурсов в родителе?
                Alexey
                25 января 2021, 10:48
                0
                «зачем проверять наличие ресурсов в родителе?»

                Ну, в исходном скрипте есть проверка через getCollection, я ХЗ зачем она, спросите автора топика.

                «зачем tv»?

                А чем не вариант? Есть много реализаций, к примеру, импорт из 1С, где в отдельную тивиху сохраняли ID товара из файла импорта, как уникальное поле — skrinshoter.ru/s/250121/tgpRylds
                  Артур Шевченко
                  25 января 2021, 11:29
                  +1
                  Ну вариант, конечно, когда полей много и стандартных не хватает, а тут-то зачем? Ну да ладно, хочется автору через tv пусть будет так))
                    Alexey
                    25 января 2021, 11:34
                    0
                    На самом деле, я тоже стараюсь не плодить TV без надобности. Но многие клиенты прямо настаивают, чтобы в отдельной вкладочке все настройки ресурса были, привыкли к доп. полям с категориями.
                  Роман
                  25 января 2021, 11:33
                  0
                  Да, именно, у меня такая же ситуация, сторонний сервис как 1C, и приходиться в tv отдельную писать уникальные их id.
              Роман
              25 января 2021, 15:11
              0
              Благодарю!
              Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
              39