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

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

Ответы: 58

Аноним
Аноним
Александр Здравствуйте! Столкнулся с проблемой решил не создавать отдельный вопрос, так как, есть предположение что проблема с дополнением 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:
Аноним
Аноним
Александр, баг с коннектором был в дополнении, сейчас всё работает, та версия с которой я тестил и пытался создать аналогичную проблему, была новая и проблемы с коннектором, там уже не было, поэтому был сделан ошибочный вывод, что причина не в msFavorites, а оказалось именно в нём.
Аноним
Аноним
Может есть способ проще, без создания таблицы… по типу как тут?
modx.pro/howto/13058
Аноним
Аноним
В случае с TV параметрами исключать нечего, поэтому наиболее корректный вариант – это оптимизировать данные в базе данных. Или вообще избавиться от них, и написать свои решения.
Аноним
Аноним
Скажите, а если уже имеется каталог с tv параметрами у mFilter2 этот способ поможет?
Аноним
Аноним
Да поможет, сейчас у вас фильтрует по дефолтной таблице а с этим вариантом будет по той которую создадите.
При редактировании ресурса, значения полей так же сможете изменять как и раньше, только в данном случае при заполнении тв у ресурса помимо дефолтной таблицы они будут дублироваться в новую таблицу. Уменьшиться количества запросов к базе и скорость фильтрации возрастёт. Перед тем как будите что-то менять, сделайте резервною копию базы данных и сайта. Способ отличный, спасибо Александру за подробное руководство.
Аноним
Аноним
Вот так можно сделать фильтр в 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`
]]
Аноним
Аноним
Александр, огромнейшее Вам спасибо, за уникальную и ценнейшую информацию. Получилось вывести фильтры, фильтрация работает, но не могу понять кое какие моменты.

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

[[!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) Как я понимаю, если установлен сео-фильтр, чтобы он работал с этой таблицей, там нужно выбрать, (значение в другой таблице), как правильно там прописать, подскажите пожалуйста?


Аноним
Аноним
По одному из вопросов в предыдущем сообщении, касаемо своего чанка для каждой группы фильтров, проблем нет, у меня не работало потому-что, забыл прописать aliases, выводиться обычным способом:
&tplFilter.outer.tv1=`tpl.имя чанка`
Аноним
Аноним
Параметры «&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.
Аноним
Аноним
В SeoFilter:
— компонент: extendresource
— класс: extendResource
— поле для сопоставления (id): resource
— поле, где хранится значение (name): tv1
Аноним
Аноним
Александр, по всем вопросам всё предельно понятно, спасибо. DebugParser, пользуюсь им и отслеживаю каждый килобайт и запрос, лишний надеюсь не проскочит:) но есть проблема только с выводом значений в результатах фильтра на сколько я понимаю, более а точнее менее затратный по ресурсам, это второй вариант: leftJoin, у меня не получается вывести, если я в чанке вызываю так: [[!+tv1]] то тянуться значения с дефолтной таблицы и не зависимо от того, есть ли в вызове mFilter2 ваш пример: leftJoin, проверил это ручным удалением с дефолтной таблицы значения. Если делаю так: [[!+extFields.tv1]] то не выводит не чего, очевидно что я просто не правильно делаю вызов?
Аноним
Аноним
SeoFilter при таком раскладе не хочет нормально работать, что с параметрами что без них не работает, а именно подсчёты не работают и хлебные крошки через ajax ну и в админке вкладка сео-страницы, название страниц не выводит, походу там тоже нужно расширять класс, чтобы работало нормально? Сейчас всё завязано на этом: modTemplateVar
Аноним
Аноним
SeoFilter не использовал, могу подсказать только навскидку.
Аноним
Аноним
Наиболее просто — это вывести все плейсхолдеры на экран и посмотреть, как они называются. Для этого параметру устанавливающему чанк для каждого результата нужно в качестве значения установить пустую строку:
&tpl = ``
Аноним
Аноним
Как я понимаю, если использовать свой класс в SeoFilter, там нужно расширять его, примерно так-же как и в mFilter2, тогда подсчёты будут работать, это так мысли в слух.
Аноним
Аноним
Спасибо! Мистика честно говоря, вызов обычный: [[!+tv1]] выводит и при чём выводит с новой таблицы, всё как нужно, это при том, что я удалил с дефолтной таблицы в ручную все значения, оставил только их в новой таблице, но не понятно почему тогда, когда значения находились в обоих таблицах, при таком вызове: [[!+tv1]] выводились значения с дефолтной таблицы, вообще такое теоретические возможно, при указанном &leftJoin, если значения в обоих таблицах то выводятся с дефолтной, если только в новой, то с неё? И обязательно вызов должен быть не кешированым?
Аноним
Аноним
Александр, подскажите пожалуйста, как изменить разделитель || при выводе значений на, с помощью модификатора? как лучше и правильней это делать?
Аноним
Аноним
По поводу разделителя, хотел бы уточнить свой вопрос, понимаю что можно выводить так:
[[!+tv1:replace=`||==, `]]
, но интересует ваше мнение и есть ли ищё какие варианты вывода? Можно ли в &leftJoin это прописать?
Аноним
Аноним
Обработку лучше выполнять после получения данных.
Можно через Fenom:
{var $arrtv1 = $tv1 | split : '||'}
{if $arrtv1 | iterable}
    {foreach $arrtv1 as $value}
        <div>{$value}</div>
    {/foreach}
{/if}
Так же можно написать пользовательские модификаторы вывода. Они реализуются через сниппеты, тут уже можно написать любую логику.
Аноним
Аноним
Может они переопределялись значениями дефолтной таблицы.
Аноним
Аноним
Александр, спасибо.
Аноним
Аноним
Здравствуйте, изначально не заметил но сортирует не правильно:

Вызов такой:
<a href="#" data-sort="extendresource|tv1" data-dir="[[+mse2_sort:is=`extendresource|tv1:desc`:then=`desc`]]" data-default="desc" class="sort">Тест <span></span></a>
с чем связано не подскажите?
Аноним
Аноним
Возможно кому пригодиться, проблема с сортировкой была у полей, которых значения в виде числа: пример: 5000,350,580 и т.д, у таких полей в таблице, тип поля нужно выбрать: smallint.
Аноним
Аноним
Как понимаю, проблема с сортировкой решилась. Нужно было чтобы она выполнялась как с числами, а она выполнялась как со строками.
Аноним
Аноним
Да, с сортировкой проблема решилась, хотел бы уточнить кое какие моменты, для чисел нужно использовать INT, для текста VARCHAR или TEXT — тогда всё должно сортироваться верно.
Аноним
Аноним
В основном эти.
Для целых чисел int, для строк с переменной длиной от 1 до 255 символов varchar, text — для строк с максимальной длиной, равной 65535 символов.
Ещё бывает используется tinyint для хранения маленьких чисел (со знаком от –128 до 127, без знака от 0 до 255), datetime — для даты и время, и mediumtext — для больших текстов с максимальной длиной до 16777215 символов.
Аноним
Аноним
Александр, здравствуйте! Не так давно, вышло обновление 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, такой вариант не прокатывает, подскажите пожалуйста что можно попробовать сделать?
Аноним
Аноним
Здравствуйте! Это нужно смотреть какие изменения были сделаны в этой версии. Но так как проект закрытый и его нет на Github, то узнать, что в коде было изменено так просто не получится. Если найдёте какие изменения были конкретно сделаны в новой версии, то в этом случае уже можно будет что-то предложить.
Аноним
Аноним
Александр, по поводу отсутствия 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`
]]
Аноним
Аноним
В плагине нужно поправить код:
...
//$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.
Аноним
Аноним
Здравствуйте! При таком раскладе в таблицу пишуться урл тв поля 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;     
}
Аноним
Аноним
Сейчас TV указываются с помощью id. Значит нужно указать id нужных TV полей.
'tmplvarid' => 1, // id TV
Аноним
Аноним
Александр, где эти id? Если 3,4,5 у вас ниже на скрине тоже самое что и у меня, то с ними у меня не работает, так же если те id в таблице где у вас на втором скрине 5,6,7,8 они же не привязаны к конкретному полю или я чё то не догоняю, на всякий случай пробовал те и эти не сохраняет в таблице значения. В данном случае появляется пустая строка в таблице с новым id.


Аноним
Аноним
id TV это то что указано в круглях скобках в дереве элементов:
Вкладка с элементами в MODX
В этом примере tv1 имеет id, равный 7, tv2 имеет id, равный 8, tv3 имеет id, равный 9.
Аноним
Аноним
:) Точно нужны же id полей, чтобы плагин знал какие брать с дефолтной таблицы, и дублировал их в новой, запутался не много, поэтому не сообразил, спасибо:) Теперь всё работает.

Александр а по поводу фильтрации с mfilter2 по этой таблице, как это примерно реализовать, расширять класс? Может есть готовое решение где нужно просто изменить по минимуму, к примеру взять с файла filter.class.php? как я понимаю сейчас даже не получиться вывести эти тв в результатах mfilter2
Аноним
Аноним
Александр, если у базы данных префикс к примеру такой 2jbFDWbsFUQx, что в плагине нужно изменить? Просто возникла проблема если плагин установлен то не сохраняет ресурс, просто зависает при сохранении. На локалке всё работает на хосте с другим префиксом зависает.
Аноним
Аноним
Такие ошибки сыпятся:
[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.
Аноним
Аноним
Хотел бы дополнить и поправить вопрос, оказывается причина не в префиксе, не могу разобраться в чём, но как только устанавливаешь системное событие: OnDocFormSave, вылетают ошибки а при сохранении ресурса просто зависает, Александр если есть время внесите свою лепту по поводу этого, очень нужно?
Аноним
Аноним
Вообщем проблема тут:
addPackage('extendResource'
крови она мне выпила, но странная вещь, на локалке работает на на хосте не в какую, поэтому изначально даже не предполагал что в этом весь гемор.
Аноним
Аноним
На хосте создали таблицу в базе данных? Дополнение core/extendresource скопировали?
Аноним
Аноним
Всё делал по новой, то есть с нуля, не работало если в плагине указано addPackage('extendResource' при чём пять раз переделывал, заработало addPackage('extendresource', по логике тут же должно быть название пакета, (папки extendresource) а не класса или я не прав?
Аноним
Аноним
Хотя наверно я не прав, но факт есть, работает а по другому не работает, с чем связано не понятно.
Аноним
Аноним
Там указывается название пакета (папки), так что должно быть маленькими буквами, т.е. extendresource. В коде неправильно написал. В Windows нет разницы прописная буква или строчная, поэтому и сработало. А на боевом сайте (в Linux) — нет, т.к. там есть разница прописная буква или строчная.
Аноним
Аноним
Префикс мы ни где не указывали. Он не нужен. Т.к. запрос к базе данных составляет сам механизм MODX и он, конечно, создаёт его с учётом префикса.
Префикс может понадобиться, если писать SQL запросы напрямую. В этом случае нужно будет получить префикс таблиц и подставить его в SQL:
$tablePrefix = $modx->getOption('table_prefix');
Аноним
Аноним
А зачем подгружать пакет плагин да без этого не работает, а в custom.class.php, если убрать блок construct работает, зачем он там нужен?
Аноним
Аноним
Спасибо, предельно понятно. Изначально грешил на него, когда были проблемы с плагином.
Аноним
Аноним
Значит уже загружен, тогда подгрузка не нужна и фрагмент construct можно убрать.
Аноним
Аноним
Заметил не большой баг, при сохранении ресурса в котором лежат все ресурсы, плагин добавил пустую строку в базе данных с id этого ресурса, на функционал не влияет но хотелось бы понять почему?
Аноним
Аноним
Всё на много серьёзней оказывается, при сохранении любого ресурса в новой базе появляется пустая строка, как исправить не подскажите?
Аноним
Аноним
Это из-за того, что в плагине нет проверки.
TV привязываются к шаблону, поэтому можно написать проверку, в которой проверить id шаблона ресурса. Если id шаблона нужный, то выполнять сохранение, в противном случае прервать выполнение кода.
switch ($modx->event->name) {
    case 'OnDocFormSave':
    case 'OnDocPublished':
    case 'OnDocUnPublished':
    case 'OnResourceUndelete':
        // например, выполнять после условия, только для тех ресурсов, у которых id шаблона, равно 15
        if ($resource->get('template') !== 15) {
            break;
        }
        ...
Аноним
Аноним
То что нужно, спасибо.
Аноним
Аноним
Привет!
Первую часть вопроса можно реализовать воспользовавшись рецептом, описанным в этой статье.

Т.е. открываете 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
Аноним
Аноним
Александр душевное Вам спасибо, за развёрнутый ответ. Получилось сделать, чтобы сохранялись значений поля tv1 в этой таблице, но я что-то походу намудрил в создании таблицы, сделал скрины что у меня вышло:

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


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


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

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

Аноним
Аноним
Александр всё работает ищё раз огромное спасибо, фильтрация тоже, только не понятны некоторые вещи, скажите, значения тв в таблице добавляются слитно, это нормально?

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

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

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

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

Аноним
Аноним
Да, они дублируются, иначе нужно было бы переписывать уже существующую логику на страницах. А так она будет использоваться там, где нужно сократить время. Например, если используется 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]]
Аноним
Аноним
Да, для дублирования TV в своей таблице нужно не только это выполнить, а также обновить схему компонента и сгенерировать ему новую модель.