• Блог
  • Фильтрация, контейнер, планшет...

Новость для разработчиков. В библиотеку добавлено несколько новых функций:

  • is_tablet()
  • is_desktop()
  • app()
  • filter_data()
  • null_if()
  • И ещё немного доработана функция pls() для работы с плейсхолдерами, logout() и parse().

    С первыми двумя функциями, думаю, всё понятно. Это функции-детекторы текущего устройства. Раньше можно было только проверить является ли устройство мобильным или нет, используя функцию is_mobile(). Теперь проверка полноценнее. Особенно это хорошо впишется при использовании шаблонизатора.

    {if $.php.is_tablet()}
        // Планшет
    {elseif $.php.is_mobile()}
        // Телефон
    {else}
        // Десктоп
    {/if}
    

    Функция is_mobile() определяет и телефоны и планшеты как мобильные. Поэтому сначала нужно проверять планшеты.

    Детектор устройства использует библиотеку MobileDetect. Поэтому можно использовать все её возможности. А у неё очень много полезных методов. Эта библиотека подключается как сервис через функцию app() (о ней ниже). Поэтому обратиться к ней можно в любом месте так

    $detector = app('detector');
    
    // И дальше уже вызывать методы
    $detect->version('Firefox');
    if ($detect->isiOS()) {}
    if ($detect->is('Chrome')) {}
    

    Теперь о функции app(). Она возвращает объект контейнера, который используется для разрешения зависимостей. В контейнере можно хранить объект, который будет один и тот же на протяжении загрузки приложения. Это так называемый синглтон (singleton). Например, в начале загрузки определяется репозиторий (репозиторий пользователей, ресурсов и т.п.), а затем в любом месте приложения к нему можно обращаться. Синглтоны часто используются как сервисы.

    Основные методы:

  • bind() — регистрация зависимости.
  • singleton() — регистрация синглтона через имя класса или замыкание.
  • instance() — регистрация уже существующего объекта в качестве синглтона.
  • bound() — проверяет, определена ли указанная зависимость.
  • resolved() — проверяет, создан ли объект указанной зависимости.
  • Работает это так:

    // В плагине при инициализации MODX определяем зависимость
    app()->singleton('userRepo', function() use ($modx) {
    	return users()->where(['active'=>true])->toArray();
    });
    

    И теперь в любом месте приложения можно вызвать:

    $users = app('userRepo');

    И получаем всегда один и тот же репозиторий. И никаких повторных запросов к базе.

    Проверяем, определена ли уже зависимость:

    if (!app()->bound('alias')) {
        app()->bind('alias', function(){...});
    }
    

    Удобно когда нужно проводить какие-нибудь однотипные манипуляции

    // Инициализируем зависимость
    app()->bind('user', function($app, $params = array()) {
        if (isset($params['id'])) $user = user($params['id']);
        // Делаем нужные манипуляции и инициализации
        ...
        // Возвращаем объект
        return $user;
    });
    ...
    // В любом месте приложения вызываем
    $user = app('user', array('id' => 5));  // получаем подготовленный объект пользователя
    

    Про filter_data() я уже писал. Добавлю только, что можно вызывать несколько фильтров для поля (через |), а также указывать параметры у фильтров (после :).

    На сегодняшний момент фильтры следующие:

  • int, integer — Приводит к integer.
  • string — Удаляет теги и пробелы из начала и конца строки.
  • float — Приводит к float типу.
  • array — Конвертирует значение в массив.
  • bool, boolean — Возвращает TRUE для «1», «true», «on» и «yes». И FALSE в остальных случаях.
  • alpha — Возвращает только буквенные символы из указанного значения.
  • alpha_num — Возвращает только буквы и цифры.
  • num — Возвращает только цифры.
  • email — Удаляет все символы кроме букв, цифр и !#$%&'*+-=?^_`{|}~@.[].
  • url — Удаляет все символы кроме букв, цифр и $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=.
  • limit — Обрезает строку до указанного значения и добавляет в конец указанную строку. После двоеточия через запятую можно определить 2 параметра — длина строки и окончание ('limit:20,...'). Многоточие указывается по-умолчанию.
  • fromJSON — Декодирует строку из JSON формата.
  • toJSON — Возвращает значение в JSON формате.
  • default — Возвращает значение по-умолчанию, если указанное значение не существует ('default: Значение по-умолчанию').
  • Кроме того можно использовать не только замыкания (анонимные функции), но и функции php (к ним же относятся и функции самой библиотеки modHelpers). Например, из важных htmlspecialchars().

    // $_POST['list' => 'cat1, cat2, cat5']
    $post = filter_data($_POST, ['list' => 'explode|trim'; // Вызываем 2 фильтра - функции php
    // $post['list'] = array('cat1', 'cat2', 'cat5')
    

    Загружает объект пользователя

    // $_POST = ['user' => '5']
    $rules = [
    	'user' => 'user', // функция modHelpers
    ];
    $post = filter_data($_POST, $rules);
    // $post['user']  - объект класса modUser с id 5.
    

    Можно использовать конейнер для хранения правил фильтрации.

    // При загрузке MODX определяем зависимость
    app()->bind('user_rules', function() {
        return array(
            'username' => 'string',
            'fullname' => 'string',
            'email' => 'email',
            'user' => 'user',
        );
    });
    
    // Затем при фильтрации данных формы вызывать.
    $rules = app('user_rules');
    $post = filter_data($_POST, $rules);
    if (is_object($user = $post['user'])) {
        $user->fromArray($post); 
        $user->Profile->fromArray($post); 
        $user->save();
    }
    

    Ну и осталась функция null_if(). Она возвращает NULL, если переданное значение равно второму параметру. По-умолчанию, второй параметр равен пустой строке. Эта функция — задел на будущий функционал валидации данных.

    Ещё пару слов про функцию logout(). У неё появился третий параметр, определяющий нужно ли перелогиниться. Если указать TRUE, то если пользователь залогинен в админке, он будет аутентифицирован как этот пользователь. Если указать FALSE, то он так и останется гостем. Это может пригодится при тестировании — когда нужен гость, в вы залогинены в админке, и MODX автоматом аутентифицирует пользователя сайта как админа. Вот чтобы не выходить из админки можно разлогиниться с параметром FALSE.

    Что касается функции parse(). Теперь у неё 2 режима: быстрый парсинг и полный. Быстрый — для простой замены тегов.

    $tpl = '<li>[[+id]]. [[+username]]</li>';
    $output = '';
    foreach($users as $user) {
        $output .= parse($tpl, $user);
    }
    $output = '<ul>' . $output . '</ul>';
    

    А полный парсинг работает как getChunk() для инлайн чанка. Т.е. можно указать полноценную строку с тегами чанков, сниппетов.

    $tpl = 'Строка с вызовом чанка [[$chunk]].';
    $output = parse($tpl, $data, true, 5);
    

    Для полного парсинга нужно передать в третьем параметре TRUE. В четвертом можно указать количество итераций парсера. По-умолчанию, 10.

    На этом всё.

    22 августа 2017, 20:58   809     10

    Комментарии ()

    1. Семён 21 октября 2017, 20:42 # 0
      Добрый вечер, Сергей.
      Изучаю документацию modHelpers и столкнулся с таким моментом:
      yadi.sk/i/s6jTzs573NxNUc

      Согласно доков метод parent возвращает объект, с которым ожидается возможным использовать другие методы объекта, но вот поменять ему pagetitle не получается. Может я как то не правильно код написал?
      1. Сергей Шлоков 23 октября 2017, 07:38 # 0
        Ну так там же написано в чем ошибка. Метод set первым параметром принимает название поля, а вторым — значение.

        Метод parent() возвращает объект xPDOObject и это его метод set().
      2. Семён 06 декабря 2017, 16:28 # 0
        Возникла такая мысль, а можно ли как-то получить в чанке все доступные плейсхолдеры, но именно выставленные сниппетом, который использует этот чанк для оформления?
        Сейчас если заглянуть в массив плейсхолдеров там огромная куча всего, а хотелось бы видеть только то, что даёт сниппет.
        Было бы не плохо такую функцию всегда под рукой держать, а так приходится либо в документацию лезть искать либо в код сниппета заглядывать и там выискивать выставление плейсхолдеров.
        1. Сергей Шлоков 06 декабря 2017, 20:08 # 0
          Выделить данные, переданные в чанк, не реально. По крайней мере, я не знаю такого способа. Не представляю зачем это нужно.
          1. Семён 06 декабря 2017, 20:15 # 0
            Это нужно для понимания какими плейсхолдерами можно распоряжаться в чанке оформления, ведь далеко не все авторы дополнений пишут документацию о своих сниппетах, что они передают в чанк, поэтому было бы удобно вызываешь любой сниппет, а в чанке оформления запускаешь какую-нибудь конструкцию, которая тебе распечатает все плейсхолдеры сниппета и вперёд! — вставлять их в вёрстку!
            Примерно по такому принципу у Василия сделана обработка параметра &tpl в сниппетах pdoTools — если указан пустой параметр, то распечатывается весь массив плейсхолдеров, вот тоже самое хотелось бы иметь в чанках, что бы это было универсальное решение независимое от сниппета.
        2. Vladimir 16 января 2018, 14:13 # 0
          Вот интересно, и modHelpers и MobileDetect используют библиотеку MobileDetect. И, вроде, на реальных устройствах работают одинаково.
          Но вот есть такой браузер, Blisk — эмулятор устройств (как мобильных так и широкоформатных), пользуюсь им примерно год. Так вот он иногда наотрез (или через раз) отказывается определять
          ​{if 'standard' | mobiledetect}
                               текст для десктопов и т.п.
                               {/if}
                               {if 'mobile' | mobiledetect}
                               тут текст со ссылкой для мобильных
                               {/if}
          
          тогда как
           {if $.php.is_tablet() or $.php.is_mobile()}
          ссылка для мобильых и планшетов
                               {else}
                         текст для десктопа     
                              {/if}
          
          — нет проблем и в эмуляторе и на реальных мобильных.
          1. Сергей Шлоков 16 января 2018, 16:45 # 0
            Ну у тебя некорректное сравнение. В первом случае ты проверяешь стандарт, а во втором — мобайл. Сделай первое условие как у modHelpers. Думаю всё сработает.

            Кстати, автор пишет, что планшеты являются подмножеством мобильных. Т.е. is_mobile() будет истинно и для тех и для других. Если есть возможность, проверь этот момент.
            1. Vladimir 16 января 2018, 16:52 # 0
              Во втором примере я объединяю планшеты и мобильники, просто не было смысла разделать. Но пытался по разному. Blisk вроде корректно передает юзерагент, но с modHelpers нет проблем (я только о работе в Blisk), а с пакетом MobileDetect эмулятор все время ошибается (уточню, все в случае использования fenom).
              1. Сергей Шлоков 16 января 2018, 16:58 # 0
                Рад за modHelpers. :)

                Вот примеры из документации
                // Any mobile device (phones or tablets).
                if ( $detect->isMobile() ) {
                 
                }
                // Any tablet device.
                if( $detect->isTablet() ){
                 
                }
                 // Exclude tablets.
                if( $detect->isMobile() && !$detect->isTablet() ){
                 
                }
                
                Для твоего случая достаточно только is_mobile().
                1. Vladimir 16 января 2018, 17:07 # +1
                  Попытаюсь наплодить примеров, покажу, хочется понять почему в одном случае работает, а в другом нет.
                  Было еще с MobileDetect (пакетом), что он на немецких серверах (на модхосте) и на СПБ вел себя по-разному. Т.е. буквально, меняю сервер на немецкий- работает, возвращаю на СПБ — нет.
                  (это я опять про тот же браузер-эмулятор Blisk, на «железных» девайсах все нормально во всех случаях, но в Blisk уж очень удобно тестить варианты отображения.)

                  Да, за modHelpers огромное спасибо!

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

          Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.