Вход Регистрация
Файл: system/controllers/content/model.php
Строк: 2991
<?php

class modelContent extends cmsModel {

    protected 
$pub_filter_disabled false;
    protected 
$pub_filtered false;

    private static 
$all_ctypes null;

    public function 
__construct() {

        
parent::__construct();

        
$this->loadAllCtypes();

    }

//============================================================================//
//=======================    ТИПЫ КОНТЕНТА   =================================//
//============================================================================//

    
public function addContentType($ctype){

        if(!isset(
$ctype['labels'])){
            
$ctype['labels'] = array(
                
'one'     => $ctype['name'],
                
'two'     => $ctype['name'],
                
'many'    => $ctype['name'],
                
'create'  => $ctype['name'],
                
'list'    => '',
                
'profile' => ''
            
);
        }

        
$id $this->insert('content_types'$ctype);

        
$config cmsConfig::getInstance();

        
// получаем структуру таблиц для хранения контента данного типа
        
$content_table_struct      $this->getContentTableStruct();
        
$fields_table_struct       $this->getFieldsTableStruct();
        
$props_table_struct        $this->getPropsTableStruct();
        
$props_bind_table_struct   $this->getPropsBindTableStruct();
        
$props_values_table_struct $this->getPropsValuesTableStruct();

        
// создаем таблицы
        
$table_name $this->table_prefix $ctype['name'];

        
$this->db->createTable($table_name$content_table_struct);
        
$this->db->createTable("{$table_name}_fields"$fields_table_struct$config->db_engine);
        
$this->db->createCategoriesTable("{$table_name}_cats");
        
$this->db->createCategoriesBindsTable("{$table_name}_cats_bind");

        
$this->db->createTable("{$table_name}_props"$props_table_struct$config->db_engine);
        
$this->db->createTable("{$table_name}_props_bind"$props_bind_table_struct$config->db_engine);
        
$this->db->createTable("{$table_name}_props_values"$props_values_table_struct$config->db_engine);

        
//
        // добавляем стандартные поля
        //

        // заголовок
        
$this->addContentField($ctype['name'], array(
            
'name' => 'title',
            
'title' => LANG_TITLE,
            
'type' => 'caption',
            
'ctype_id' => $id,
            
'is_in_list' => 1,
            
'is_in_item' => 1,
            
'is_in_filter' => 1,
            
'is_fixed' => 1,
            
'is_fixed_type' => 1,
            
'is_system' => 0,
            
'options' => array(
                
'label_in_list' => 'none',
                
'label_in_item' => 'none',
                
'min_length' => 3,
                
'max_length' => 255,
                
'is_required' => true
            
)
        ), 
true);

        
// дата публикации
        
$this->addContentField($ctype['name'], array(
            
'name' => 'date_pub',
            
'title' => LANG_DATE_PUB,
            
'type' => 'date',
            
'ctype_id' => $id,
            
'is_in_list' => 1,
            
'is_in_item' => 1,
            
'is_in_filter' => 1,
            
'is_fixed' => 1,
            
'is_fixed_type' => 1,
            
'is_system' => 1,
            
'options' => array(
                
'label_in_list' => 'none',
                
'label_in_item' => 'left',
                
'show_time' => true
            
)
        ), 
true);

        
// автор
        
$this->addContentField($ctype['name'], array(
            
'name' => 'user',
            
'title' => LANG_AUTHOR,
            
'type' => 'user',
            
'ctype_id' => $id,
            
'is_in_list' => 1,
            
'is_in_item' => 1,
            
'is_in_filter' => 0,
            
'is_fixed' => 1,
            
'is_fixed_type' => 1,
            
'is_system' => 1,
            
'options' => array(
                
'label_in_list' => 'none',
                
'label_in_item' => 'left'
            
)
        ), 
true);

        
// фотография
        
$this->addContentField($ctype['name'], array(
            
'name' => 'photo',
            
'title' => LANG_PHOTO,
            
'type' => 'image',
            
'ctype_id' => $id,
            
'is_in_list' => 1,
            
'is_in_item' => 1,
            
'is_fixed' => 1,
            
'options' => array(
                
'size_teaser' => 'small',
                
'size_full' => 'normal',
                
'sizes' => array('micro''small''normal''big')
            )
        ), 
true);

        
// описание
        
$this->addContentField($ctype['name'], array(
            
'name' => 'content',
            
'title' => LANG_DESCRIPTION,
            
'type' => 'text',
            
'ctype_id' => $id,
            
'is_in_list' => 1,
            
'is_in_item' => 1,
            
'is_fixed' => 1,
            
'options' => array(
                
'label_in_list' => 'none',
                
'label_in_item' => 'none'
            
)
        ), 
true);

        
cmsCache::getInstance()->clean('content.types');

        return 
$id;

    }

//============================================================================//
//============================================================================//

    
public function updateContentType($id$item){

        
cmsCache::getInstance()->clean('content.types');

        return 
$this->update('content_types'$id$item);

    }

//============================================================================//
//============================================================================//

    
public function deleteContentType($id){

        
$ctype $this->getContentType($id);

        if (
$ctype['is_fixed']) { return false; }

        
$this->disableDeleteFilter()->disableApprovedFilter()->
                
disablePubFilter()->disablePrivacyFilter();

        
$items $this->getContentItems($ctype['name']);
        if (
$items){
            foreach(
$items as $item){
                
$this->deleteContentItem($ctype['name'], $item['id']);
            }
        }

        
cmsCore::getModel('tags')->recountTagsFrequency();

        
$this->delete('content_types'$id);
        
$this->delete('content_datasets'$id'ctype_id');

        
$table_name $this->table_prefix $ctype['name'];

        
$this->db->dropTable("{$table_name}");
        
$this->db->dropTable("{$table_name}_fields");
        
$this->db->dropTable("{$table_name}_cats");
        
$this->db->dropTable("{$table_name}_filters");
        
$this->db->dropTable("{$table_name}_cats_bind");
        
$this->db->dropTable("{$table_name}_props");
        
$this->db->dropTable("{$table_name}_props_bind");
        
$this->db->dropTable("{$table_name}_props_values");

        
cmsCache::getInstance()->clean('content.types');

        
// связь как родитель
        
$relations $this->getContentRelations($id);

        if(
$relations){
            foreach (
$relations as $relation) {

                
$this->deleteContentRelation($relation['id']);

                
$parent_field_name "parent_{$ctype['name']}_id";

                if(
$relation['target_controller'] != 'content'){

                    
$this->setTablePrefix('');

                    
$target_ctype = array(
                        
'name' => $relation['target_controller']
                    );

                } else {

                    
$this->setTablePrefix(cmsModel::DEFAULT_TABLE_PREFIX);

                    
$target_ctype $this->getContentType($relation['child_ctype_id']);

                }

                if (
$this->isContentFieldExists($target_ctype['name'], $parent_field_name)){
                    
$this->deleteContentField($target_ctype['name'], $parent_field_name'name'true);
                }

            }
        }

        
// связь как дочка
        
$relations $this->filterEqual('child_ctype_id'$id)->getContentRelations();
        if(
$relations){
            foreach (
$relations as $relation) {
                
$this->deleteContentRelation($relation['id']);
            }
        }

        return 
true;

    }

//============================================================================//
//============================================================================//

    
public function getContentTypesCount(){

        if(!
self::$all_ctypes){
            return 
0;
        }

        return 
count(self::$all_ctypes);

    }

//============================================================================//
//============================================================================//

    
public function loadAllCtypes() {

        return !isset(
self::$all_ctypes) ? $this->reloadAllCtypes() : $this;

    }

    public function 
reloadAllCtypes($enabled true) {

        if(
$enabled){
            
$this->filterEqual('is_enabled'1);
        }

        
self::$all_ctypes $this->getContentTypesFiltered();
        return 
$this;
    }

    public function 
getContentTypes(){
        return 
self::$all_ctypes;
    }

    public function 
getContentTypesFiltered(){

        
$this->useCache('content.types');

        if (!
$this->order_by){ $this->orderBy('ordering'); }

        return 
$this->get('content_types', function($item$model){

            
$item['options'] = cmsModel::yamlToArray($item['options']);
            
$item['labels'] = cmsModel::yamlToArray($item['labels']);

            
// YAML некорректно преобразовывает пустые значения массива
            // убрать после перевода всего на JSON
            
if(!empty($item['options']['list_style'])){
                if(
is_array($item['options']['list_style'])){
                    
$list_styles = array();
                    foreach (
$item['options']['list_style'] as $key => $value) {
                        
$list_styles[$key] = is_array($value) ? '' $value;
                    }
                    
$item['options']['list_style'] = $list_styles;
                }
            }
            if(!empty(
$item['options']['context_list_cover_sizes'])){
                if(
is_array($item['options']['context_list_cover_sizes'])){
                    
$list_styles = array();
                    foreach (
$item['options']['context_list_cover_sizes'] as $key => $value) {
                        
$list_styles[$key?$key:''] = $value;
                    }
                    
$item['options']['context_list_cover_sizes'] = $list_styles;
                }
            }

            return 
$item;

        });

    }

    public function 
getContentTypesCountFiltered(){
        return 
$this->getCount('content_types');
    }

    public function 
getContentTypesNames(){

        if(!
self::$all_ctypes){
            return 
false;
        }

        foreach (
self::$all_ctypes as $ctype_id => $ctype) {
            
$names[$ctype_id] = $ctype['name'];
        }

        return 
$names;

    }

    public function 
reorderContentTypes($ctypes_ids_list){

        
$this->reorderByList('content_types'$ctypes_ids_list);

        
cmsCache::getInstance()->clean('content.types');

        return 
true;

    }

//============================================================================//
//============================================================================//

    
public function getContentType($id$by_field='id'){

        if(!
self::$all_ctypes){
            return 
false;
        }

        foreach (
self::$all_ctypes as $ctype_id => $ctype) {

            if(
$ctype[$by_field] == $id) {
                return 
$ctype;
            }

        }

        return 
false;

    }

    public function 
getContentTypeByName($name){
        return 
$this->getContentType($name'name');
    }

//============================================================================//
//======================    ПАПКИ КОНТЕНТА   =================================//
//============================================================================//

    
public function addContentFolder($ctype_id$user_id$title) {
        return 
$this->insert('content_folders', [
            
'ctype_id' => $ctype_id,
            
'user_id'  => $user_id,
            
'title'    => $title
        
]);
    }

    public function 
getContentFolders($ctype_id$user_id) {
        return 
$this->filterEqual('ctype_id'$ctype_id)->
                
filterEqual('user_id'$user_id)->
                
get('content_folders');
    }

    public function 
getContentFolder($id) {
        return 
$this->joinUserLeft()->getItemById('content_folders'$id, function($item$model){
            
$item['user'] = array(
                
'id'        => $item['user_id'],
                
'slug'      => $item['user_slug'],
                
'nickname'  => $item['user_nickname'],
                
'avatar'    => $item['user_avatar']
            );
            return 
$item;
        });
    }

    public function 
getContentFolderByTitle($title$ctype_id$user_id) {
        return 
$this->filterEqual('ctype_id'$ctype_id)->
                
filterEqual('user_id'$user_id)->
                
getItemByField('content_folders''title'$title);
    }

    public function 
updateContentFolder($id$folder) {
        return 
$this->update('content_folders'$id$folder);
    }

    public function 
deleteContentFolder($folder$is_delete_content true) {

        
$ctype $this->getContentType($folder['ctype_id']);

        
$this->filterEqual('folder_id'$folder['id']);

        if (!
$is_delete_content) {
            
$table_name $this->table_prefix $ctype['name'];
            
$this->updateFiltered($table_name, [
                
'folder_id' => null
            
]);
        }

        if (
$is_delete_content) {

            
$this->disableDeleteFilter()->disableApprovedFilter()->
                    
disablePubFilter()->disablePrivacyFilter();

            
$items $this->getContentItems($ctype['name']);

            if (
$items) {
                foreach (
$items as $item) {
                    
$this->deleteContentItem($ctype['name'], $item['id']);
                }
            }
        }

        return 
$this->delete('content_folders'$folder['id']);
    }

//============================================================================//
//=======================    ПОЛЯ КОНТЕНТА   =================================//
//============================================================================//

    
public function getDefaultContentFieldOptions() {
        return [
            
'is_required'           => 0,
            
'is_digits'             => 0,
            
'is_number'             => 0,
            
'is_alphanumeric'       => 0,
            
'is_email'              => 0,
            
'is_unique'             => 0,
            
'is_url'                => 0,
            
'disable_drafts'        => 0,
            
'is_date_range_process' => 'hide',
            
'label_in_list'         => 'none',
            
'label_in_item'         => 'none',
            
'wrap_type'             => 'auto',
            
'wrap_width'            => '',
            
'profile_value'         => '',
            
'is_in_item_pos'        => ['page']
        ];
    }

//============================================================================//
//============================================================================//

    
public function addContentField($ctype_name$field$is_virtual=false){

        
$content_table_name $this->table_prefix $ctype_name;
        
$fields_table_name  $this->table_prefix $ctype_name '_fields';

        
$field['ordering'] = $this->getNextOrdering($fields_table_name);

        if (!
$is_virtual){

            
$field_class  'field'.string_to_camel('_'$field['type']);
            
$field_parser = new $field_class(null, (isset($field['options']) ? array('options' => $field['options']) : null));

            
$sql "ALTER TABLE {#}{$content_table_name} ADD `{$field['name']}{$field_parser->getSQL()}";
            
$this->db->query($sql);

            
$field_parser->hookAfterAdd($content_table_name$field$this);

            if(
$field_parser->is_denormalization){

                
$cfield_name $field['name'].cmsFormField::FIELD_CACHE_POSTFIX;
                
$sql "ALTER TABLE {#}{$content_table_name} ADD `{$cfield_name}{$field_parser->getCacheSQL()}";
                
$this->db->query($sql);

            }

            if (!empty(
$field['is_in_filter']) && $field_parser->allow_index){
                
$this->db->addIndex($content_table_name$field['name']);
            }

        }

        
$field['id'] = $this->insert($fields_table_name$field);

        
cmsEventsManager::hook('ctype_field_after_add', array($field$ctype_name$this));

        
cmsCache::getInstance()->clean("content.fields.{$ctype_name}");

        
// если есть опция полнотекстового поиска
        
if(!$is_virtual && is_array($field['options']) && !empty($field['options']['in_fulltext_search'])){
            
// получаем полнотекстовый индекс для таблицы, он может быть только один
            
$fulltext_index $this->db->getTableIndexes($content_table_name'FULLTEXT');
            if(
$fulltext_index){
                
// название индекса
                
$index_name key($fulltext_index);
                
// поля индекса
                
$index_fields $fulltext_index[$index_name];
                
// ищем, нет ли такого поля уже в индексе, мало ли :-)
                
$key array_search($field['name'], $index_fields);
                
// не нашли, добавляем
                
if($key === false){
                    
// удаляем старый индекс
                    
$this->db->dropIndex($content_table_name$index_name);
                    
// создаем новый
                    
$this->createFullTextIndex($ctype_name$field['name']);
                }
            } else {
                
$this->createFullTextIndex($ctype_name$field['name']);
            }
        }

        return 
$field['id'];

    }

//============================================================================//
//============================================================================//

    
public function getContentFieldsCount($ctype_name){

        
$table_name $this->table_prefix $ctype_name '_fields';

        
$this->useCache('content.fields.'.$ctype_name);

        return 
$this->getCount($table_name);

    }

//============================================================================//
//============================================================================//

    
public function getContentFields($ctype_name$item_id false$enabled true) {

        
$table_name $this->table_prefix $ctype_name '_fields';

        
$this->useCache('content.fields.' $ctype_name);

        if (
$enabled) {
            
$this->filterEqual('is_enabled'1);
        }

        
$this->orderBy('ordering');

        
$fields $this->get($table_name, function($item$model) use ($ctype_name$item_id) {

            
$item['options']     = cmsModel::yamlToArray($item['options']);
            
$item['options']     = array_merge($model->getDefaultContentFieldOptions(), $item['options']);
            
$item['groups_read'] = cmsModel::yamlToArray($item['groups_read']);
            
$item['groups_add']  = cmsModel::yamlToArray($item['groups_add']);
            
$item['groups_edit'] = cmsModel::yamlToArray($item['groups_edit']);
            
$item['filter_view'] = cmsModel::yamlToArray($item['filter_view']);
            
$item['default']     = $item['values'];

            
$rules = [];
            if (
$item['options']['is_required']) { $rules[] = ['required']; }
            if (
$item['options']['is_digits']) { $rules[] = ['digits']; }
            if (
$item['options']['is_number']) { $rules[] = ['number']; }
            if (
$item['options']['is_alphanumeric']) { $rules[] = ['alphanumeric']; }
            if (
$item['options']['is_email']) { $rules[] = ['email']; }
            if (!empty(
$item['options']['is_url'])) { $rules[] = ['url']; }

            if (
$item['options']['is_unique']) {
                if (!
$item_id) {
                    
$rules[] = ['unique'$model->table_prefix $ctype_name$item['name']];
                } else {
                    
$rules[] = ['unique_exclude'$model->table_prefix $ctype_name$item['name'], $item_id];
                }
            }

            
$item['rules'] = $rules;

            return 
$item;
        }, 
'name');

        
// чтобы сработала мультиязычность, если необходима
        // поэтому перебираем тут, а не выше
        
if ($fields) {
            foreach (
$fields as $name => $field) {

                
$field_class 'field' string_to_camel('_'$field['type']);

                
$field['handler'] = new $field_class($field['name']);

                
$field['handler_title'] = $field['handler']->getTitle();

                
$field_property $field; unset($field_property['type']);

                
$field['handler']->setOptions($field_property);

                
$fields[$name] = $field;
            }
        }

        return 
$fields;
    }

    public function 
getRequiredContentFields($ctype_name){

        
$fields $this->getContentFields($ctype_name);

        
$req_fields = array();

        foreach(
$fields as $field){
            if (
$field['options']['is_required']) {
                
$req_fields[] = $field;
            }
        }

        return 
$req_fields;

    }

//============================================================================//
//============================================================================//

    
public function getContentField($ctype_name$id$by_field 'id'){

        
$table_name $this->table_prefix $ctype_name '_fields';

        
$this->useCache('content.fields.'.$ctype_name);

        return 
$this->getItemByField($table_name$by_field$id, function($item$model){

            
$item['options'] = cmsModel::yamlToArray($item['options']);

            if (!
$item['is_system']){
                
$item['options'] = array_merge($model->getDefaultContentFieldOptions(), $item['options']);
            }

            
$item['groups_read'] = cmsModel::yamlToArray($item['groups_read']);
            
$item['groups_add']  = cmsModel::yamlToArray($item['groups_add']);
            
$item['groups_edit'] = cmsModel::yamlToArray($item['groups_edit']);
            
$item['filter_view'] = cmsModel::yamlToArray($item['filter_view']);

            
$field_class 'field' string_to_camel('_'$item['type']);

            
$handler = new $field_class($item['name']);

            
$item['parser_title'] = $handler->getTitle();

            
$handler->setOptions($item);

            
$item['parser'] = $handler;

            return 
$item;

        });

    }

    public function 
getContentFieldByName($ctype_name$name){

        return 
$this->getContentField($ctype_name$name'name');

    }

    public function 
isContentFieldExists($ctype_name$name){
        return 
$this->getContentField($ctype_name$name'name') !== false;
    }

//============================================================================//
//============================================================================//

    
public function reorderContentFields($ctype_name$fields_ids_list){

        
$table_name $this->table_prefix $ctype_name '_fields';

        
$this->reorderByList($table_name$fields_ids_list);

        
cmsCache::getInstance()->clean("content.fields.{$ctype_name}");

        return 
true;

    }

//============================================================================//
//============================================================================//

    
public function updateContentField($ctype_name$id$field){

        
$content_table_name $this->table_prefix $ctype_name;
        
$fields_table_name $this->table_prefix $ctype_name '_fields';

        
$field_old $this->getContentField($ctype_name$id);

        if (!
$field_old['is_system']){

            
$new_lenght = ((isset($field['options']) && !empty($field['options']['max_length'])) ? $field['options']['max_length'] : false);
            
$old_lenght = ((isset($field_old['options']) && !empty($field_old['options']['max_length'])) ? $field_old['options']['max_length'] : false);

            
$field_class   'field'.string_to_camel('_'$field['type']);
            
$field_handler = new $field_class(null, (isset($field['options']) ? array('options' => $field['options']) : null));

            
$field_handler->hookAfterUpdate($content_table_name$field$field_old$this);

            if ((
$field_old['name'] != $field['name']) || ($field_old['type'] != $field['type']) || ($new_lenght != $old_lenght)){

                if(
$field_old['type'] != $field['type']){ $this->db->dropIndex($content_table_name$field_old['name']); }

                
$sql "ALTER TABLE `{#}{$content_table_name}` CHANGE `{$field_old['name']}` `{$field['name']}{$field_handler->getSQL()}";
                
$this->db->query($sql);

                if((
$field_old['name'] != $field['name']) || ($field_old['type'] != $field['type'])){

                    
// поля денормализации
                    
$old_cfield_name $field_old['name'].cmsFormField::FIELD_CACHE_POSTFIX;
                    
$new_cfield_name $field['name'].cmsFormField::FIELD_CACHE_POSTFIX;

                    
$update_cache_sql "ALTER TABLE `{#}{$content_table_name}` CHANGE `{$old_cfield_name}` `{$new_cfield_name}{$field_handler->getCacheSQL()}";

                    
// изменилось только имя поля
                    
if($field_handler->is_denormalization && $field_old['type'] == $field['type']){

                        
$this->db->query($update_cache_sql);

                    }
                    
// изменился тип
                    
if($field_old['type'] != $field['type']){

                        if(
$field_old['parser']->is_denormalization && $field_handler->is_denormalization){

                            
$this->db->query($update_cache_sql);

                        } elseif(
$field_old['parser']->is_denormalization && !$field_handler->is_denormalization){

                            
$this->db->dropTableField($content_table_name$old_cfield_name);

                        } elseif(!
$field_old['parser']->is_denormalization && $field_handler->is_denormalization){

                            
$sql "ALTER TABLE {#}{$content_table_name} ADD `{$new_cfield_name}{$field_handler->getCacheSQL()}";
                            
$this->db->query($sql);

                        }

                    }

                    
// удаляем старый индекс
                    
$this->db->dropIndex($content_table_name$field_old['name']);

                    
// добавляем новый
                    
if ($field['is_in_filter'] && $field_handler->allow_index){
                        
$this->db->addIndex($content_table_name$field['name']);
                    }

                }

            }

            if (
$field['is_in_filter'] && $field_handler->allow_index && !$field_old['is_in_filter']){
                
$this->db->addIndex($content_table_name$field['name']);
            }

            if (!
$field['is_in_filter'] && $field_handler->allow_index && $field_old['is_in_filter']){
                
$this->db->dropIndex($content_table_name$field_old['name']);
            }

            
// если есть опция полнотекстового поиска и ее значение изменилось
            
if(is_array($field['options']) && array_key_exists('in_fulltext_search'$field['options'])){
                if(
$field['options']['in_fulltext_search'] != @$field_old['options']['in_fulltext_search']){
                    
// получаем полнотекстовый индекс для таблицы, он может быть только один
                    
$fulltext_index $this->db->getTableIndexes($content_table_name'FULLTEXT');
                    if(
$fulltext_index){
                        
// название индекса
                        
$index_name key($fulltext_index);
                        
// поля индекса
                        
$index_fields $fulltext_index[$index_name];
                        
// выключили опцию
                        
if(!$field['options']['in_fulltext_search']){
                            
$key array_search($field['name'], $index_fields);
                            
// нашли - удаляем из массива
                            
if($key !== false){
                                unset(
$index_fields[$key]);
                                
// удаляем индекс
                                
$this->db->dropIndex($content_table_name$index_name);
                                
// и создаем новый
                                
if($index_fields){
                                    
$this->db->addIndex($content_table_name$index_fields'''FULLTEXT');
                                }
                            }
                        }
                        
// включили опцию
                        
if($field['options']['in_fulltext_search']){
                            
// ищем, нет ли такого поля уже в индексе, мало ли :-)
                            
$key array_search($field['name'], $index_fields);
                            
// не нашли, добавляем
                            
if($key === false){
                                
// удаляем старый индекс
                                
$this->db->dropIndex($content_table_name$index_name);
                                
// создаем новый
                                
$this->createFullTextIndex($ctype_name$field['name']);
                            }
                        }

                    } elseif(
$field['options']['in_fulltext_search']) {
                        
$this->createFullTextIndex($ctype_name$field['name']);
                    }
                }
            }

        }

        
$result $this->update($fields_table_name$id$field);

        if (
$result){
            
$field['id'] = $id;
            
cmsEventsManager::hook('ctype_field_after_update', array($field$ctype_name$this));
            
cmsEventsManager::hook('ctype_field_'.str_replace(['{','}'], ''$ctype_name).'_after_update', array($field$this));
        }

        
cmsCache::getInstance()->clean('content.fields.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
$result;

    }

    
/**
     * Создает fulltext индекс согласно настроек полей типа контента
     * @param string $ctype_name Название типа контента
     * @param string|null $add_field Название поля, для которого принудительно нужно создать индекс
     * @return boolean
     */
    
public function createFullTextIndex($ctype_name$add_field=null) {

        
// важен порядок индексов, поэтому создаем их так, как они будут в запросе
        // для этого получаем все поля этого типа контента
        
$fields $this->getContentFields($ctype_name);

        foreach (
$fields as $field) {

            
$is_text $field['handler']->getOption('in_fulltext_search') || $field['name'] == $add_field;
            if(!
$is_text){ continue; }

            
$index_fields[] = $field['name'];

        }

        if(
$index_fields){
            
$this->db->addIndex($this->table_prefix $ctype_name$index_fields'''FULLTEXT'); return true;
        }

        return 
false;

    }
//============================================================================//
//============================================================================//

    
public function toggleContentFieldVisibility($ctype_name$id$mode$is_visible){

        
$fields_table_name $this->table_prefix $ctype_name '_fields';

        
$result $this->update($fields_table_name$id, array(
            
$mode => $is_visible
        
));

        
cmsCache::getInstance()->clean("content.fields.{$ctype_name}");

        return 
$result;

    }

//============================================================================//
//============================================================================//

    
public function deleteContentField($ctype_name_or_id$id$by_field='id'$isForced false){

        if (
is_numeric($ctype_name_or_id)){
            
$ctype $this->getContentType($ctype_name_or_id);
            
$ctype_name $ctype['name'];
        } else {
            
$ctype_name $ctype_name_or_id;
        }

        
$field $this->getContentField($ctype_name$id$by_field);
        if (
$field['is_fixed'] && !$isForced) { return false; }

        
cmsEventsManager::hook('ctype_field_before_delete', array($field$ctype_name$this));

        
$content_table_name $this->table_prefix $ctype_name;
        
$fields_table_name $this->table_prefix $ctype_name '_fields';

        
$this->delete($fields_table_name$id$by_field);
        
$this->reorder($fields_table_name);

        
cmsCache::getInstance()->clean("content.fields.{$ctype_name}");

        
$this->db->dropTableField($content_table_name$field['name']);

        
$field['parser']->hookAfterRemove($content_table_name$field$this);

        if(
$field['parser']->is_denormalization){
            
$this->db->dropTableField($content_table_name$field['parser']->getDenormalName());
        }

        return 
true;

    }

//============================================================================//
//============================================================================//

    
public function getContentFieldsets($ctype_id){

        if (
is_numeric($ctype_id)){
            
$ctype $this->getContentType($ctype_id);
            
$ctype_name $ctype['name'];
        } else {
            
$ctype_name $ctype_id;
        }

        
$table_name $this->table_prefix $ctype_name '_fields';

        
$this->useCache('content.fields.'.$ctype_name);

        
$this->groupBy('fieldset');

        if (!
$this->order_by){ $this->orderBy('fieldset'); }

        
$fieldsets $this->get($table_name, function($item$model){
            
$item $item['fieldset'];
            return 
$item;
        }, 
false);

        if (
$fieldsets[0] == '') { unset($fieldsets[0]); }

        return 
$fieldsets;

    }

//============================================================================//
//============================    СВОЙСТВА   =================================//
//============================================================================//

    
public function isContentPropsExists($ctype_name){

        
$props_table_name $this->table_prefix $ctype_name '_props';

        return (bool)
$this->getCount($props_table_name);

    }

    public function 
getContentPropsBinds($ctype_name$category_id false) {

        
$props_table_name $this->table_prefix $ctype_name '_props';
        
$bind_table_name $this->table_prefix $ctype_name '_props_bind';

        
$this->selectOnly('p.*');
        
$this->select('p.id''prop_id');
        
$this->select('i.id''id');
        
$this->select('i.cat_id''cat_id');

        
$this->join($props_table_name'p''p.id = i.prop_id');

        if (
$category_id){
            
$this->filterEqual('i.cat_id'$category_id);
        }

        
$this->orderBy('i.ordering');
        
$this->groupBy('p.id');

        return 
$this->get($bind_table_name);

    }

    public function 
getContentProps($ctype_name$category_id false) {

        
$props_table_name $this->table_prefix $ctype_name '_props';
        
$bind_table_name $this->table_prefix $ctype_name '_props_bind';

        if (
$category_id){
            
$this->selectOnly('p.*');
            
$this->select('c.title''cat_title');
            
$this->select('i.cat_id');
            
$this->join($props_table_name'p''p.id = i.prop_id');
            
$this->join($this->table_prefix $ctype_name '_cats''c''c.id = i.cat_id');
            if(
is_array($category_id)){
                
$this->filterIn('cat_id'$category_id);
            } else {
                
$this->filterEqual('cat_id'$category_id);
            }
            
$this->orderBy('ordering');
            
$table_name $bind_table_name;
        } else {
            
$table_name $props_table_name;
        }

        return 
$this->get($table_name, function($item$model){
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            return 
$item;
        });

    }

    public function 
getContentProp($ctype_name$id){

        
$props_table_name $this->table_prefix $ctype_name '_props';
        
$bind_table_name $this->table_prefix $ctype_name '_props_bind';

        
$prop $this->getItemById($props_table_name$id, function($item$model){
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            return 
$item;
        });

        
$this->filterEqual('prop_id'$id);

        
$prop['cats'] = $this->get($bind_table_name, function($item$model){
           return (int)
$item['cat_id'];
        });

        return 
$prop;

    }

    public function 
addContentProp($ctype_name$prop){

        
$table_name $this->table_prefix $ctype_name '_props';

        
$cats_list $prop['cats']; unset($prop['cats']);

        
$prop['id'] = $this->insert($table_name$prop);

        
$this->bindContentProp($ctype_name$prop['id'], $cats_list);

        
cmsEventsManager::hook('ctype_prop_after_add', array($prop$ctype_name$this));

        return 
$prop['id'];

    }

    public function 
updateContentProp($ctype_name$id$prop){

        
$table_name $this->table_prefix $ctype_name '_props';

        
$old_prop $this->getContentProp($ctype_name$id);

        
$missed_cats_list array_diff($old_prop['cats'], $prop['cats']);
        
$added_cats_list array_diff($prop['cats'], $old_prop['cats']);

        if (
$missed_cats_list) {
            foreach(
$missed_cats_list as $cat_id){
                
$this->unbindContentProp($ctype_name$id$cat_id);
            }
        }

        if (
$added_cats_list) {
            
$this->bindContentProp($ctype_name$id$added_cats_list);
        }

        unset(
$prop['cats']);

        
$result $this->update($table_name$id$prop);

        
$prop['id'] = $id;
        
cmsEventsManager::hook('ctype_prop_after_update', array($prop$ctype_name$this));

        return 
$result;

    }

    public function 
toggleContentPropFilter($ctype_name$id$is_in_filter){

        
$table_name $this->table_prefix $ctype_name '_props';

        return 
$this->update($table_name$id, array(
            
'is_in_filter' => $is_in_filter
        
));

    }


    public function 
deleteContentProp($ctype_name_or_id$prop_id){

        if (
is_numeric($ctype_name_or_id)){
            
$ctype $this->getContentType($ctype_name_or_id);
            
$ctype_name $ctype['name'];
        } else {
            
$ctype_name $ctype_name_or_id;
        }

        
$table_name $this->table_prefix $ctype_name '_props';

        
$prop $this->getContentProp($ctype_name$prop_id);

        
cmsEventsManager::hook('ctype_prop_before_delete', array($prop$ctype_name$this));

        foreach(
$prop['cats'] as $cat_id){
            
$this->unbindContentProp($ctype_name$prop_id$cat_id);
        }

        
$this->deleteContentPropValues($ctype_name$prop_id);

        return 
$this->delete($table_name$prop_id);

    }

    public function 
bindContentProp($ctype_name$prop_id$cats_list){

        
$table_name $this->table_prefix $ctype_name '_props_bind';

        foreach(
$cats_list as $cat_id){

            
$this->filterEqual('cat_id'$cat_id);

            
$ordering $this->getNextOrdering($table_name);

            
$this->insert($table_name, array(
                
'prop_id' => $prop_id,
                
'cat_id' => $cat_id,
                
'ordering' => $ordering
            
));

        }

        return 
true;

    }

    public function 
unbindContentProp($ctype_name$prop_id$cat_id){

        
$table_name $this->table_prefix $ctype_name '_props_bind';

        
$this->
            
filterEqual('prop_id'$prop_id)->
            
filterEqual('cat_id'$cat_id)->
            
deleteFiltered($table_name);

        
$this->
            
filterEqual('cat_id'$cat_id)->
            
reorder($table_name);

        return 
true;

    }

    public function 
unbindContentProps($ctype_name$cat_id){

        
$table_name $this->table_prefix $ctype_name '_props_bind';

        
$this->
            
filterEqual('cat_id'$cat_id)->
            
deleteFiltered($table_name);

        return 
true;

    }

    public function 
deleteContentPropValues($ctype_name$prop_id){

        
$table_name $this->table_prefix $ctype_name '_props_values';

        
$this->filterEqual('prop_id'$prop_id)->deleteFiltered($table_name);

        return 
true;

    }

    public function 
reorderContentProps($ctype_name$props_ids_list){

        
$table_name $this->table_prefix $ctype_name '_props_bind';

        
$this->reorderByList($table_name$props_ids_list);

        return 
true;

    }

    public function 
getContentPropsFieldsets($ctype_id){

        if (
is_numeric($ctype_id)){
            
$ctype $this->getContentType($ctype_id);
            
$ctype_name $ctype['name'];
        } else {
            
$ctype_name $ctype_id;
        }

        
$table_name $this->table_prefix $ctype_name '_props';

        
$this->groupBy('fieldset');
        
$this->orderBy('fieldset');

        
$fieldsets $this->get($table_name, function($item$model){
            
$item $item['fieldset'];
            return 
$item;
        }, 
false);

        if (
is_array($fieldsets) && $fieldsets[0] == '') { unset($fieldsets[0]); }

        return 
$fieldsets;

    }

    public function 
getPropsValues($ctype_name$item_id){

        
$table_name $this->table_prefix $ctype_name '_props_values';

        
$this->filterEqual('item_id'$item_id);

        return 
$this->get($table_name, function($item$model){
            return 
$item['value'];
        }, 
'prop_id');

    }

    public function 
addPropsValues($ctype_name$item_id$props_values){

        
$table_name $this->table_prefix $ctype_name '_props_values';

        foreach(
$props_values as $prop_id=>$value){

            
$this->insert($table_name, array(
                
'prop_id' => $prop_id,
                
'item_id' => $item_id,
                
'value' => $value
            
));

        }

    }

    public function 
updatePropsValues($ctype_name$item_id$props_values){

        
$table_name $this->table_prefix $ctype_name '_props_values';

        
$props_ids array_keys($props_values);

        
$this->
            
filterEqual('item_id'$item_id)->
            
filterIn('prop_id'$props_ids)->
            
deleteFiltered($table_name);

        
$this->addPropsValues($ctype_name$item_id$props_values);

    }

    public function 
deletePropsValues($ctype_name$item_id){

        
$table_name $this->table_prefix $ctype_name '_props_values';

        
$this->
            
filterEqual('item_id'$item_id)->
            
deleteFiltered($table_name);

    }

//============================================================================//
//===============================   СВЯЗИ   ==================================//
//============================================================================//

    
public function getContentRelations($ctype_id=false){

        if (
$ctype_id) { $this->filterEqual('ctype_id'$ctype_id); }

        
$this->useCache('content.relations');

        
$relations $this->get('content_relations', function($item){
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            return 
$item;
        });

        return 
$relations;

    }

    public function 
getContentRelation($id$by_field 'id'){

        return 
$this->getItemByField('content_relations'$by_field$id, function($item){
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            return 
$item;
        });

    }

    public function 
getContentRelationByTypes($ctype_id$child_ctype_id$target_controller 'content'){

        
$this->filterEqual('ctype_id'$ctype_id);
        
$this->filterEqual('child_ctype_id'$child_ctype_id);
        
$this->filterEqual('target_controller'$target_controller);

        return 
$this->getItem('content_relations', function($item){
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            return 
$item;
        });

    }

    public function 
addContentRelation($relation){

        
cmsCache::getInstance()->clean('content.relations');

        
$relation['ordering'] = $this->getNextOrdering('content_relations');

        return 
$this->insert('content_relations'$relation);

    }

    public function 
updateContentRelation($id$relation){

        
cmsCache::getInstance()->clean('content.relations');

        return 
$this->update('content_relations'$id$relation);

    }

    public function 
deleteContentRelation($id){

        
cmsCache::getInstance()->clean('content.relations');

        return 
$this->delete('content_relations'$id);

    }

    public function 
getContentTypeChilds($ctype_id){

        
$this->useCache('content.relations');

        
$this->selectOnly('i.*');
        
$this->select('c.title''child_title');
        
$this->select('c.labels''child_labels');
        
$this->select('c.name''child_ctype_name');

        
$this->joinLeft('content_types''c''c.id = i.child_ctype_id');

        
$this->filterEqual('ctype_id'$ctype_id);

        
$this->orderBy('ordering''asc');

        return 
$this->get('content_relations', function($item$model){

            
$item['child_labels'] = cmsModel::yamlToArray($item['child_labels']);
            
$item['options'] = cmsModel::yamlToArray($item['options']);
            if(empty(
$item['child_ctype_name'])){
                
$item['child_ctype_name'] = $item['target_controller'];
            }

            return 
$item;

        });

    }

    public function 
getContentTypeParents($ctype_id$target_controller 'content'){

        
$this->selectOnly('i.*');
        
$this->select('c.name''ctype_name');
        
$this->select('c.title''ctype_title');
        
$this->select('c.id''ctype_id');

        
$this->joinLeft('content_types''c''c.id = i.ctype_id');

        
$this->filterEqual('child_ctype_id'$ctype_id);
        
$this->filterEqual('target_controller'$target_controller);

        
$this->orderBy('ordering''asc');

        
$parents $this->get('content_relations');
        if (!
$parents) { return array(); }

        foreach (
$parents as $id => $parent){
            
$parents[$id]['id_param_name'] = 'parent_'.$parent['ctype_name'].'_id';
        }

        return 
$parents;

    }

    public function 
updateChildItemParentIds($relation){

        
$this->selectOnly('parent_item_id''id');

        
$this->filterEqual('parent_ctype_id'$relation['parent_ctype_id']);
        
$this->filterEqual('child_ctype_id'$relation['child_ctype_id']);
        
$this->filterEqual('child_item_id'$relation['child_item_id']);
        
$this->filterEqual('target_controller', (isset($relation['target_controller']) ? $relation['target_controller'] : 'content'));

        
$parent_items_ids $this->get('content_relations_bind', function($item$model){
            return 
$item['id'];
        }, 
false);

        if (
$parent_items_ids){

            
$ids trim(implode(','$parent_items_ids));

            if (
$ids){

                
$item_table $this->table_prefix $relation['child_ctype_name'];

                if(
$item_table == 'users'){ $item_table '{users}'; }

                
$this->update($item_table$relation['child_item_id'], array(
                   
'parent_'.$relation['parent_ctype_name'].'_id' => $ids
                
));

                
cmsCache::getInstance()->clean('content.list.'.$relation['child_ctype_name']);
                
cmsCache::getInstance()->clean('content.item.'.$relation['child_ctype_name']);

            }

        }

    }

    public function 
bindContentItemRelation($relation){

        
$id $this->insert('content_relations_bind'$relation);

        
$this->updateChildItemParentIds($relation);

        return 
$id;

    }

    public function 
unbindContentItemRelation($relation){

        
$this->filterEqual('parent_ctype_id'$relation['parent_ctype_id']);
        
$this->filterEqual('parent_item_id'$relation['parent_item_id']);
        
$this->filterEqual('child_ctype_id'$relation['child_ctype_id']);
        
$this->filterEqual('child_item_id'$relation['child_item_id']);
        
$this->filterEqual('target_controller', (isset($relation['target_controller']) ? $relation['target_controller'] : 'content'));

        
$this->deleteFiltered('content_relations_bind');

        
$this->updateChildItemParentIds($relation);

        return;

    }

    public function 
deleteContentItemRelations($ctype_id$item_id){

        
$this->filterEqual('child_ctype_id'$ctype_id);
        
$this->filterEqual('child_item_id'$item_id);

        
$this->deleteFiltered('content_relations_bind');

    }

    public function 
getContentItemParents($parent_ctype$child_ctype$item_id){

        if(empty(
$child_ctype['controller'])){
            
$child_ctype['controller'] = 'content';
        }

        
$this->selectOnly('i.*');

        
$parent_ctype_table $this->table_prefix $parent_ctype['name'];

        if(
$parent_ctype_table == 'users'){
            
$parent_ctype_table '{users}';
        }

        
$join_on =  "r.parent_ctype_id = '{$parent_ctype['id']}' AND " .
                    
'r.child_ctype_id '.(!empty($child_ctype['id']) ? '='.$child_ctype['id'] : 'IS NULL' ).' AND ' .
                    
"r.child_item_id = '{$item_id}' AND " .
                    
"r.parent_item_id = i.id AND r.target_controller = '{$child_ctype['controller']}'";

        
$this->joinInner('content_relations_bind''r'$join_on);

        return 
$this->get($parent_ctype_table);


    }

    public function 
reorderContentRelation($fields_ids_list){

        
$this->reorderByList('content_relations'$fields_ids_list);

        
cmsCache::getInstance()->clean('content.relations');

        return 
true;

    }

//============================================================================//
//=============================   Фильтры   ==================================//
//============================================================================//

    
public function getContentFilters($ctype_name){

        
$this->useCache('content.filters.'.$ctype_name);

        
$table_name $this->getContentTypeTableName($ctype_name).'_filters';

        return 
$this->get($table_name, function($item$model){

            
$item['filters'] = cmsModel::stringToArray($item['filters']);

            return 
$item;
        });

    }

    public function 
addContentFilter($filter$ctype){

        
$table_name $this->getContentTypeTableName($ctype['name']).'_filters';

        
$filter['filters'] = array_filter_recursive($filter['filters']);
        
array_multisort($filter['filters']);
        
$filter['hash'] = md5(json_encode($filter['filters']));

        
$filter['id'] = $this->insert($table_name$filtertrue);

        
cmsEventsManager::hook('ctype_filter_add', array($filter$ctype$this));
        
cmsEventsManager::hook('ctype_filter_'.$ctype['name'].'_add', array($filter$ctype$this));

        
cmsCache::getInstance()->clean('content.filters.'.$ctype['name']);

        return 
$filter['id'];

    }

    public function 
updateContentFilter($filter$ctype){

        list(
$filter$ctype) = cmsEventsManager::hook('ctype_filter_update', array($filter$ctype));
        list(
$filter$ctype) = cmsEventsManager::hook('ctype_filter_'.$ctype['name'].'_update', array($filter$ctype));

        
$table_name $this->getContentTypeTableName($ctype['name']).'_filters';

        
$filter['filters'] = array_filter_recursive($filter['filters']);
        
array_multisort($filter['filters']);
        
$filter['hash'] = md5(json_encode($filter['filters']));

        
$this->update($table_name$filter['id'], $filterfalsetrue);

        
cmsCache::getInstance()->clean('content.filters.'.$ctype['name']);

        return 
true;

    }

    public function 
getContentFilter($ctype$id$by_hash false){

        if(!
$this->isFiltersTableExists($ctype['name'])){
            return 
false;
        }

        
$table_name $this->getContentTypeTableName($ctype['name']).'_filters';

        
$this->useCache('content.filters.'.$ctype['name']);

        
$field_name 'id';
        if(!
is_numeric($id)){
            if(
$by_hash){
                
$field_name 'hash';
            } else {
                
$field_name 'slug';
            }
        }

        
$this->filterEqual($field_name$id);

        return 
$this->getItem($table_name, function($item$model) use($ctype){

            
$item['filters'] = cmsModel::stringToArray($item['filters']);
            
$item['ctype_name'] = $ctype['name'];

            return 
$item;

        });

    }

    public function 
deleteContentFilter($ctype$id){

        
$table_name $this->getContentTypeTableName($ctype['name']).'_filters';

        
$this->delete($table_name$id);

        
cmsCache::getInstance()->clean('content.filters.'.$ctype['name']);

        return 
true;

    }

//============================================================================//
//==============================   НАБОРЫ   ==================================//
//============================================================================//

    
public function getContentDatasets($ctype_id=false$only_visible=false$item_callback=false){

        if (
$ctype_id) {
            if(
is_numeric($ctype_id)){
                
$this->filterEqual('ctype_id'$ctype_id);
            } else {
                
$this->filterEqual('target_controller'$ctype_id);
            }
        }

        if (
$only_visible) { $this->filterEqual('is_visible'1); }

        
$this->orderBy('ordering');

        
$this->useCache('content.datasets');

        
$datasets $this->get('content_datasets', function($item$model) use($item_callback){

            
$item['groups_view'] = cmsModel::yamlToArray($item['groups_view']);
            
$item['groups_hide'] = cmsModel::yamlToArray($item['groups_hide']);
            
$item['cats_view']   = cmsModel::yamlToArray($item['cats_view']);
            
$item['cats_hide']   = cmsModel::yamlToArray($item['cats_hide']);
            
$item['filters']     = $item['filters'] ? cmsModel::yamlToArray($item['filters']) : array();
            
$item['sorting']     = $item['sorting'] ? cmsModel::yamlToArray($item['sorting']) : array();
            
$item['list']        = cmsModel::stringToArray($item['list']);

            if (
is_callable($item_callback)){
                
$item call_user_func_array($item_callback, array($item$model));
                if (
$item === false){ return false; }
            }

            return 
$item;

        }, 
'name');

        if (
$only_visible && $datasets){
            
$user cmsUser::getInstance();
            foreach(
$datasets as $id=>$dataset){
                
$is_user_view $user->isInGroups($dataset['groups_view']);
                
$is_user_hide = !empty($dataset['groups_hide']) && $user->isInGroups($dataset['groups_hide']) && !$user->is_admin;
                if (!
$is_user_view || $is_user_hide) { unset($datasets[$id]); }
            }
        }

        return 
$datasets;

    }

    public function 
getContentDataset($id){

        return 
cmsEventsManager::hook('ctype_dataset_get'$this->getItemById('content_datasets'$id, function($item$model){

            
$item['groups_view'] = cmsModel::yamlToArray($item['groups_view']);
            
$item['groups_hide'] = cmsModel::yamlToArray($item['groups_hide']);
            
$item['cats_view']   = cmsModel::yamlToArray($item['cats_view']);
            
$item['cats_hide']   = cmsModel::yamlToArray($item['cats_hide']);
            
$item['filters']     = $item['filters'] ? cmsModel::yamlToArray($item['filters']) : array();
            
$item['sorting']     = $item['sorting'] ? cmsModel::yamlToArray($item['sorting']) : array();
            
$item['list']        = cmsModel::stringToArray($item['list']);

            return 
$item;

        }));

    }

    public function 
deleteContentDatasetIndex($ctype_name$index_name) {

        
// если используется в других датасетах, не удаляем
        
if($this->getItemByField('content_datasets''index'$index_name)){
            return 
false;
        }

        return 
$this->db->dropIndex($this->table_prefix.$ctype_name$index_name);

    }

    public function 
addContentDatasetIndex($dataset$ctype_name) {

        
$content_table_name $this->table_prefix.$ctype_name;
        
$index_name         'dataset_'.$dataset['name'];

        
// поля для индекса
        
$filters_fields $sorting_fields $fields = array();

        
// создаем индекс
        // параметры выборки
        
if($dataset['filters']){
            foreach (
$dataset['filters'] as $filters) {
                if(
$filters && !in_array($filters['condition'], array('gt','lt','ge','le','nn','ni'))){
                    
$filters_fields[] = $filters['field'];
                }
            }
            
$filters_fields array_unique($filters_fields);
        }
        
// добавим условия, которые в каждой выборке
        // только для записей типов контента
        
if($this->table_prefix){
            
$filters_fields[] = 'is_pub';
            
$filters_fields[] = 'is_parent_hidden';
            
$filters_fields[] = 'is_deleted';
            
$filters_fields[] = 'is_approved';
        }
        
// сортировка
        
if($dataset['sorting']){
            foreach (
$dataset['sorting'] as $sorting) {
                if(
$sorting){
                    
$sorting_fields[] = $sorting['by'];
                }
            }
            
$sorting_fields array_unique($sorting_fields);
        }

        
// если поле присутствует и в выборке и в сортировке, оставляем только в сортировке
        
if($filters_fields){
            foreach (
$filters_fields as $key => $field) {
                if(
in_array($field$sorting_fields)){
                    unset(
$filters_fields[$key]);
                }
            }
        }

        
$fields array_merge($filters_fields$sorting_fields);

        if(!
$fields){ return null; }

        if(
$fields == array('date_pub')){
            
$index_name 'date_pub';
        } elseif(
$fields == array('user_id','date_pub') || $fields == array('user_id')){
            
$index_name 'user_id';
        } else {

            
// ищем индекс с таким же набором полей
            
$is_found false;
            
$indexes $this->db->getTableIndexes($content_table_name);
            foreach (
$indexes as $_index_name => $_index_fields) {
                if(
$fields == $_index_fields){
                    
$is_found $_index_name; break;
                }
            }

            
// нашли - используем его
            
if($is_found){
                
$index_name $is_found;
            } else {

                
// если нет, то создаем новый
                
$this->db->addIndex($content_table_name$fields$index_name);

            }

        }

        return 
$index_name;

    }

    public function 
addContentDataset($dataset$ctype){

        
$table_name 'content_datasets';

        
$dataset['ctype_id'] = $ctype['id'];

        
$this->filterEqual('ctype_id'$dataset['ctype_id']);

        
$dataset['ordering'] = $this->getNextOrdering($table_name);

        
$dataset['index'] = $this->addContentDatasetIndex($dataset$ctype['name']);

        
$dataset['list'] = cmsModel::arrayToString($dataset['list']);

        
$dataset['id'] = $this->insert($table_name$dataset);

        
cmsEventsManager::hook('ctype_dataset_add', array($dataset$ctype$this));

        
cmsCache::getInstance()->clean('content.datasets');

        return 
$dataset['id'];

    }

    public function 
updateContentDataset($id$dataset$ctype$old_dataset){

        
$dataset['ctype_id'] = $ctype['id'];

        
$dataset['list'] = cmsModel::arrayToString($dataset['list']);

        
$success $this->update('content_datasets'$id$dataset);

        
$dataset['id'] = $id;
        
cmsEventsManager::hook('ctype_dataset_update', array($dataset$ctype$this));

        
cmsCache::getInstance()->clean('content.datasets');

        if((
$old_dataset['sorting'] != $dataset['sorting']) || ($old_dataset['filters'] != $dataset['filters'])){

            
$this->deleteContentDatasetIndex($ctype['name'], $old_dataset['index']);

            
$index $this->addContentDatasetIndex($dataset$ctype['name']);

            
$this->update('content_datasets'$id, array('index'=>$index));

            
cmsCache::getInstance()->clean('content.datasets');

        }

        return 
$success;

    }

    public function 
toggleContentDatasetVisibility($id$is_visible){

        return 
$this->update('content_datasets'$id, array(
            
'is_visible' => $is_visible
        
));

    }

    public function 
reorderContentDatasets($fields_ids_list){

        
$this->reorderByList('content_datasets'$fields_ids_list);

        
cmsCache::getInstance()->clean('content.datasets');

        return 
true;

    }

    public function 
deleteContentDataset($id){

        
$dataset $this->getContentDataset($id);
        if(!
$dataset){ return false; }

        if(
$dataset['ctype_id']){
            
$ctype $this->getContentType($dataset['ctype_id']);
            if (!
$ctype) { return false; }
        } else {
            
$ctype = array(
                
'title' => string_lang($dataset['target_controller'].'_controller'),
                
'name'  => $dataset['target_controller'],
                
'id'    => null
            
);
            
$this->setTablePrefix('');
        }

        
cmsEventsManager::hook('ctype_dataset_before_delete', array($dataset$ctype$this));

        
$this->delete('content_datasets'$id);

        
$this->deleteContentDatasetIndex($ctype['name'], $dataset['index']);

        
cmsCache::getInstance()->clean('content.datasets');

        return 
true;

    }

//============================================================================//
//=============================   КОНТЕНТ   ==================================//
//============================================================================//

    
public function resetFilters(){
        
parent::resetFilters();
        
$this->pub_filtered false;
        return 
$this;
    }

    public function 
enablePubFilter(){
        
$this->pub_filter_disabled false;
        return 
$this;
    }

    public function 
disablePubFilter(){
        
$this->pub_filter_disabled true;
        return 
$this;
    }

    public function 
filterPublishedOnly(){

        if (
$this->pub_filtered) { return $this; }

        
$this->pub_filtered true;

        return 
$this->filterEqual('is_pub'1);

    }

    public function 
isFiltersTableExists($ctype_name) {

        
$table_name $this->getContentTypeTableName($ctype_name).'_filters';

        return 
$this->db->isTableExists($table_name);

    }
//============================================================================//

    
public function filterPropValue($ctype_name$prop$value){

        
$table_name  $this->table_prefix.$ctype_name.'_props_values';
        
$table_alias 'p'.$prop['id'];

        if(
$prop['handler']->setName($table_alias.'.value')->applyFilter($this$value) !== false){

            
$this->joinInner($table_name$table_alias"{$table_alias}.item_id = i.id")->setStraightJoin();

            return 
$this->filterEqual($table_alias.'.prop_id'$prop['id']);

        }

        return 
false;

    }

//============================================================================//
//============================================================================//

    
public function addContentItem($ctype$item$fields){

        
$table_name $this->table_prefix $ctype['name'];

        
$item['user_id'] = empty($item['user_id']) ? cmsUser::getInstance()->id $item['user_id'];

        if (!empty(
$item['props'])){
            
$props_values $item['props'];
            unset(
$item['props']);
        }

        if(!isset(
$item['category_id'])){
            
$item['category_id'] = 0;
        }

        if(!empty(
$item['is_approved'])){
            
$item['date_approved'] = null// будет CURRENT_TIMESTAMP
        
}

        if (!empty(
$item['new_category'])){
            
$category $this->addCategory($ctype['name'], array(
                
'title' => $item['new_category'],
                
'parent_id' => $item['category_id']
            ));
            
$item['category_id'] = $category['id'];
        }

        unset(
$item['new_category']);

        if (!empty(
$item['new_folder'])){
            
$folder_exists $this->getContentFolderByTitle($item['new_folder'], $ctype['id'], $item['user_id']);
            if(!
$folder_exists){
                
$item['folder_id'] = $this->addContentFolder($ctype['id'], $item['user_id'], $item['new_folder']);
            } else {
                
$item['folder_id'] = $folder_exists['id'];
            }
        }

        unset(
$item['new_folder']);

        
$add_cats = [];

        if (isset(
$item['add_cats'])){
            foreach(
$item['add_cats'] as $cat_id){
                if(!
$cat_id){
                    continue;
                }
                
$add_cats[] = $cat_id;
            }
            unset(
$item['add_cats']);
        }

        
$item['id'] = $this->insert($table_name$item);

        
$this->updateContentItemCategories($ctype['name'], $item['id'], $item['category_id'], $add_cats);

        if (isset(
$props_values)){
            
$this->addPropsValues($ctype['name'], $item['id'], $props_values);
        }

        if (empty(
$item['slug'])){
            
$item array_merge($item$this->getContentItem($ctype['name'], $item['id']));
            
$item['slug'] = $this->getItemSlug($ctype$item$fields);
        }

        
$this->update($table_name$item['id'], array(
            
'slug' => $item['slug'],
            
'date_last_modified' => null
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype['name']);
        
cmsCache::getInstance()->clean('content.item.'.$ctype['name']);

        
$this->fieldsAfterStore($item$fields'add');

        return 
$item;

    }

//============================================================================//
//============================================================================//

    
public function updateContentItem($ctype$id$item$fields){

        
$table_name $this->table_prefix $ctype['name'];

        if(
array_key_exists('date_pub_end'$item)){
            if(
$item['date_pub_end'] === null){
                
$item['date_pub_end'] = false;
            }
        }

        if (!
$ctype['is_fixed_url']){

            if (
$ctype['is_auto_url']){
                
$item['slug'] = $this->getItemSlug($ctype$item$fields);
            } elseif(!empty(
$item['slug'])) {
                
$item['slug'] = lang_slug($item['slug']);
            }

            if(!empty(
$item['slug'])) {
                
$this->update($table_name$id, array( 'slug' => $item['slug'] ));
            }

        }

        if (!empty(
$item['new_category'])){
            
$category $this->addCategory($ctype['name'], array(
                
'title' => $item['new_category'],
                
'parent_id' => $item['category_id']
            ));
            
$item['category_id'] = $category['id'];
        }

        unset(
$item['new_category']);

        if (!empty(
$item['new_folder'])){
            
$folder_exists $this->getContentFolderByTitle($item['new_folder'], $ctype['id'], $item['user_id']);
            if(!
$folder_exists){
                
$item['folder_id'] = $this->addContentFolder($ctype['id'], $item['user_id'], $item['new_folder']);
            } else {
                
$item['folder_id'] = $folder_exists['id'];
            }
        }

        unset(
$item['new_folder']);
        unset(
$item['folder_title']);

        
// удаляем поле SLUG из перечня полей для апдейта,
        // посколько оно могло быть изменено ранее
        
$update_item $item; unset($update_item['slug']);

        if (!empty(
$update_item['props'])){
            
$this->updatePropsValues($ctype['name'], $id$update_item['props']);
        }

        unset(
$update_item['props']);
        unset(
$update_item['user']);
        unset(
$update_item['user_nickname']);

        
$add_cats = [];

        if (isset(
$update_item['add_cats'])){
            foreach(
$update_item['add_cats'] as $cat_id){
                if(!
$cat_id){
                    continue;
                }
                
$add_cats[] = $cat_id;
            }
            unset(
$update_item['add_cats']);
        }

        
$update_item['date_last_modified'] = null;

        
$this->update($table_name$id$update_item);

        
$this->updateContentItemCategories($ctype['name'], $id$item['category_id'], $add_cats);

        
cmsCache::getInstance()->clean('content.list.'.$ctype['name']);
        
cmsCache::getInstance()->clean('content.item.'.$ctype['name']);

        
$this->fieldsAfterStore($item$fields'edit');

        return 
$item;

    }

    public function 
updateContentItemTags($ctype_name$id$tags){

        
$table_name $this->table_prefix $ctype_name;

        
$this->update($table_name$id, array(
            
'tags' => $tags
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

    }

    public function 
replaceCachedTags($ctype_name$ids$new_tag$old_tag) {

        
$table_name $this->table_prefix $ctype_name;

        
$old_tag $this->db->escape($old_tag);
        
$new_tag $this->db->escape($new_tag);

        if(!
is_array($ids)){
            
$ids = array($ids);
        }

        foreach(
$ids as $k=>$v){
            
$v $this->db->escape($v);
            
$ids[$k] = "'{$v}'";
        }
        
$ids implode(','$ids);

        
$this->db->query("UPDATE `{#}{$table_name}` SET `tags` = REPLACE(`tags`, '{$old_tag}', '$new_tag') WHERE id IN ({$ids})");

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

    }

//============================================================================//
//============================================================================//

    
public function getItemSlug($ctype$item$fields$check_slug true){

        
$content_table_struct $this->getContentTableStruct();
        
$slug_len $content_table_struct['title']['size'];

        
$pattern trim($ctype['url_pattern'], '/');

        
preg_match_all('/{([a-z0-9_]+)}/i'$pattern$matches);

        if (!
$matches) { return lang_slug($item['id'], false); }

        list(
$tags$names) = $matches;

        if (
in_array('category'$names)){
            
$category $this->getCategory($ctype['name'], $item['category_id']);
            
$pattern str_replace('{category}'$category['slug'], $pattern);
            unset(
$namesarray_search('category'$names) ]);
        }

        
$pattern trim($pattern'/');

        foreach(
$names as $idx=>$field_name){
            if (!empty(
$item[$field_name])){

                
$value str_replace('/'''$item[$field_name]);

                if (isset(
$fields[$field_name])){

                    
$value $fields[$field_name]['handler']->getStringValue($value);

                    
$value lang_slug(trim($value'/'), false);

                }

                
$pattern str_replace($tags[$idx], $value$pattern);

            }
        }

        
$slug $pattern;

        
$slug mb_substr($slug0$slug_len);

        if(!
$check_slug){
            return 
$slug;
        }

        
$slug $this->checkCorrectEqualSlug($this->getContentTypeTableName($ctype['name']), $slug$item['id'], $slug_len);

        return 
$slug;
    }

//============================================================================//
//============================================================================//

    
public function getContentItemCategories($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name '_cats_bind';

        return 
$this->filterEqual('item_id'$id)->get($table_name, function($item$model){
            return 
$item['category_id'];
        }, 
false);

    }

    public function 
getContentItemCategoriesList($ctype_name$id){

        
$bind_table_name $this->table_prefix $ctype_name '_cats_bind';
        
$cats_table_name $this->table_prefix $ctype_name '_cats';

        
$this->join($bind_table_name'b''b.category_id = i.id');

        
$this->filterEqual('b.item_id'$id);

        
$this->orderBy('ns_left');

        
$this->useCache('content.categories');

        return 
$this->get($cats_table_name);

    }

    public function 
moveContentItemsToCategory($ctype$category_id$items_ids$fields){

        
$table_name $this->table_prefix $ctype['name'];
        
$binds_table_name $this->table_prefix $ctype['name'] . '_cats_bind';

        
$items $this->filterIn('id'$items_ids)->get($table_name);

        foreach(
$items as $item){

            
$this->
                
filterEqual('item_id'$item['id'])->
                
filterEqual('category_id'$item['category_id'])->
                
deleteFiltered($binds_table_name);

            
$is_bind_exists $this->
                                
filterEqual('item_id'$item['id'])->
                                
filterEqual('category_id'$category_id)->
                                
getCount($binds_table_name'item_id');

            
$this->resetFilters();

            if (!
$is_bind_exists){

                
$this->insert($binds_table_name, array(
                    
'item_id' => $item['id'],
                    
'category_id' => $category_id
                
));

            }

            
$item['category_id'] = $category_id;

            if (!
$ctype['is_fixed_url'] && $ctype['is_auto_url']){
                
$item['slug'] = $this->getItemSlug($ctype$item$fields);
                
$this->update($table_name$item['id'], array( 'slug' => $item['slug'] ));
            }

        }

        
$this->filterIn('id'$items_ids)->updateFiltered($table_name, array(
            
'category_id' => $category_id
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype['name']);
        
cmsCache::getInstance()->clean('content.item.'.$ctype['name']);

        return 
true;

    }

    public function 
updateContentItemCategories($ctype_name$id$category_id$add_cats){

        
$table_name $this->table_prefix $ctype_name '_cats_bind';

        
$new_cats = empty($add_cats) ? array() : $add_cats;

        if (!
$category_id) { $category_id 1; }

        if (!
in_array($category_id$new_cats)){
            
$new_cats[] = $category_id;
        }

        
$current_cats $this->
                            
filterEqual('item_id'$id)->
                            
get($table_name, function($item$model){
                                return 
$item['category_id'];
                            }, 
false);

        if (
$current_cats){
            foreach(
$current_cats as $current_cat_id){

                if (!
in_array($current_cat_id$new_cats)){
                    
$this->
                        
filterEqual('item_id'$id)->
                        
filterEqual('category_id'$current_cat_id)->
                        
deleteFiltered($table_name);
                }

            }
        }

        foreach(
$new_cats as $new_cat_id){
            if (!
$current_cats || !in_array($new_cat_id$current_cats)){
                
$this->insert($table_name, array(
                    
'item_id' => $id,
                    
'category_id' => $new_cat_id
                
));
            }
        }

    }

//============================================================================//
//============================================================================//

    
public function restoreContentItem($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name;

        if(
is_numeric($id)){
            
$item $this->getContentItem($ctype_name$id);
            if(!
$item){ return false; }
        } else {
            
$item $id;
        }

        
cmsCore::getController('activity')->addEntry('content'"add.{$ctype_name}", array(
            
'user_id'          => $item['user_id'],
            
'subject_title'    => $item['title'],
            
'subject_id'       => $item['id'],
            
'subject_url'      => href_to_rel($ctype_name$item['slug'] . '.html'),
            
'is_private'       => isset($item['is_private']) ? $item['is_private'] : 0,
            
'group_id'         => isset($item['parent_id']) ? $item['parent_id'] : null,
            
'is_parent_hidden' => $item['is_parent_hidden'],
            
'date_pub'         => $item['date_pub'],
            
'is_pub'           => $item['is_pub']
        ));

        
cmsCore::getModel('comments')->setCommentsIsDeleted('content'$ctype_name$item['id'], null);

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        
$this->update($table_name$item['id'], array('is_deleted' => null));

        
cmsEventsManager::hook('content_after_restore', array($ctype_name$item));
        
cmsEventsManager::hook("content_{$ctype_name}_after_restore"$item);

        return 
true;

    }

    public function 
toTrashContentItem($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name;

        if(
is_numeric($id)){
            
$item $this->getContentItem($ctype_name$id);
            if(!
$item){ return false; }
        } else {
            
$item $id;
        }

        
cmsCore::getController('activity')->deleteEntry('content'"add.{$ctype_name}"$item['id']);

        
cmsCore::getModel('comments')->setCommentsIsDeleted('content'$ctype_name$item['id']);

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        
$this->update($table_name$item['id'], array('is_deleted' => 1));

        
cmsEventsManager::hook('content_after_trash_put', array($ctype_name$item));
        
cmsEventsManager::hook("content_{$ctype_name}_after_trash_put"$item);

        return 
true;

    }

    public function 
deleteContentItem($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name;

        
$item $this->getContentItem($ctype_name$id);
        if(!
$item){ return false; }

        
$ctype $this->getContentTypeByName($ctype_name);

        
cmsEventsManager::hook('content_before_delete', array('ctype_name'=>$ctype_name'item'=>$item));
        
cmsEventsManager::hook("content_{$ctype_name}_before_delete"$item);

        
$fields $this->getContentFields($ctype_name$id);

        foreach(
$fields as $field){
            
$field['handler']->delete($item[$field['name']]);
        }

        
cmsCore::getController('activity')->deleteEntry('content'"add.{$ctype_name}"$id);

        
cmsCore::getModel('comments')->deleteComments('content'$ctype_name$id);
        
cmsCore::getModel('rating')->deleteVotes('content'$ctype_name$id);
        
cmsCore::getModel('tags')->deleteTags('content'$ctype_name$id);

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        
$this->deletePropsValues($ctype_name$id);

        
$this->deleteContentItemRelations($ctype['id'], $id);

        
$this->filterEqual('item_id'$item['id'])->deleteFiltered($table_name.'_cats_bind');

        
$success $this->delete($table_name$id);

        if(
$success){
            
cmsEventsManager::hook('content_after_delete', array('ctype_name'=>$ctype_name'item'=>$item));
            
cmsEventsManager::hook("content_{$ctype_name}_after_delete"$item);
        }

        return 
$success;

    }

    public function 
deleteUserContent($user_id){

        
$ctypes $this->getContentTypes();

        foreach(
$ctypes as $ctype){

            
$this->disableDeleteFilter()->disableApprovedFilter()->
                    
disablePubFilter()->disablePrivacyFilter();

            
$items $this->filterEqual('user_id'$user_id)->getContentItems($ctype['name']);

            if (
is_array($items)){
                foreach(
$items as $item){
                    
$this->deleteContentItem($ctype['name'], $item['id']);
                }
            }

        }

        
$this->filterEqual('user_id'$user_id)->deleteFiltered('content_folders');
        
$this->filterEqual('user_id'$user_id)->deleteFiltered('moderators');

    }

//============================================================================//
//============================================================================//

    
public function applyPrivacyFilter($ctype$allow_view_all false) {

        
$hide_except_title = (!empty($ctype['options']['privacy_type']) && $ctype['options']['privacy_type'] == 'show_title');

        
// Сначала проверяем настройки типа контента
        
if (!empty($ctype['options']['privacy_type']) && in_array($ctype['options']['privacy_type'], array('show_title''show_all'), true)) {
            
$this->disablePrivacyFilter();
            if(
$ctype['options']['privacy_type'] != 'show_title'){
                
$hide_except_title false;
            }
        }

        
// А потом, если разрешено правами доступа, отключаем фильтр приватности
        
if ($allow_view_all) {
            
$this->disablePrivacyFilter(); $hide_except_title false;
        }

        return 
$hide_except_title;

    }

    public function 
getContentItemsCount($ctype_name){

        
$table_name $this->table_prefix $ctype_name;

        if (!
$this->privacy_filter_disabled) { $this->filterPrivacy(); }
        if (!
$this->approved_filter_disabled) { $this->filterApprovedOnly(); }
        if (!
$this->delete_filter_disabled) { $this->filterAvailableOnly(); }
        if (!
$this->pub_filter_disabled) { $this->filterPublishedOnly(); }
        if (!
$this->hidden_parents_filter_disabled) { $this->filterHiddenParents(); }

        
$this->useCache("content.list.{$ctype_name}");

        return 
$this->getCount($table_name);

    }

    public function 
getContentItemsForSitemap($ctype_name$fields = array()){

        
$table_name $this->table_prefix $ctype_name;

        
$this->selectOnly('slug');
        
$this->select('date_last_modified');
        
$this->select('title');
        if(
$fields){
            foreach (
$fields as $field) {
                
$this->select($field);
            }
        }

        if (!
$this->privacy_filter_disabled) { $this->filterPrivacy(); }
        if (!
$this->approved_filter_disabled) { $this->filterApprovedOnly(); }
        if (!
$this->delete_filter_disabled) { $this->filterAvailableOnly(); }
        if (!
$this->pub_filter_disabled) { $this->filterPublishedOnly(); }
        if (!
$this->hidden_parents_filter_disabled) { $this->filterHiddenParents(); }

        if (!
$this->order_by){ $this->orderBy('date_pub''desc')->forceIndex('date_pub'); }

        return 
$this->get($table_namefalsefalse);

    }

    public function 
getContentItems($ctype_name$callback null){

        
$table_name $this->table_prefix $ctype_name;

        
$this->select('u.nickname''user_nickname');
        
$this->select('u.slug''user_slug');
        
$this->select('u.avatar''user_avatar');
        
$this->select('u.groups''user_groups');
        
$this->select('f.title''folder_title');
        
$this->join('{users}''u''u.id = i.user_id');
        
$this->joinLeft('content_folders''f''f.id = i.folder_id');

        if (!
$this->privacy_filter_disabled) { $this->filterPrivacy(); }
        if (!
$this->approved_filter_disabled) { $this->filterApprovedOnly(); }
        if (!
$this->delete_filter_disabled) { $this->filterAvailableOnly(); }
        if (!
$this->pub_filter_disabled) { $this->filterPublishedOnly(); }

        if (!
$this->order_by){ $this->orderBy('date_pub''desc')->forceIndex('date_pub'); }

        
$this->useCache('content.list.'.$ctype_name);

        
$user cmsUser::getInstance();

        return 
$this->get($table_name, function($item$model) use ($user$callback$ctype_name){

            
$item['user'] = array(
                
'id'        => $item['user_id'],
                
'slug'      => $item['user_slug'],
                
'nickname'  => $item['user_nickname'],
                
'avatar'    => $item['user_avatar'],
                
'groups'    => $item['user_groups'],
                
'is_friend' => $user->isFriend($item['user_id'])
            );

            if (
is_callable($callback)){
                
$item $callback($item$model$ctype_name$user);
            }

            return 
$item;

        });

    }

//============================================================================//
//============================================================================//

    
public function getContentItem($ctype_name$id$by_field 'id'){

        if(
is_numeric($ctype_name)){

            
$ctype $this->getContentType($ctype_name);

            if(!
$ctype){ return false; }

            
$ctype_name $ctype['name'];

        }

        
$table_name $this->table_prefix $ctype_name;

        
$this->select('f.title''folder_title');

        
$this->joinUser();
        
$this->joinLeft('content_folders''f''f.id = i.folder_id');

        
$this->useCache("content.item.{$ctype_name}");

        return 
$this->getItemByField($table_name$by_field$id, function($item$model) use($ctype_name){

            
$item['user'] = array(
                
'id'       => $item['user_id'],
                
'groups'   => $item['user_groups'],
                
'slug'     => $item['user_slug'],
                
'nickname' => $item['user_nickname'],
                
'avatar'   => $item['user_avatar']
            );

            
$item['is_draft'] = false;

            if (!
$item['is_approved']){
                
$item['is_draft'] = $model->isDraftContentItem($ctype_name$item);
            }

            return 
$item;

        }, 
$by_field);

    }

    public function 
getContentItemBySLUG($ctype_name$slug){

        return 
$this->getContentItem($ctype_name$slug'slug');

    }

//============================================================================//
//============================================================================//

    
public function getUserContentItemsCount($ctype_name$user_id$is_only_approved true){

        
$this->filterEqual('user_id'$user_id);

        if (!
$is_only_approved) { $this->approved_filter_disabled true; }

        
$count $this->getContentItemsCount$ctype_name );

        
$this->resetFilters();

        return 
$count;

    }

    public function 
getUserContentItemsCount24($ctype_name$user_id){

        
$this->filter("DATE(DATE_FORMAT(i.date_pub, '%Y-%m-%d')) = CURDATE()");

        return 
$this->getUserContentItemsCount($ctype_name$user_idfalse);

    }

    public function 
getUserContentCounts($user_id$is_filter_hidden=false$access_callback false){

        
$counts = array();

        
$ctypes $this->getContentTypes();

        
$this->filterEqual('user_id'$user_id);

        if (
$is_filter_hidden){
            
$this->enableHiddenParentsFilter();
        }

        if (!
$is_filter_hidden){
            
$this->disableApprovedFilter();
            
$this->disablePubFilter();
            
$this->disablePrivacyFilter();
        }

        foreach(
$ctypes as $ctype){

            if(
is_callable($access_callback) && !$access_callback($ctype)){
                continue;
            }

            if(!
$ctype['options']['profile_on']){
                continue;
            }

            
$count $this->getContentItemsCount$ctype['name'] );

            if (
$count) {

                
$counts$ctype['name'] ] = array(
                    
'count' => $count,
                    
'is_in_list' => $ctype['options']['profile_on'],
                    
'title' => empty($ctype['labels']['profile']) ? $ctype['title'] : $ctype['labels']['profile']
                );

            }

        }

        
$this->resetFilters();

        return 
$counts;

    }

//============================================================================//
//============================================================================//

    
public function publishDelayedContentItems($ctype_name){

        return 
$this->filterIsNull('is_deleted')->
                    
filterNotEqual('is_pub'1)->
                    
filter('i.date_pub <= NOW()')->
                    
updateFiltered($this->table_prefix.$ctype_name, array(
                        
'is_pub' => 1
                    
));

    }

    public function 
hideExpiredContentItems($ctype_name){

        return 
$this->filterIsNull('is_deleted')->
                    
filterEqual('is_pub'1)->
                    
filterNotNull('date_pub_end')->
                    
filter('i.date_pub_end <= NOW()')->
                    
updateFiltered($this->table_prefix.$ctype_name, array(
                        
'is_pub' => 0
                    
));

    }

    public function 
deleteExpiredContentItems($ctype_name){

        return 
$this->
                    
filterNotNull('date_pub_end')->
                    
filter('i.date_pub_end <= NOW()')->
                    
get($this->table_prefix.$ctype_name, function($item$model) use($ctype_name){
                        
$model->deleteContentItem($ctype_name$item['id']);
                        return 
$item['id'];
                    });

    }

    public function 
toTrashExpiredContentItems($ctype_name){

        return 
$this->
                    
filterNotNull('date_pub_end')->
                    
filter('i.date_pub_end <= NOW()')->
                    
get($this->table_prefix.$ctype_name, function($item$model) use($ctype_name){
                        
$model->toTrashContentItem($ctype_name$item);
                        return 
$item['id'];
                    });

    }

    public function 
toggleContentItemPublication($ctype_name$id$is_pub){

        
$this->update($this->table_prefix.$ctype_name$id, array(
            
'is_pub' => $is_pub
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
true;

    }

    public function 
incrementHitsCounter($ctype_name$id){

        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
$this->filterEqual('id'$id)->increment($this->table_prefix.$ctype_name'hits_count');

    }

//============================================================================//
//============================================================================//

    
public function deleteCategory($ctype_name$id$is_delete_content=false){

        
$category $this->getCategory($ctype_name$id);

        
$this->filterCategory($ctype_name$categorytrue);

        if (!
$is_delete_content){
            
$table_name $this->table_prefix $ctype_name;
            
$this->updateFiltered($table_name, array(
                
'category_id' => 1
            
));
        }

        if (
$is_delete_content){

            
$this->disableDeleteFilter()->disableApprovedFilter()->
                    
disablePubFilter()->disablePrivacyFilter();

            
$items $this->getContentItems($ctype_name);

            if (
$items){
                foreach(
$items as $item){
                    
$this->deleteContentItem($ctype_name$item['id']);
                }
            }

        }

        
$this->unbindContentProps($ctype_name$id);

        
parent::deleteCategory($ctype_name$id);

    }

//============================================================================//
//============================================================================//

    
public function getRatingTarget($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name;

        
$item $this->getItemById($table_name$id);

        if(
$item){
            
$item['page_url'] = href_to($ctype_name$item['slug'].'.html');
        }

        return 
$item;

    }

    public function 
updateRating($ctype_name$id$rating){

        
$table_name $this->table_prefix $ctype_name;

        
$this->update($table_name$id, array('rating' => $rating));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

    }

//============================================================================//
//============================================================================//

    
public function updateCommentsCount($ctype_name$id$comments_count){

        
$table_name $this->table_prefix $ctype_name;

        
$this->update($table_name$id, array('comments' => $comments_count));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
true;

    }

    public function 
getCommentsOptions($ctype_name) {

        
$ctype $this->getContentTypeByName($ctype_name);

        return [
            
'enable' => $ctype['is_comments'],
            
'title_pattern' => (!empty($ctype['options']['comments_title_pattern']) ? $ctype['options']['comments_title_pattern'] : ''),
            
'labels' => (!empty($ctype['options']['comments_labels']) ? $ctype['options']['comments_labels'] : []),
            
'template' => (!empty($ctype['options']['comments_template']) ? $ctype['options']['comments_template'] : '')
        ];

    }

    public function 
getTargetItemInfo($ctype_name$id){

        
$item $this->getContentItem($ctype_name$id);

        if (!
$item){ return false; }

        return array(
            
'url' => href_to_rel($ctype_name$item['slug'].'.html'),
            
'title' => $item['title'],
            
'is_private' => $item['is_private'] || $item['is_parent_hidden']
        );

    }

//============================================================================//
//============================================================================//

    
public function toggleParentVisibility($parent_type$parent_id$is_hidden){

        
$ctypes_names $this->getContentTypesNames();

        
$is_hidden $is_hidden null;

        foreach(
$ctypes_names as $ctype_name){

            
$table_name $this->table_prefix $ctype_name;

            
$this->
                
filterEqual('parent_type'$parent_type)->
                
filterEqual('parent_id'$parent_id)->
                
updateFiltered($table_name, array('is_parent_hidden' => $is_hidden));

            
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
            
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        }

    }

    public function 
isDraftContentItem($ctype_name$item) {

        if(!empty(
$item['is_approved'])){ return false; }

        return !(bool)
$this->selectOnly('id')->filterEqual('ctype_name'$ctype_name)->
                    
filterEqual('item_id'$item['id'])->getItem('moderators_tasks');

    }

    public function 
getDraftCounts($user_id){

        
$counts = array();

        
$ctypes $this->getContentTypes();

        foreach(
$ctypes as $ctype){

            
$this->useCache("content.list.{$ctype['name']}");

            
$this->filterEqual('user_id'$user_id);
            
$this->filterEqual('is_approved'0);
            
$this->disableApprovedFilter();
            
$this->disablePubFilter();
            
$this->disablePrivacyFilter();

            
$this->joinExcludingLeft('moderators_tasks''t''t.item_id''i.id'"t.ctype_name = '{$ctype['name']}'");

            
$count $this->getContentItemsCount($ctype['name']);

            
$this->resetFilters();

            if (
$count) {
                
$counts$ctype['name'] ] = $count;
            }

        }

        return 
$counts;

    }

    public function 
approveContentItem($ctype_name$id$moderator_user_id){

        
$table_name $this->table_prefix $ctype_name;

        
$this->update($table_name$id, array(
            
'is_approved'   => 1,
            
'approved_by'   => $moderator_user_id,
            
'date_approved' => ''
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
true;

    }

    public function 
unbindParent($ctype_name$id){

        
$table_name $this->table_prefix $ctype_name;

        
$this->update($table_name$id, array(
            
'parent_id'        => null,
            
'parent_type'      => null,
            
'parent_title'     => null,
            
'parent_url'       => null,
            
'is_parent_hidden' => null
        
));

        
cmsCache::getInstance()->clean('content.list.'.$ctype_name);
        
cmsCache::getInstance()->clean('content.item.'.$ctype_name);

        return 
true;

    }

    
/**
     * @deprecated
     *
     * Метод для совместимости
     * @param string $ctype_name
     * @param integer $user_id
     * @return boolean
     */
    
public function userIsContentTypeModerator($ctype_name$user_id){
        return 
cmsCore::getModel('moderation')->userIsContentModerator($ctype_name$user_id);
    }

}
Онлайн: 3
Реклама