• Как сделать range validator для yii2?

    mulat
    @mulat
    seo, php, yii2
    Пример "in range" валидатора для дат:

    public function rules()
        {
            return [
                [['date'], 'required'],
                [['date'], 'safe'],
                [['date'],
                    'filter',
                    'filter' => function($value){
                        return \Yii::$app->formatter->asDate($value, 'yyyy-MM-dd');
                    }
                ],
                [
                    ['date'],
                    'date',
                    'format' => 'yyyy-MM-dd'
                ],
                [
                    ['date'],
                    'in',
                    'range' => function ($model, $attribute) {
    
                        $start = \Yii::$app->formatter->asTimestamp(!empty($model->oldAttributes[$attribute]) ?
                                    $model->oldAttributes[$attribute] :
                                    $this->$attribute);
                        $start += 24 * 60 * 60;
    
                        $stop = \Yii::$app->formatter->asTimestamp($model->relatedModel->end_date);
    
                        $dates = [];
                        while ($start <= $stop) {
                            $dates[] = \Yii::$app->formatter->asDate($start, 'MM/dd/yyyy');
                            $start += (24 * 60 * 60);
                        }
                        return $dates;
                    },
                    'on' => [
                        self::SCENARIO_DEFAULT,
                    ],
                    'skipOnEmpty' => false,
                    'skipOnError' => false
                ],
          ];
    }


    P.S.
    Валидатор готовит массив дат в американском формате, т.к. именно он нужен для выбора даты из \yii\jui\DatePicker

    <?php
                $form = ActiveForm::begin();
                $model->date = \Yii::$app->formatter->asDate($model->date, 'MM/dd/yyyy');
    ?>
    
    <?= $form->field($model, 'date')
                    ->label('Date')
                    ->widget(DatePicker::className(), [
                        'dateFormat' => 'MM/dd/yyyy',
            ])
            ->textInput([
                  'class'    => 'form-control',
            ]);
    ?>
    Ответ написан
    Комментировать
  • Где можно по шагам разобрать пример разработки сайта на yii 2.0?

    mulat
    @mulat
    seo, php, yii2
    Лично мне не подходит обучение по одному чудо-учебнику.
    Опишу свой путь.

    1. документация на английском + почитывал Mark Safronov, Jeffrey Winesett - Web Application Development with Yii 2 and PHP - 2014. Учебник прочёл с большего и закинул в пользу доки.
    2. параллельно смотрел канал DoingItEasy, плейлист Yii2 Lessons
    3. устанавливал и разбирал модули и дополнения Kartik Visweswaran, Василия Круду, Михалыча, Neverton, himiklab.
    4. сделал своё приложение со всевозможными извратами для переноса старых проектов с самописной cms.
    Очень помогло знание английского, т.к. в буржнете немало поднимается вопросов, и по теме Yii2 в частности.
    Хватило месяца, чтобы почувствовать себя уверенно в теме. На самом деле думал освою на много раньше.
    Ответ написан
    Комментировать
  • Почему sphinx не ищет кириллицу?

    mulat
    @mulat
    seo, php, yii2
    Дополню WhoMe: похожий вопрос.
    Ответ написан
    Комментировать
  • Как заставить морфологию sphinx работать на utf8?

    mulat
    @mulat
    seo, php, yii2
    Sphinx 2.2.9 Release

    В блоке source прописать:

    sql_query_pre = SET NAMES utf8
    sql_query_pre = SET CHARACTER SET utf8


    В блоке index:

    morphology = stem_ru, stem_en
    Ответ написан
    Комментировать
  • Как подключить sphinx в yii2 и работать с ним?

    mulat
    @mulat
    seo, php, yii2
    Пару примеров моего кода для Yii2
    из виджета RelatedPosts:

    /**
      * $inCategory
      * @var boolean  false - get posts from alien categories, true - from this category
      */
    
    $postIds = $query
          ->select('id')
          ->from(Yii::$app->getModule('blog')->getParam('sphinxRtIndex'))
          ->match(new Expression(':match',
              [
                  'match' => implode(' | ', $search)
              ]
          ))
          ->andWhere('id != :id', [':id' => $this->postModel->id])
          ->andWhere('category_id' . ($this->inCategory? '=' : '!=') . ':category_id', 
                 [
                     ':category_id' => $this->postModel->category_id
                 ]
          )
          ->limit($this->limit)
          ->all();


    из поведения RtSphinxBehavior (на github):

    protected function replace() {
        $params = [];
    
        $sql = \Yii::$app->sphinx->getQueryBuilder()
            ->replace(
                $this->rtIndex,
                $this->getColumns(),
                $params
            );
        return \Yii::$app->sphinx->createCommand($sql, $params)->execute();
    }
    /**
      * $this->getColumns()  возвращает массив вида:
      * ['title' => 'John Doe', 'text' => 'I knew John well...']
      *
      * $this->rtIndex - содержит значение имени Realtime индекса
     */
    Ответ написан
    Комментировать
  • Как сделать ЧПУ пагинацию на Yii2?

    mulat
    @mulat
    seo, php, yii2
    Как раз только что с этим разобрался. Приведу пример кода из своего проекта.
    Вариант для yii\widgets\ListView
    Контроллер:
    $dataProvider = new ActiveDataProvider([
                'query' => Post::find()->andWhere(['category_id' => $model->id]),
                'pagination' => [
                    // Размер выводимых элементов на страницу. 
                    // Беру из настроек своего модуля blog
                    'pageSize' => Yii::$app->getModule('blog')->postPerPage,
                    // Размер эл-тов на страницу по умолчанию. Зачем нужен - поясню после кода
                    'defaultPageSize' => Yii::$app->getModule('blog')->postPerPage,
                    // Имя параметра, содержащего номер текущей страницы. 
                    // (если Ваш отличается от дефолтного 'page')
                    'pageParam' => 'pageNum',
                    // Так подавляется ссылка на первую страницу вида /category-name-х/1/
                    // Вместо неё выведется  /category-name-х/
                    'forcePageParam' => false,
                ]
            ]);


    Значение 'defaultPageSize' нужно установить равным значению 'pageSize' для того, чтобы подавить добавление классом Pagination параметра 'per-page' в урлы постранички. Но это нужно для того случая, когда не устраивает значение родного 'pageSize'. По-моему равно 20-ти.


    Так же требуется url первой страницы менять с такого mysite.ru/controllerName?page=1&per-page=2 на такой mysite.ru/controllerName

    Этот момент решается установкой параметра 'forcePageParam' в значение false.

    Для того, чтобы подхватывался route из Вашего urlManager, нужно чтобы описанный в менеджере pattern содержал правильные имена параметров. Т.е. в настройках класса Pagination - значение 'pageParam' по умолчанию задано как 'page'. Значит pattern для урлов должен быть такого плана:
    //...
    // Category with pager
     [
        'pattern' => '<alias:[\w\-]+>/<page:\d+>',
        'route' => 'blog/category/index',
        'suffix' => '/'
      ],
    //...


    В моём случае pattern для урлов такой:
    'pattern' => '<alias:[\w\-]+>/<pageNum:\d+>'

    P.S.
    В итоге мне самому этот вариант не подошёл, т.к. я хотел в постраничке оставить только ссылки на сами страницы без ссылок Следющий и Предыдщий пост. Не нашёл как сделать под ListView. А в LinkPager без проблем.
    Вариант для yii\widgets\LinkPager
    Контроллер:
    $query = Post::find()->andWhere(['category_id' => $model->id]);
            $countQuery = clone $query;
            $pages = new Pagination([
                'totalCount' => $countQuery->count(),
                'pageSize' => Yii::$app->getModule('blog')->postPerPage,
                'defaultPageSize' => Yii::$app->getModule('blog')->postPerPage,
                'pageParam' => 'pageNum',
                'forcePageParam' => false,
            ]);
            $postModels = $query->offset($pages->offset)->limit($pages->limit)->all();
    
            return $this->render('index', [
                'postModels' => $postModels,
                'pages' => $pages,
            ]);


    Представление:
    echo LinkPager::widget([
                'pagination' => $pages,
                // Отключаю ссылку "Следующий"
                'nextPageLabel' => false,
                // Отключаю ссылку "Предыдущий"
                'prevPageLabel' => false,
            ]);


    Вроде на оба вопроса ответил.

    P.S.

    Использую доработанный LinkPager. В частности ради настройки `activeLinkable` (не ссылаться на активную страницу), отображения номера конечной страницы и вывода островной нумерации:
    1,2,3,4 ... 44 [45] 46 ... 999
    Ответ написан
    1 комментарий