Как уйти от TV и увеличить быстродействие MODX mFilter2?

Александр
Александр
3,3K
58
Содержание:
  1. Комментарии
Александр Здравствуйте! Вы в одном из комментариев отметили что для того, чтобы, скорость фильтрации mFilter2 возросла, необходимо чтобы значения tv сохранялись в отдельной таблице, озадачился этой темой но инфы по поводу этого просто ноль, не могли бы вы если это возможно, описать как создать отдельную таблицу и сохранять значения tv которые для фильтрации там а далее как указать фильтру эту таблицу?

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

  1. Александр
    Александр
    2020-01-10 00:43:04
    Александр Здравствуйте! Столкнулся с проблемой решил не создавать отдельный вопрос, так как, есть предположение что проблема с дополнением msFavorites (Избранное), связана с расширением класса mfilter2.

    В чанке deflaut, mFilter2, вызов избранного такой:
    <a class="msfavorites"
               data-click
               data-data-list="default"
               data-data-type="resource"
               data-data-key="[[+id]]"
               data-msfavorites-animation="img/like.png"
               
            >
                <i class="msfavorites-icon-heart"></i>
            </a>
            <span class="msfavorites-total"
                  data-data-list="default"
                  data-data-type="resource"
                  
            >0</span>
    всё работает, ошибок нет, но проблема с множественной подгрузкой одного и того же файла, action.php, если открыть консоль браузера, раздел XHR, далее перезагрузить страницу с фильтром, будет видно, что грузиться один файл, action.php, это нормально, далее, если отметить один чекбокс в фильтре и перезагрузить страницу, будет видно что грузятся уже три одинаковых файла action.php, отмечаю в фильтре еще пару чекбоксов, перезагружаю страницу, грузятся уже 8 одинаковых файлов, чем больше в фильтре отмечено чекбоксов, тем больше одинаковых вызовов action.php, дополнения msFavorites.

    Пытался убирать сторонние скрипты с шаблона, думал может в них проблема, грешил на дополнение, но тестанул и это походу не тот случай, так и не могу точно найти источник проблемы, остаётся только расширенный класс mFilter2. Александр, подскажите пожалуйста, что можно попробовать сделать в данном случае?

    Скриншот консоли браузера раздела XHR:
  1. Александр
    Александр
    2020-01-10 03:12:00
    Александр, баг с коннектором был в дополнении, сейчас всё работает, та версия с которой я тестил и пытался создать аналогичную проблему, была новая и проблемы с коннектором, там уже не было, поэтому был сделан ошибочный вывод, что причина не в msFavorites, а оказалось именно в нём.
  • Sergey
    Sergey
    2019-12-06 14:01:42
    Может есть способ проще, без создания таблицы… по типу как тут?
    modx.pro/howto/13058
    1. Александр Мальцев
      Александр Мальцев
      2019-12-07 15:17:40
      В случае с TV параметрами исключать нечего, поэтому наиболее корректный вариант – это оптимизировать данные в базе данных. Или вообще избавиться от них, и написать свои решения.
  • Sergey
    Sergey
    2019-11-29 22:02:09
    Скажите, а если уже имеется каталог с tv параметрами у mFilter2 этот способ поможет?
    1. Александр
      Александр
      2019-11-30 20:21:25
      Да поможет, сейчас у вас фильтрует по дефолтной таблице а с этим вариантом будет по той которую создадите.
      При редактировании ресурса, значения полей так же сможете изменять как и раньше, только в данном случае при заполнении тв у ресурса помимо дефолтной таблицы они будут дублироваться в новую таблицу. Уменьшиться количества запросов к базе и скорость фильтрации возрастёт. Перед тем как будите что-то менять, сделайте резервною копию базы данных и сайта. Способ отличный, спасибо Александру за подробное руководство.
  • Александр Мальцев
    Александр Мальцев
    2019-09-29 02:25:30
    Вот так можно сделать фильтр в mFilter2 для своей таблицы.

    1. Создать файл \core\components\msearch2\custom\filters\custom.class.php:
    <?php
    class myCustomFilter extends mse2FiltersHandler {
    
      public function __construct(mSearch2 &$mse2, array $config = array()) {
        parent::__construct($mse2, $config);
        $this->modx->addPackage('extendResource' ,MODX_CORE_PATH.'components/extendresource/model/');
      }	
    
      public function getExtendresourceValues(array $fields, array $ids) {
        $filters = array();
        $q = $this->modx->newQuery('modResource', array('modResource.id:IN' => $ids));
        $q->leftJoin('extendResource', 'myTV',
          'myTV.resource = modResource.id'
        );
        $q->select('myTV.resource as id, myTV.tv1 as tv1, myTV.tv2 as tv2, myTV.tv3 as tv3');
        $tstart = microtime(true);
        if ($q->prepare() && $q->stmt->execute()) {
          $this->modx->queryTime += microtime(true) - $tstart;
          $this->modx->executedQueries++;
          while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
            if (empty($row['id'])) {
              continue;
            } elseif ((is_null($row['tv2']) || trim($row['tv2']) == '') && (is_null($row['tv1']) || trim($row['tv1']) == '') && (is_null($row['tv3']) || trim($row['tv3']) == '')) {
              continue;
            }
            $tmp = strpos($row['tv2'], '||') !== false
              ? explode('||', $row['tv2'])
              : array($row['tv2']);
            foreach ($tmp as $v) {
              $v = str_replace('"', '"', trim($v));
              if ($v == '') {
                continue;
              }
              $name = 'tv2';
              if (isset($filters[$name][$v])) {
                $filters[$name][$v][$row['id']] = $row['id'];
              } else {
                $filters[$name][$v] = array($row['id'] => $row['id']);
              }
            }
            $tmp = strpos($row['tv1'], '||') !== false
              ? explode('||', $row['tv1'])
              : array($row['tv1']);
            foreach ($tmp as $v) {
              $v = str_replace('"', '"', trim($v));
              if ($v == '') {
                continue;
              }
              $name = 'tv1';
              if (isset($filters[$name][$v])) {
                $filters[$name][$v][$row['id']] = $row['id'];
              } else {
                $filters[$name][$v] = array($row['id'] => $row['id']);
              }
            }
            $tmp = strpos($row['tv3'], '||') !== false
              ? explode('||', $row['tv3'])
              : array($row['tv3']);
            foreach ($tmp as $v) {
              $v = str_replace('"', '"', trim($v));
              if ($v == '') {
                continue;
              }
              $name = 'tv3';
              if (isset($filters[$name][$v])) {
                $filters[$name][$v][$row['id']] = $row['id'];
              } else {
                $filters[$name][$v] = array($row['id'] => $row['id']);
              }
            }
          }
        } else {
          $this->modx->log(modX::LOG_LEVEL_ERROR, "[mSearch2] Error on get filter params.\nQuery: ".$q->toSQL()."\nResponse: ".print_r($q->stmt->errorInfo(),1));
        }
        return $filters;
      }
    
    }
    
    2. В системных настройках в разделе mSearch2 в параметре mse2_filters_handler_class указать свой класс-обработчик для фильтров:
    myCustomFilter
    
    3. Настроить сниппет mFilter2:
    [[!mFilter2? 
      ...
      &loadModels=`extendresource`
      &filters=`extendresource|tv:default`
    ]]
    
    1. Александр
      Александр
      2019-09-29 18:39:45
      Александр, огромнейшее Вам спасибо, за уникальную и ценнейшую информацию. Получилось вывести фильтры, фильтрация работает, но не могу понять кое какие моменты.

      Вывожу фильтр так:

      [[!mFilter2?
      &tvFiltersOrDelimiter=`||`
      &tpl_5=`tpl5th`
      &parents=`0`
      EmptyFilters=`1`
      &tpls=`tpl_default`
      &includeTVs=`data,tv1,tv2`
      &noPreciseMSFilters=`1`
      &forceSearch=`0`
      &setMeta=`0` 
      &suggestions=`1`
      &showLog=`0`
      &limit=`25`
      &paginator=`pdoPage`
      &ajaxMode=`button`
      &toSeparatePlaceholders=`my.`
      &loadModels=`extendresource`
      
      &filters=`
      extendresource|tv:default
      `
      &aliases=`
      extendresource|tv1==tv1,
      `
      &tplFilter.outer.my.tv1=`tpl.outertv1`
      &tplFilter.outer.tv|tv2=`tpl.mFilter2.filter.slider`
      ]]
      1) Вот в этой строке: &includeTVs=`data,tv1,tv2` как правильно указать?

      2) Не понятно как правильно указать чанк для группы фильтров: &tplFilter.outer.my.tv1=`tpl.outertv1`?

      3) Сколько не пытался не получается вывести значения tv в результатах фильтра, создал сниппет, назвал getTVFields, поместил вызов в шаблон, где вызываю mfilter2:
      [[!getTVFields? &id=`[[*id]]`]]
      В чанке:
      [[!+my.tv1]]
      не выводит, подозреваю что не правильно указал тв в вызове фильтра:
      &includeTVs=`data,tv1,tv2` ?
      4) Как можно убедиться в том, что фильтрует именно по этой таблице а не дефолтной?

      5) Группы фильтров вывожу так: [[+my.extendresource|tv2]], это правильный вариант?

      6) Теперь если я правильно понимаю при добавлении нового тв, нужно править файл в этой строке:
      $q->select('myTV.resource as id, myTV.tv1 as tv1, myTV.tv2 as tv2, myTV.tv3 as tv3');
      и тут:
      $tmp = strpos($row['tv1'], '||') !== false
                ? explode('||', $row['tv1'])
                : array($row['tv1']);
              foreach ($tmp as $v) {
                $v = str_replace('"', '"', trim($v));
                if ($v == '') {
                  continue;
                }
                $name = 'tv1';
                if (isset($filters[$name][$v])) {
                  $filters[$name][$v][$row['id']] = $row['id'];
                } else {
                  $filters[$name][$v] = array($row['id'] => $row['id']);
                }
              }
      6) Как я понимаю, если установлен сео-фильтр, чтобы он работал с этой таблицей, там нужно выбрать, (значение в другой таблице), как правильно там прописать, подскажите пожалуйста?


    2. Александр
      Александр
      2019-09-30 04:38:53
      По одному из вопросов в предыдущем сообщении, касаемо своего чанка для каждой группы фильтров, проблем нет, у меня не работало потому-что, забыл прописать aliases, выводиться обычным способом:
      &tplFilter.outer.tv1=`tpl.имя чанка`
    3. Александр Мальцев
      Александр Мальцев
      2019-09-30 14:29:02
      Параметры «&includeTVs», «&tvFiltersOrDelimiter» и другие, связанные с TV не нужны. Иначе они будут включаться в запрос. Выборка данных осуществляется же с другой таблицы.
      В этом случае сниппет нужно вызывать в чанке и в нём id записи уже будет плейсхолдер [[+id]]:
      [[!getTVFields? &id=`[[+id]]`]]
      
      Или вообще не использовать сниппет, а сделать так:
      [[!mFilter2? 
        &loadModels=`extendresource`
        &leftJoin=`{
          "extendResource": {
            "class": "extendResource",
            "alias": "extFields", 
            "on": "extFields.resource = modResource.id"
          }
        }`
        &select=`{
          "extFields": "extFields.tv1 as tv1, extFields.tv2 as tv2, extFields.tv3 as tv3"
        }`
        ...
      
      Поставьте debugParser и протестируйте время и количество запросов. Параметр «&filters» определяется почему будет фильтроваться.

      При добавлении нового поля нужно добавить ещё в условие, где оно проверяется на пустоту или null.
    4. Александр Мальцев
      Александр Мальцев
      2019-09-30 14:53:22
      В SeoFilter:
      — компонент: extendresource
      — класс: extendResource
      — поле для сопоставления (id): resource
      — поле, где хранится значение (name): tv1
    5. Александр
      Александр
      2019-09-30 19:39:36
      Александр, по всем вопросам всё предельно понятно, спасибо. DebugParser, пользуюсь им и отслеживаю каждый килобайт и запрос, лишний надеюсь не проскочит:) но есть проблема только с выводом значений в результатах фильтра на сколько я понимаю, более а точнее менее затратный по ресурсам, это второй вариант: leftJoin, у меня не получается вывести, если я в чанке вызываю так: [[!+tv1]] то тянуться значения с дефолтной таблицы и не зависимо от того, есть ли в вызове mFilter2 ваш пример: leftJoin, проверил это ручным удалением с дефолтной таблицы значения. Если делаю так: [[!+extFields.tv1]] то не выводит не чего, очевидно что я просто не правильно делаю вызов?
    6. Александр
      Александр
      2019-10-01 00:40:33
      SeoFilter при таком раскладе не хочет нормально работать, что с параметрами что без них не работает, а именно подсчёты не работают и хлебные крошки через ajax ну и в админке вкладка сео-страницы, название страниц не выводит, походу там тоже нужно расширять класс, чтобы работало нормально? Сейчас всё завязано на этом: modTemplateVar
    7. Александр Мальцев
      Александр Мальцев
      2019-10-01 14:04:54
      SeoFilter не использовал, могу подсказать только навскидку.
    8. Александр Мальцев
      Александр Мальцев
      2019-10-01 14:25:03
      Наиболее просто — это вывести все плейсхолдеры на экран и посмотреть, как они называются. Для этого параметру устанавливающему чанк для каждого результата нужно в качестве значения установить пустую строку:
      &tpl = ``
      
    9. Александр
      Александр
      2019-10-01 18:41:09
      Как я понимаю, если использовать свой класс в SeoFilter, там нужно расширять его, примерно так-же как и в mFilter2, тогда подсчёты будут работать, это так мысли в слух.
    10. Александр
      Александр
      2019-10-01 18:53:45
      Спасибо! Мистика честно говоря, вызов обычный: [[!+tv1]] выводит и при чём выводит с новой таблицы, всё как нужно, это при том, что я удалил с дефолтной таблицы в ручную все значения, оставил только их в новой таблице, но не понятно почему тогда, когда значения находились в обоих таблицах, при таком вызове: [[!+tv1]] выводились значения с дефолтной таблицы, вообще такое теоретические возможно, при указанном &leftJoin, если значения в обоих таблицах то выводятся с дефолтной, если только в новой, то с неё? И обязательно вызов должен быть не кешированым?
    11. Александр
      Александр
      2019-10-01 19:09:20
      Александр, подскажите пожалуйста, как изменить разделитель || при выводе значений на, с помощью модификатора? как лучше и правильней это делать?
    12. Александр
      Александр
      2019-10-01 20:33:32
      По поводу разделителя, хотел бы уточнить свой вопрос, понимаю что можно выводить так:
      [[!+tv1:replace=`||==, `]]
      , но интересует ваше мнение и есть ли ищё какие варианты вывода? Можно ли в &leftJoin это прописать?
    13. Александр Мальцев
      Александр Мальцев
      2019-10-02 11:50:48
      Обработку лучше выполнять после получения данных.
      Можно через Fenom:
      {var $arrtv1 = $tv1 | split : '||'}
      {if $arrtv1 | iterable}
          {foreach $arrtv1 as $value}
              <div>{$value}</div>
          {/foreach}
      {/if}
      
      Так же можно написать пользовательские модификаторы вывода. Они реализуются через сниппеты, тут уже можно написать любую логику.
    14. Александр Мальцев
      Александр Мальцев
      2019-10-02 11:55:27
      Может они переопределялись значениями дефолтной таблицы.
    15. Александр
      Александр
      2019-10-02 23:08:04
      Александр, спасибо.
    16. Александр
      Александр
      2019-10-04 21:49:41
      Здравствуйте, изначально не заметил но сортирует не правильно:

      Вызов такой:
      <a href="#" data-sort="extendresource|tv1" data-dir="[[+mse2_sort:is=`extendresource|tv1:desc`:then=`desc`]]" data-default="desc" class="sort">Тест <span></span></a>
      с чем связано не подскажите?
    17. Александр
      Александр
      2019-10-05 03:56:36
      Возможно кому пригодиться, проблема с сортировкой была у полей, которых значения в виде числа: пример: 5000,350,580 и т.д, у таких полей в таблице, тип поля нужно выбрать: smallint.
    18. Александр Мальцев
      Александр Мальцев
      2019-10-05 07:41:14
      Как понимаю, проблема с сортировкой решилась. Нужно было чтобы она выполнялась как с числами, а она выполнялась как со строками.
    19. Александр
      Александр
      2019-10-05 16:01:24
      Да, с сортировкой проблема решилась, хотел бы уточнить кое какие моменты, для чисел нужно использовать INT, для текста VARCHAR или TEXT — тогда всё должно сортироваться верно.
    20. Александр Мальцев
      Александр Мальцев
      2019-10-06 06:11:54
      В основном эти.
      Для целых чисел int, для строк с переменной длиной от 1 до 255 символов varchar, text — для строк с максимальной длиной, равной 65535 символов.
      Ещё бывает используется tinyint для хранения маленьких чисел (со знаком от –128 до 127, без знака от 0 до 255), datetime — для даты и время, и mediumtext — для больших текстов с максимальной длиной до 16777215 символов.
    21. Александр
      Александр
      2020-07-20 17:15:50
      Александр, здравствуйте! Не так давно, вышло обновление mSearh2 1.14-0-pl, где добавлена возможность кэширование предварительных результатов и сразу возникли проблемы с фильтрацией по своей таблицы а именно с предварительными подсчётами и правильным построением результатов, происходит это так у всех фильтров в фильтре в предварительных результатах одно и тоже число, при выборе любого фильтра остальные становятся не доступны, логика полностью нарушена, до этого были проблемы с подсчётами и тогда помогло такое решение, добавить пару строчек кода в файл custom.class.php:

      //Правильные подсчёты в mFilter2
      public function filterDefault(array $requested, array $values, array $ids) {
           return array_unique(parent::filterDefault($requested,$values,$ids));
      }
      после всё работало, но после обновления mSearh2, такой вариант не прокатывает, подскажите пожалуйста что можно попробовать сделать?
    22. Александр Мальцев
      Александр Мальцев
      2020-08-06 15:29:41
      Здравствуйте! Это нужно смотреть какие изменения были сделаны в этой версии. Но так как проект закрытый и его нет на Github, то узнать, что в коде было изменено так просто не получится. Если найдёте какие изменения были конкретно сделаны в новой версии, то в этом случае уже можно будет что-то предложить.
  • Александр
    Александр
    2019-09-27 22:11:49
    Александр, по поводу отсутствия id в таблице, оказывается забыл при создании таблицы поставить галку параметра auto_increment.
    Сейчас выглядит так:


    Остались только проблемы с разбиением, как я понимаю от этого зависит разделитель значений тв в таблице? что там указывать?

    Так же не получается вывести в mfilter2, как нужно указать там?

    Вывожу так:
    [[!mFilter2?
    &tvFiltersOrDelimiter=`||`
    &parents=`0`
    EmptyFilters=`1`
    &includeTVs=`tv1`
    &noPreciseMSFilters=`1`
    &forceSearch=`0`
    &setMeta=`0` 
    &suggestions=`1`
    &showLog=`0`
    &limit=`25`
    &paginator=`pdoPage`
    &ajaxMode=`button`
    &toSeparatePlaceholders=`my.`
    
    &filters=`
    tv|tv1
    `
    &aliases=`
    		tv|tv1==tv1
    `
    &tplFilter.outer.tv1=`tpl.checkboxmy`
    ]]
    1. Александр Мальцев
      Александр Мальцев
      2019-09-28 14:38:19
      В плагине нужно поправить код:
      ...
      //$tv1 = $resource->getTVValue('tv1');
      //$tv2 = $resource->getTVValue('tv2');            
      //$tv3 = $resource->getTVValue('tv3'); 
      
      $tv1 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 1, // id TV
        'contentid' => $id
      ));
      if (is_object($tv1)) {
        $tv1 = $tv1->get('value');
      } else {
        $tv1= '';
      }
             
      $tv2 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 2, // id TV
        'contentid' => $id
      ));
      if (is_object($tv2)) {
        $tv2 = $tv2->get('value');
      } else {
        $tv2 = '';
      }            
                 
      $tv3 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 3, // id TV
        'contentid' => $id
      )); 
      if (is_object($tv3)) {
        $tv3 = $tv3->get('value');
      } else {
        $tv3 = '';
      }   
      
      Метод getTVValue выполняет обработку данных, поэтому вместо него нужно просто выбирать значения.

      Таблица готова, теперь для выбора всех полей нужен всего 1 запрос.

      По mFilter2 нет готового рецепта, тут нужно писать решение для этой таблицы, т.е. свой фильтр для mFilter2.
    2. Александр
      Александр
      2019-09-28 16:49:06
      Здравствуйте! При таком раскладе в таблицу пишуться урл тв поля img чё то не правильно делаю?

      <?php
      $modx->addPackage('extendResource', $modx->getOption('core_path').'components/extendresource/model/');
      
      switch ($modx->event->name) {
       
              // Documents
              case 'OnDocFormSave':
              case 'OnDocPublished':
              case 'OnDocUnPublished':
              case 'OnResourceUndelete':
                
      
      $isPublished = $resource->get('published');
          $id = $resource->get('id');        
      $tv1 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 1, // id TV
        'contentid' => $id
      ));
      if (is_object($tv1)) {
        $tv1 = $tv1->get('value');
      } else {
        $tv1= '';
      }
             
      $tv2 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 2, // id TV
        'contentid' => $id
      ));
      if (is_object($tv2)) {
        $tv2 = $tv2->get('value');
      } else {
        $tv2 = '';
      }            
                 
      $tv3 = $modx->getObject('modTemplateVarResource', array(
        'tmplvarid' => 3, // id TV
        'contentid' => $id
      )); 
      if (is_object($tv3)) {
        $tv3 = $tv3->get('value');
      } else {
        $tv3 = '';
      }   
                  
                  
          $extendResource = $modx->getObject('extendResource',array(
                     'resource' => $id,
                  ));
                  if (is_object($extendResource)) {
                      if ($isPublished) {
                      $extendResource->set('resource', $id);
                      $extendResource->set('tv1', $tv1);
                      $extendResource->set('tv2', $tv2);
                      $extendResource->set('tv3', $tv3);
                      $extendResource->save(); } else {
                        $extendResource->remove();
                      }
                  } else {
                      if ($isPublished) {
                      $extendResource = $modx->newObject('extendResource');
                      $extendResource->set('resource', $id);
                      $extendResource->set('tv1', $tv1);
                      $extendResource->set('tv2', $tv2);
                      $extendResource->set('tv3', $tv3);
                      $extendResource->save();
                      }
                  }
              break;        
              
              case 'OnDocFormDelete':
                $extendResource = $modx->getObject('extendResource',array(
                     'resource' => $resource->get('id'),
                ));
                if (is_object($extendResource)) {
                    $extendResource->remove();
                }          
              break;     
      }
    3. Александр Мальцев
      Александр Мальцев
      2019-09-28 23:00:22
      Сейчас TV указываются с помощью id. Значит нужно указать id нужных TV полей.
      'tmplvarid' => 1, // id TV
      
    4. Александр
      Александр
      2019-09-29 00:19:31
      Александр, где эти id? Если 3,4,5 у вас ниже на скрине тоже самое что и у меня, то с ними у меня не работает, так же если те id в таблице где у вас на втором скрине 5,6,7,8 они же не привязаны к конкретному полю или я чё то не догоняю, на всякий случай пробовал те и эти не сохраняет в таблице значения. В данном случае появляется пустая строка в таблице с новым id.


    5. Александр Мальцев
      Александр Мальцев
      2019-09-29 01:50:50
      id TV это то что указано в круглях скобках в дереве элементов:
      Вкладка с элементами в MODX
      В этом примере tv1 имеет id, равный 7, tv2 имеет id, равный 8, tv3 имеет id, равный 9.
    6. Александр
      Александр
      2019-09-29 02:26:22
      :) Точно нужны же id полей, чтобы плагин знал какие брать с дефолтной таблицы, и дублировал их в новой, запутался не много, поэтому не сообразил, спасибо:) Теперь всё работает.

      Александр а по поводу фильтрации с mfilter2 по этой таблице, как это примерно реализовать, расширять класс? Может есть готовое решение где нужно просто изменить по минимуму, к примеру взять с файла filter.class.php? как я понимаю сейчас даже не получиться вывести эти тв в результатах mfilter2
    7. Александр
      Александр
      2019-10-05 19:39:07
      Александр, если у базы данных префикс к примеру такой 2jbFDWbsFUQx, что в плагине нужно изменить? Просто возникла проблема если плагин установлен то не сохраняет ресурс, просто зависает при сохранении. На локалке всё работает на хосте с другим префиксом зависает.
    8. Александр
      Александр
      2019-10-05 20:09:15
      Такие ошибки сыпятся:
      [2019-10-05 20:06:10] (ERROR @ /home/s20017/www/core/xpdo/xpdo.class.php : 644) Could not load class: extendResource from mysql.extendresource.
      [2019-10-05 20:06:10] (ERROR @ /home/s20017/www/core/xpdo/xpdo.class.php : 762) extendResource::load() is not a valid static method.
      [2019-10-05 20:06:10] (ERROR @ /home/s20017/www/core/xpdo/xpdo.class.php : 644) Could not load class: extendResource from mysql.extendresource.
    9. Александр
      Александр
      2019-10-05 22:28:55
      Хотел бы дополнить и поправить вопрос, оказывается причина не в префиксе, не могу разобраться в чём, но как только устанавливаешь системное событие: OnDocFormSave, вылетают ошибки а при сохранении ресурса просто зависает, Александр если есть время внесите свою лепту по поводу этого, очень нужно?
    10. Александр
      Александр
      2019-10-06 02:37:02
      Вообщем проблема тут:
      addPackage('extendResource'
      крови она мне выпила, но странная вещь, на локалке работает на на хосте не в какую, поэтому изначально даже не предполагал что в этом весь гемор.
    11. Александр Мальцев
      Александр Мальцев
      2019-10-06 03:00:29
      На хосте создали таблицу в базе данных? Дополнение core/extendresource скопировали?
    12. Александр
      Александр
      2019-10-06 04:32:00
      Всё делал по новой, то есть с нуля, не работало если в плагине указано addPackage('extendResource' при чём пять раз переделывал, заработало addPackage('extendresource', по логике тут же должно быть название пакета, (папки extendresource) а не класса или я не прав?
    13. Александр
      Александр
      2019-10-06 04:58:00
      Хотя наверно я не прав, но факт есть, работает а по другому не работает, с чем связано не понятно.
    14. Александр Мальцев
      Александр Мальцев
      2019-10-06 05:57:07
      Там указывается название пакета (папки), так что должно быть маленькими буквами, т.е. extendresource. В коде неправильно написал. В Windows нет разницы прописная буква или строчная, поэтому и сработало. А на боевом сайте (в Linux) — нет, т.к. там есть разница прописная буква или строчная.
    15. Александр Мальцев
      Александр Мальцев
      2019-10-06 06:22:10
      Префикс мы ни где не указывали. Он не нужен. Т.к. запрос к базе данных составляет сам механизм MODX и он, конечно, создаёт его с учётом префикса.
      Префикс может понадобиться, если писать SQL запросы напрямую. В этом случае нужно будет получить префикс таблиц и подставить его в SQL:
      $tablePrefix = $modx->getOption('table_prefix');
      
    16. Александр
      Александр
      2019-10-06 15:45:12
      А зачем подгружать пакет плагин да без этого не работает, а в custom.class.php, если убрать блок construct работает, зачем он там нужен?
    17. Александр
      Александр
      2019-10-06 15:57:03
      Спасибо, предельно понятно. Изначально грешил на него, когда были проблемы с плагином.
    18. Александр Мальцев
      Александр Мальцев
      2019-10-06 16:26:48
      Значит уже загружен, тогда подгрузка не нужна и фрагмент construct можно убрать.
    19. Александр
      Александр
      2019-10-07 01:04:19
      Заметил не большой баг, при сохранении ресурса в котором лежат все ресурсы, плагин добавил пустую строку в базе данных с id этого ресурса, на функционал не влияет но хотелось бы понять почему?
    20. Александр
      Александр
      2019-10-07 01:28:33
      Всё на много серьёзней оказывается, при сохранении любого ресурса в новой базе появляется пустая строка, как исправить не подскажите?
    21. Александр Мальцев
      Александр Мальцев
      2019-10-07 13:57:27
      Это из-за того, что в плагине нет проверки.
      TV привязываются к шаблону, поэтому можно написать проверку, в которой проверить id шаблона ресурса. Если id шаблона нужный, то выполнять сохранение, в противном случае прервать выполнение кода.
      switch ($modx->event->name) {
          case 'OnDocFormSave':
          case 'OnDocPublished':
          case 'OnDocUnPublished':
          case 'OnResourceUndelete':
              // например, выполнять после условия, только для тех ресурсов, у которых id шаблона, равно 15
              if ($resource->get('template') !== 15) {
                  break;
              }
              ...
      
    22. Александр
      Александр
      2019-10-07 15:50:02
      То что нужно, спасибо.
  • Александр Мальцев
    Александр Мальцев
    2019-09-27 13:44:08
    Привет!
    Первую часть вопроса можно реализовать воспользовавшись рецептом, описанным в этой статье.

    Т.е. открываете phpMyAdmin или какой-то другой инструмент для работы с базой данных. С помощью phpMyAdmin создаёте таблицу, например, modx_site_content_extend (modx_ — это префикс, который установлен для таблиц на сайте).
    Структура таблицы modx_site_content_extend
    Тут, всё понятно. Поле «id» – это первичный ключ, resource – это id ресурса, tv1, tv2, tv3, и т.д. – значения tv полей.

    После этого создаём в «/core/components» папку нашего приложения, например, extendresource. А в ней папку «model», а в ней папку «schema».
    В папке «schema» создадим файл «extendresource.mysql.schema.xml».
    Содержимое файла:
    <?xml version="1.0" encoding="UTF-8"?>
    <model package="extendresource" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
        <object class="extendResource" table="site_content_extend" extends="xPDOSimpleObject">
            <field key="resource" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" index="pk" />
            <field key="tv1" dbtype="mediumtext" phptype="string" null="false" />
            <field key="tv2" dbtype="mediumtext" phptype="string" null="false" />
            <field key="tv3" dbtype="mediumtext" phptype="string" null="false" />
            <index alias="resource" name="resource" primary="false" unique="true" type="BTREE" >
                <column key="resource" length="" collation="A" null="false" />
            </index>
            <aggregate alias="Resource" class="modResource" local="resource" foreign="id" cardinality="one" owner="foreign" />
        </object>
    </model>
    
    Далее скачиваем скрипт parse_schema.php и помещае его в корень проекта.
    Открываем данный файл, вводим в него название «extendresource».
    Выполняем данный файл. Всё компонент готов.

    Далее создаём плагин со следующим содержимым:
    <?php
    $modx->addPackage('extendResource', $modx->getOption('core_path').'components/extendresource/model/');
    
    switch ($modx->event->name) {
     
            // Documents
            case 'OnDocFormSave':
            case 'OnDocPublished':
            case 'OnDocUnPublished':
            case 'OnResourceUndelete':
              
                $isPublished = $resource->get('published');
                $id = $resource->get('id');
                $tv1 = $resource->getTVValue('tv1');
                $tv2 = $resource->getTVValue('tv2');            
                $tv3 = $resource->getTVValue('tv3'); 
                
                $extendResource = $modx->getObject('extendResource',array(
                   'resource' => $id,
                ));
                if (is_object($extendResource)) {
                    if ($isPublished) {
                    $extendResource->set('resource', $id);
                    $extendResource->set('tv1', $tv1);
                    $extendResource->set('tv2', $tv2);
                    $extendResource->set('tv3', $tv3);
                    $extendResource->save(); } else {
                      $extendResource->remove();
                    }
                } else {
                    if ($isPublished) {
                    $extendResource = $modx->newObject('extendResource');
                    $extendResource->set('resource', $id);
                    $extendResource->set('tv1', $tv1);
                    $extendResource->set('tv2', $tv2);
                    $extendResource->set('tv3', $tv3);
                    $extendResource->save();
                    }
                }
            break;
            
            case 'OnDocFormDelete':
              $extendResource = $modx->getObject('extendResource',array(
                   'resource' => $resource->get('id'),
              ));
              if (is_object($extendResource)) {
                  $extendResource->remove();
              }          
            break;     
            
    }
    
    На вкладке «Системные события» отмечаем галочками пункты: OnDocFormDelete, OnDocFormSave, OnDocPublished, OnDocUnPublished и OnResourceUndelete.
    Системные события плагина MODX

    Данный плагин будет обновлять таблицу modx_site_content_extend при сохранении ресурса, публикации, снятие его с публикации и удалении.

    Данные таблицы modx_site_content_extend
    1. Александр
      Александр
      2019-09-27 21:17:34
      Александр душевное Вам спасибо, за развёрнутый ответ. Получилось сделать, чтобы сохранялись значений поля tv1 в этой таблице, но я что-то походу намудрил в создании таблицы, сделал скрины что у меня вышло:

      Как видно id нет и значения не разделяются


      И ошибки есть:


      В руководстве есть опечатка «modal» model.

      Подскажите пожалуйста в чём я допустил ошибку?

    2. Александр
      Александр
      2019-09-27 23:15:35
      Александр всё работает ищё раз огромное спасибо, фильтрация тоже, только не понятны некоторые вещи, скажите, значения тв в таблице добавляются слитно, это нормально?

      Предупреждение (Разбиение отсутствует) как с этим решить вопрос?

      Как я понимаю сейчас при создание тв, если мне нужно чтобы его значения сохранялись в этой таблице, необходимо вручную добавить строку в таблице и указать название тв в плагине, правильно я понимаю?

      В компонентах не чего не нужно править для работы с этой таблицей?
    3. Александр
      Александр
      2019-09-28 01:57:53
      Поспешил не много, как я понял значения полей tv1 tv2 tv3, дублируются в таблицу modx_site_tmplvar_contentvalues, изначально ошибочно предполагая что сохраняться они будут только в новой таблице, поэтому решил что всё у меня работает, так как фильтрация работала. Александр, если не трудно подскажите как использовать эти поля, значения в фильтре? И просто выводить плейсхолдером?

      И нормально ли это что в таблице значения у тв без разделителя просто слитно в таком формате: СпичкиСтружка?

    4. Александр Мальцев
      Александр Мальцев
      2019-09-28 15:25:55
      Да, они дублируются, иначе нужно было бы переписывать уже существующую логику на страницах. А так она будет использоваться там, где нужно сократить время. Например, если используется 7 TV, то вместо 7 запросов можно ограничиться одним.

      Т.к. таблица кастомная, то нужно писать свою логику для mFilter2.

      Выводить значения из своей таблицы можно реализовать через сниппет или плагин.
      Например, можно создать сниппет getExtendFields:
      <?php
      $modx->addPackage('extendResource', $modx->getOption('core_path').'components/extendresource/model/');
      
      $extendResource = $modx->getObject('extendResource',array(
        'resource' => $id,
      ));
      
      $tv1 = "";
      $tv2 = "";
      $tv3 = "";
      
      if (is_object($extendResource)) {
        $tv1 = $extendResource->get('tv1');
        $tv2 = $extendResource->get('tv2');
        $tv3 = $extendResource->get('tv3');
      }
                
      $modx->setPlaceholders(array(
         'tv1' => $tv1,
         'tv2' => $tv2,
         'tv3' => $tv3,   
      ),'my.');
      
      return; 
      
      После этого поместить его вызов в шаблон:
      [[!getTVFields? &id=`[[*id]]`]]
      
      Вывести поля в этом случае можно так:
      [[!+my.tv1]]
      [[!+my.tv2]]
      [[!+my.tv3]]
      
    5. Александр Мальцев
      Александр Мальцев
      2019-09-28 15:29:15
      Да, для дублирования TV в своей таблице нужно не только это выполнить, а также обновить схему компонента и сгенерировать ему новую модель.