Добавляем сортировку по умолчанию в фильтрах Vtiger

Добавляем сортировку по умолчанию в фильтрах Vtiger

За более чем 10 лет работы с Vtiger мною было реализовано множество проектов и доработок. И один из наиболее часто встречающихся запросов - это сортировка по умолчанию в фильтрах.

Vtiger предоставляет удобный инструмент создания пользовательских фильтров. Каждый пользователь может настроить под себя отображение списка модулей. Выбрать нужные колонки в таблице, отфильтровать записи. Но нельзя настроить сортировку по умолчанию.

Ниже я покажу, какие изменения следует внести в код, чтобы у вас появилась такая возможность.

Во-первых, нам нужно внести изменения в базу данных, где мы будем хранить данные сортировки по умолчанию:

alter table vtiger_customview

add sortingfield varchar(200) null;

 

alter table vtiger_customview

add sortingdirect varchar(10) null;

 

Т.е. мы добавляем два столбца в таблицу vtiger_customview: sortingfield и sortingdirect.

Затем меняем файл modules/CustomView/views/EditAjax.php, функцию process.

Добавляем строчки после данного цикла, в районе строки 107:

foreach ($customViewSharedMembers as $memberGroupLabel => $membersList) {

if(count($membersList) > 0){

$listShared = true;

break;

}

}

 

Добавляем:

 

$sortField = $customViewModel->get('sortingfield');

$sortDirect = $customViewModel->get('sortingdirect');

$viewer->assign('SORTING_FIELD',$sortField);

$viewer->assign('SORTING_DIRECT',$sortDirect);

 

Далее в файле layouts/v7/modules/CustomView/EditView.tpl отрисовываем непосредственно сам блок с сортировкой.

После блока, в районе строки 119:

<div>

<label class="filterHeaders">{vtranslate('LBL_CHOOSE_FILTER_CONDITIONS', $MODULE)} :</label>

<div class="filterElements well filterConditionContainer filterConditionsDiv">

{include file='AdvanceFilter.tpl'|@vtemplate_path}

</div>

</div>

 

добавляем следующий:

 

<div class="marginBottom10px">

<label class="filterHeaders">Sorting Conditions</label>

<div class="filterElements filterConditionContainer filterConditionsDiv">

<div class="row">

<div class="col-lg-6">

<select class="select2 col-lg-6" name="sortingfield">

<option value="none">{vtranslate('LBL_SELECT_FIELD',$MODULE)}</option>

{foreach key=BLOCK_LABEL item=BLOCK_FIELDS from=$RECORD_STRUCTURE}

<optgroup label='{vtranslate($BLOCK_LABEL, $SOURCE_MODULE)}'>

{foreach key=FIELD_NAME item=FIELD_MODEL from=$BLOCK_FIELDS}

{assign var=FIELD_INFO value=$FIELD_MODEL->getFieldInfo()}

{assign var=MODULE_MODEL value=$FIELD_MODEL->getModule()}

{assign var="SPECIAL_VALIDATOR" value=$FIELD_MODEL->getValidator()}

{if !empty($COLUMNNAME_API)}

{assign var=columnNameApi value=$COLUMNNAME_API}

{else}

{assign var=columnNameApi value=getCustomViewColumnName}

{/if}

<option value="{$FIELD_MODEL->$columnNameApi()}" data-fieldtype="{$FIELD_MODEL->getFieldType()}" data-field-name="{$FIELD_NAME}"

{if decode_html($FIELD_MODEL->$columnNameApi()) eq decode_html($SORTING_FIELD)}

{assign var=FIELD_TYPE value=$FIELD_MODEL->getFieldType()}

{assign var=SELECTED_FIELD_MODEL value=$FIELD_MODEL}

{if $FIELD_MODEL->getFieldDataType() == 'reference'  ||  $FIELD_MODEL->getFieldDataType() == 'multireference'}

{$FIELD_TYPE='V'}

{/if}

{$FIELD_INFO['value'] = decode_html($SORTING_FIELD)}

selected="selected"

{/if}

{if ($MODULE_MODEL->get('name') eq 'Calendar' || $MODULE_MODEL->get('name') eq 'Events') && ($FIELD_NAME eq 'recurringtype')}

{assign var=PICKLIST_VALUES value = Calendar_Field_Model::getReccurencePicklistValues()}

{$FIELD_INFO['picklistvalues'] = $PICKLIST_VALUES}

{/if}

{if ($MODULE_MODEL->get('name') eq 'Calendar') && ($FIELD_NAME eq 'activitytype')}

{$FIELD_INFO['picklistvalues']['Task'] = vtranslate('Task', 'Calendar')}

{/if}

{if $FIELD_MODEL->getFieldDataType() eq 'reference'}

{assign var=referenceList value=$FIELD_MODEL->getWebserviceFieldObject()->getReferenceList()}

{if is_array($referenceList) && in_array('Users', $referenceList)}

{assign var=USERSLIST value=array()}

{assign var=CURRENT_USER_MODEL value = Users_Record_Model::getCurrentUserModel()}

{assign var=ACCESSIBLE_USERS value = $CURRENT_USER_MODEL->getAccessibleUsers()}

{foreach item=USER_NAME from=$ACCESSIBLE_USERS}

{$USERSLIST[$USER_NAME] = $USER_NAME}

{/foreach}

{$FIELD_INFO['picklistvalues'] = $USERSLIST}

{$FIELD_INFO['type'] = 'picklist'}

{/if}

{/if}

data-fieldinfo='{Vtiger_Util_Helper::toSafeHTML(ZEND_JSON::encode($FIELD_INFO))}'

{if !empty($SPECIAL_VALIDATOR)}data-validator='{Zend_Json::encode($SPECIAL_VALIDATOR)}'{/if}>

{if $SOURCE_MODULE neq $MODULE_MODEL->get('name')}

({vtranslate($MODULE_MODEL->get('name'), $MODULE_MODEL->get('name'))}) {vtranslate($FIELD_MODEL->get('label'), $MODULE_MODEL->get('name'))}

{else}

{vtranslate($FIELD_MODEL->get('label'), $SOURCE_MODULE)}

{/if}

</option>

{/foreach}

</optgroup>

{/foreach}

{* Required to display event fields also while adding conditions *}

{foreach key=BLOCK_LABEL item=BLOCK_FIELDS from=$EVENT_RECORD_STRUCTURE}

<optgroup label='{vtranslate($BLOCK_LABEL, 'Events')}'>

{foreach key=FIELD_NAME item=FIELD_MODEL from=$BLOCK_FIELDS}

{assign var=FIELD_INFO value=$FIELD_MODEL->getFieldInfo()}

{assign var=MODULE_MODEL value=$FIELD_MODEL->getModule()}

{if !empty($COLUMNNAME_API)}

{assign var=columnNameApi value=$COLUMNNAME_API}

{else}

{assign var=columnNameApi value=getCustomViewColumnName}

{/if}

<option value="{$FIELD_MODEL->$columnNameApi()}" data-fieldtype="{$FIELD_MODEL->getFieldType()}" data-field-name="{$FIELD_NAME}"

{if decode_html($FIELD_MODEL->$columnNameApi()) eq $SORTING_FIELD}

{assign var=FIELD_TYPE value=$FIELD_MODEL->getFieldType()}

{assign var=SELECTED_FIELD_MODEL value=$FIELD_MODEL}

{if $FIELD_MODEL->getFieldDataType() == 'reference' || $FIELD_MODEL->getFieldDataType() == 'multireference'}

{$FIELD_TYPE='V'}

{/if}

{$FIELD_INFO['value'] = decode_html($SORTING_FIELD)}

selected="selected"

{/if}

{if ($MODULE_MODEL->get('name') eq 'Calendar' || $MODULE_MODEL->get('name') eq 'Events') && ($FIELD_NAME eq 'recurringtype')}

{assign var=PICKLIST_VALUES value = Calendar_Field_Model::getReccurencePicklistValues()}

{$FIELD_INFO['picklistvalues'] = $PICKLIST_VALUES}

{/if}

{if $FIELD_MODEL->getFieldDataType() eq 'reference'}

{assign var=referenceList value=$FIELD_MODEL->getWebserviceFieldObject()->getReferenceList()}

{if is_array($referenceList) && in_array('Users', $referenceList)}

{assign var=USERSLIST value=array()}

{assign var=CURRENT_USER_MODEL value = Users_Record_Model::getCurrentUserModel()}

{assign var=ACCESSIBLE_USERS value = $CURRENT_USER_MODEL->getAccessibleUsers()}

{foreach item=USER_NAME from=$ACCESSIBLE_USERS}

{$USERSLIST[$USER_NAME] = $USER_NAME}

{/foreach}

{$FIELD_INFO['picklistvalues'] = $USERSLIST}

{$FIELD_INFO['type'] = 'picklist'}

{/if}

{/if}

data-fieldinfo='{Vtiger_Util_Helper::toSafeHTML(ZEND_JSON::encode($FIELD_INFO))}' >

{if $SOURCE_MODULE neq $MODULE_MODEL->get('name')}

({vtranslate($MODULE_MODEL->get('name'), $MODULE_MODEL->get('name'))})  {vtranslate($FIELD_MODEL->get('label'), $MODULE_MODEL->get('name'))}

{else}

{vtranslate($FIELD_MODEL->get('label'), $SOURCE_MODULE)}

{/if}

</option>

{/foreach}

</optgroup>

{/foreach}

</select>

</div>

<div class="col-lg-6">

<select class="select2 col-lg-6" name="sortingdirect">

<option value="Asc" {if $SORTING_DIRECT eq 'Asc'}selected="true"{/if}>Asc</option>

<option value="Desc" {if $SORTING_DIRECT eq 'Desc'}selected="true"{/if}>Desc</option>

</select>

</div>

</div>

</div>

</div>

 

Также нам необходимо сделать так, чтобы данные из формы попадали в базу. 

Файл modules/CustomView/actions/Save.php в районе строки 80 перед выражением:

 

return $customViewModel->setData($customViewData);

 

Добавляем:

        $sortingfield = $request->get('sortingfield');

        if(!empty($sortingfield)) {

            $customViewData['sortingfield'] = $sortingfield;

        }

        $sortingdirect = $request->get('sortingdirect');

        if(!empty($sortingdirect)) {

            $customViewData['sortingdirect'] = $sortingdirect;

        }

 

И конечно же нам надо будет поправить запросы по добавлению сортировки в базу. Файл modules/CustomView/models/Record.php, функция save.

В районе строки 260, после 

$status = $this->get('status');

добавляем:

$sortingfield = $this->get('sortingfield');

$sortingdirect = $this->get('sortingdirect');

Также около строки 272 меняем сам запрос на следующий:

$sql = 'INSERT INTO vtiger_customview(cvid, viewname, setdefault, setmetrics, entitytype, status, userid, sortingfield, sortingdirect) VALUES (?,?,?,?,?,?,?,?,?)';

$params = array($cvId, $viewName, $setDefault, $setMetrics, $moduleName, $status, $currentUserModel->getId(), $sortingfield, $sortingdirect);

 

Аналогичный трюк следует проделать и около строки 280, поменяв запрос на обновление записи:

 

$sql = 'UPDATE vtiger_customview SET viewname=?, setdefault=?, setmetrics=?, status=?, sortingfield=?, sortingdirect=? WHERE cvid=?';

$params = array($viewName, $setDefault, $setMetrics, $status, $sortingfield, $sortingdirect, $cvId);

 

Далее можно приступать к непосредственной сортировке таблицы.

Для начала создадим необходимые методы для получения сортировки. Внесём их в файл modules/CustomView/CustomView.php

 

function getSortFieldByCvid($cvid)

{

$cv = $this->getCustomViewByCvid($cvid);

if (!empty($cv) && isset($cv['sortingfield']) && $cv['sortingfield']) {

return $cv['sortingfield'];

} else {

return false;

}

}

 

function getSortDirectByCvid($cvid)

{

$cv = $this->getCustomViewByCvid($cvid);

if (!empty($cv) && isset($cv['sortingdirect']) && $cv['sortingdirect']) {

return $cv['sortingdirect'];

} else {

return false;

}

}

 

Чтобы они заработали, нужно внести изменения в функцию getCustomViewByCvid в том же файле, в районе строки 181. Нужно добавить две строчки:

$customviewlist["sortingfield"] = $cvrow["sortingfield"];

$customviewlist["sortingdirect"] = $cvrow["sortingdirect"];

 

Для успешной сортировки, нужно внести изменения в файл modules/Vtiger/models/ListView.php

Для начала создадим новые методы, внеся их в этот файл.

protected function generateDefaultOrderBy($moduleName, $pagingModel)

    {

        $viewid = ListViewSession::getCurrentView($moduleName);

        if(empty($viewid)) {

            $viewid = $pagingModel->get('viewid');

        }

        $customView = new CustomView($moduleName);

        $sortfield = $customView->getSortFieldByCvid($viewid);

        $sortdirect = $customView->getSortDirectByCvid($viewid);

        if ($sortfield) {

            $orderBy = $this->parseFieldName($sortfield);

            $sortOrder = strtoupper($sortdirect);

            return ' ORDER BY ' . $orderBy . ' ' . $sortOrder;

        } else {

            return ' ORDER BY vtiger_crmentity.modifiedtime DESC';

        }

    }

 

    protected function parseFieldName($field)

    {

        $fieldArr = explode(':', $field);

        return $fieldArr[0] . '.' . $fieldArr[1];

    }

 

    И изменим поведение сортировки по умолчанию, изменив функцию getListViewEntries в районе строки 249

    Нужно изменить строчку

$listQuery .= ' ORDER BY vtiger_crmentity.modifiedtime DESC';

на следующую:

    $listQuery .= $this->generateDefaultOrderBy($moduleName, $pagingModel);

После проведения всех этих манипуляций, в настройках фильтров у вас должен появиться рабочий раздел по пользовательской сортировки данных в таблице.

 

Популярное

Самые популярные посты

Как быть максимально продуктивным на удалённой работе?
Business

Как быть максимально продуктивным на удалённой работе?

Я запустил собственный бизнес и намеренно сделал всё возможное, чтобы работать из любой точки мира. Иногда я сижу с своём кабинете с большим 27-дюймовым монитором в своей квартире в г. Чебоксары. Иногда я нахожусь в офисе или в каком-нибудь кафе в другом городе.

Привет! Меня зовут Сергей Емельянов и я трудоголик
Business PHP

Привет! Меня зовут Сергей Емельянов и я трудоголик

Я программист. В душе я предприниматель. Я начал зарабатывать деньги с 11 лет, в суровые 90-е годы, сдавая стеклотару в местный магазин и обменивая её на сладости. Я зарабатывал столько, что хватало на разные вкусняшки.

Акция! Профессиональный разработчик CRM за 2000 руб. в час

Выделю время под ваш проект. Знания технологий Vtiger CRM, SuiteCRM, Laravel, Vue.js, Golang, React.js. Предлагаю варианты сотрудничества, которые помогут вам воспользоваться преимуществами внешнего опыта, оптимизировать затраты и снизить риски. Полная прозрачность всех этапов работы и учёт временных затрат. Оплачивайте только рабочие часы разработки после приемки задачи. Экономьте на платежах по его содержанию разработчика в штате. Возможно заключение договора по ИП. С чего начать, чтобы нанять профессионального разработчика на full-time? Просто заполните форму!

Telegram
@sergeyem
Telephone
+4915211100235