Блог

Пишу о PHP, Laravel и Yii2, фрилансе и работе веб–разработчика.

Ошибка в регулярных выражениях роутов Yii2 в PHP7.3

Недавно занимался отладкой старого приложения на Yii2 и встретил странную ошибку:

yiibaseErrorException: preg_match(): Compilation failed: invalid range in character class at offset 376 in .../vendor/yiisoft/yii2/web/UrlRule.php

Понятно: что-то не так с роутами в конфигах. Отследил, с какими конкретно роутами проблема, и вот что оказалось:

preg_match('/[w-.]+/', ''); // Этот код не будет работать в PHP7.3
preg_match('/[w\-.]+/', ''); // Это работает в PHP7.3, необходимо экранировать дефис

Дело в том, что в PHP7.3 обновился движок регулярных выражений с PCRE на PCRE2. Вот выдержка из списка обновлений PHP7.3:

With PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL set, escape sequences such as \s which are valid in character classes, but not as the end of ranges, were being treated as literals. An example is [_-\s] (but not [\s-_] because that gave an error at the start of a range). Now an «invalid range» error is given independently of PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL.

Почему в выдаче гугла больше нет звёзд рейтинга? Микроразметка для статей

Раньше можно было добавить возможность голосования к статье, разбавить всё это микроразметкой, и гугл в поисковой выдаче показывал звёзды рейтинга в сниппете, что повышало количество кликов (CTR). Сейчас гугл обновил правила. По новым правилам, звёзды будут отображаться только у следующих типов материалов:

  • книга,
  • курс,
  • мероприятие,
  • игра,
  • инструкция «how-to»,
  • локальный бизнес,
  • фильм,
  • эпизод сериала,
  • музыкальный плейлист,
  • музыкальная запись,
  • рецепт,
  • продукт (товар),
  • приложение/компьютерная программа.

В списке нет статей, записей в блогах. У всех таких материалов звёзды пропали в выдаче, а инструмент проверки микроразметки от гугла выдаёт ошибку «Article/BlogPosting/Person — недопустимый тип целевого объекта для свойства itemReviewed».

Что делать с этим?

  1. Починить микроразметку;
  2. Следить за изменениями от Гугла. Вероятно, они в ближайшее время ещё доработают свой механизм.

Важно! Не стоит пытаться обмануть Гугл, манипулируя микроразметкой. За это могут прилететь ручные меры — об этом ниже.

Почему у некоторых конкурентов есть звёзды в статьях?

Некоторые сайты некорректно размечают часть статейных страниц, помечая их как Product. Внутри Product размечают рейтинг, а Гугл думает что всё хорошо и показывает звёзды.

Особенно сильно этим выделяются сайты, которые используют виджет комментариев Cackle. Этот виджет выводит комментарии с микроразметкой звёзд, но при этом говорит, что на странице Product, а не Article.

По правилам Гугла это является нарушением. На форуме тоже об этом написали. Кратко: за такое нарушение прилетают ручные меры. Скорее всего, ваши конкуренты либо получат ручные меры, либо просто лишатся звёзд в ближайшее время. Если же всё останется как есть, то скоро на всех сайта будут виджеты Cackle, а тогда звёзды будут у всех или ни у кого :-).

Как скрыть шаблон Vue.js пока он не отрендерится. Директива [v-cloak]

Бывают ситуации, когда вы загружаете страницу с каким-то компонентом Vue, и при этом страница при загрузке «прыгает»: сначала показывает синтаксис шаблона Vue, а потом рендерит сам шаблон. Вот пример:

Страница загрузилась, а компонент Vue ещё не отрендерился
Читать далее

В чём разница между props и data в Vue.js

Во Vue предусмотрено два способа хранения данных в компоненте: props и data.

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

Так в чём же отличие между props и data?

Data — это приватное хранилище любого компонента, в котором вы можете хранить любые данные.

Props — то, как вы передаёте данные из родительского компонента в дочерний.

В этой статье вы узнаете:

  • Чем являются props, и почему они нужны только для передачи данных вниз;
  • Для чего используется data;
  • Что такое реактивность;
  • Как избежать конфликта имён между props и data;
  • Как одновременно использовать props и data вместе, чтобы получить пользу 💰
Читать далее

Прокрутка яндекс-карты на мобильных touch устройствах

Бывает так, что вы подключаете на странице яндекс-карту, которая занимает всю ширину экрана. Это создаёт проблему прокрутки на устройствах с touch-экранами: вместо прокрутки страницы вы начинаете скролить карту.

В яндекс-картах есть несколько опций, которые помогут вам управлять этим:

map.behaviors.disable('multiTouch');
map.behaviors.disable('drag');
map.behaviors.disable('scrollZoom');

Как привязать чат-бота в Telegram к текущему пользователю в Laravel

В большинстве инструкций по работе с телеграм-ботом не сказано про то, как получить тот самый RECIPIENT_CHAT_ID, в который надо слать сообщения из PHP.

Вот типичный пример отправки сообщения из Laravel-приложения в Телеграм:

Route::post('bot/sendmessage', function() {
    Telegram::sendMessage([
        'chat_id' => 'RECIPIENT_CHAT_ID',
        'text' => 'Привет, мир!'
    ]);
    return;
});

Предположим, что наша задача — слать уведомления пользователю в телеграм, если на сайте ему ответили на комментарий. Такое уведомление нужно отправлять только конкретному пользователю, а не всем сразу.

Простой способ для привязки пользователя на сайте и чата с ботом в телеграме — использование ссылки-инвайта для добавления чат-бота. Вы даёте пользователю специальную ссылку с параметром, и когда он на неё кликает — открывается чат с ботом, бот получает инструкцию «начать работу» и отправляет информацию на сервер вместе с тем самым параметром из ссылки, а также CHAT_ID. По этому параметру вы находите в своей базе пользователя и назначаете ему CHAT_ID.

Показываем пользователю на сайте ссылку:

https://telegram.me/triviabot?start=asd123

Когда пользователь перейдёт по ссылке, у него откроется чат 1-на-1 с ботом. Как только пользователь нажмёт кнопку Start, бот получит сообщение вида:

/start PAYLOAD

Вместо PAYLOAD и будет тот самый токен. В нашем примере это asd123. Теперь вам нужно обработать это сообщение на своём сервере.

Вот пример для обработчика, который привязан к Webhook:

if ($message->getText()) {
    if (strpos('/start', $message->getText()) !== false) {
        $textStrings = explode(' ', $message->getText());

        if (isset($textStrings[1])) {
            $token = $textStrings[1];
            $chatId = $message->getChat()->getId();

            if ($token) {
                $user = User::find(['telegram_token' => $token]);

                if ($user !== null) {
                    $user->telegram_chat_id = $chatId;
                    return response()->json(['status' => $user->save()]);
                }
            }
        }
    }
}

В официальной документации Телеграм есть описание этого механизма, который называется Deep linking.

В телеграме каждый чат имеет свой уникальный CHAT_ID. Обратите внимание, что чат с ботом будет иметь числовой CHAT_ID больше 0, а если вы добавили бота в группу, то CHAT_ID будет отрицательный.

Как сбросить кеш VK, FB и Telegram для Opengraph-изображений

Бывает так, что вы расшарили ссылку на свой сайт в соцсетях, после чего изменили на сайте картинку-превью или заголовок, а соцсети не подтягивают новые данные. Это происходит потому, что сервисы один раз получают информацию о ссылке и сохраняют её у себя в кеше, и в следующий раз уже берут информацию из своего кеша. Как заставить соцсети обновить информацию о своей ссылке?

Сбросить кеш в Фейсбуке

https://developers.facebook.com/tools/debug/

Переходим по ссылке — это дебаг-панель Фейсбука. В форме сверху указываем ссылку на свой сайт и загружаем результат. Для обновления данных нужно нажать кнопку «Повторить скрапинг».

Как сбросить кеш Фейсбук для ссылки
Дебаг-панель для сброса кеша Фейсбука

Сбросить кеш Вконтакте

https://vk.com/dev/pages.clearCache

Открываем страницу, прокручиваем вниз к форме для указания ссылки, заполняем её и жмём «Выполнить». В случае успеха вы увидите надпись response: 1. После этого можете расшаривать Вконтакте вашу ссылку с новой превью.

Пример сброса кеша Вконтакте. Результат выполнения — успешно (response: 1)

Сбросить кеш для Телеграма

Пишем боту @WebpageBot, далее просто следуем инструкциям: отправьте ссылку боту, дальше он сам всё сделает. В ответном сообщении пришлёт обновлённые данные и кнопки для повторного обновления данных на случай, если вы в режиме реального времени вносите изменения и занимаетесь отладкой.

Пример работы бота

Готовый код для Pagination в Bulma для Laravel 5

Сначала вам нужно скопировать к себе в resources/views шаблон пагинации. Делаем:

php artisan vendor:publish --tag=laravel-pagination

Эта команда разместит шаблоны в папке resources/views/vendor/pagination.

По-умолчанию Laravel использует шаблон bootstrap-4.blade.php. Меняем его код:

@if ($paginator->hasPages())
    <nav class="pagination is-centered" role="navigation" aria-label="pagination">
        {{-- Previous Page Link --}}
        @if ($paginator->onFirstPage())
            <a class="pagination-previous" disabled>Previous</a>
        @else
            <a class="pagination-previous" href="{{ $paginator->previousPageUrl() }}">Previous</a>
        @endif

        {{-- Next Page Link --}}
        @if ($paginator->hasMorePages())
            <a class="pagination-next" href="{{ $paginator->nextPageUrl() }}">Next Page</a>
        @else
            <a class="pagination-next" disabled>Next Page</a>
        @endif
        

        {{-- Pagination Elements --}}
        <ul class="pagination-list">
            @foreach ($elements as $element)
                {{-- "Three Dots" Separator --}}
                @if (is_string($element))
                    <li><span class="pagination-ellipsis">…</span></li>
                @endif

                {{-- Array Of Links --}}
                @if (is_array($element))
                        @foreach ($element as $page => $url)
                            @if ($page == $paginator->currentPage())
                                <li><a class="pagination-link is-current" aria-label="Goto page {{ $page }}">{{ $page }}</a></li>
                            @else
                                <li><a href="{{ $url }}" class="pagination-link" aria-label="Goto page {{ $page }}">{{ $page }}</a></li>
                            @endif
                        @endforeach
                @endif
            @endforeach
        </ul>

    </nav>
@endif

Как посмотреть размер всех подключаемых через Laravel-mix Javascript библиотек

Бывает полезно посмотреть размер файлов всех подключаемых библиотек и фреймворков, из которых собирается приложение. Это можно легко сделать с помощью плагина bundle-analyzer для Webpack. Ставим плагин:

npm i laravel-mix-bundle-analyzer

Добавляем плагин в webpack.mix.js:

const mix = require('laravel-mix');
require('laravel-mix-bundle-analyzer');

if (!mix.inProduction()) {
    mix.bundleAnalyzer();
}

Теперь вы можете запустить npm run dev, и после сборки откроется браузер с анализом:

Результат работы Bundle-analyzer

Полная документация к плагину доступна на сайте laravel-mix.

Плюрализация строк в Laravel для русского языка

Часто встречается задача выбора окончания для строк во множественном числе. В Laravel есть готовое решение, которое описано в документации, но мне не удалось найти готового примера, который бы работал корректно с русским языком. Вот простое решение, которое покрывает большинство случаев:

{{ trans_choice('Публикация|Публикации|Публикаций', $user->articles->count()) }}

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