Drupal 8 где хранит кэш

Обновлено: 07.07.2024

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

Каким образом?

Контекст кэша - это строка, которая ссылается на одну из доступных служб контекста кэша (см. ниже).

Контексты кэша передаются в наборах (порядок не имеет значения) строк, поэтому они печатаются в string[]. Это наборы, потому что один элемент кэша может зависеть (варьироваться) от многих контекстов кэша.

Но это не означает, что контексты кэша должны исходить из запроса - они также могут зависеть от развернутого кода, например, контекста deployment_id

Во-вторых, контексты кэша описаны в виде иерархии. Самый простой пример: когда что-то отличается для каждого пользователя, то нам уже не нужно использовать просто права доступа, потому что различия для каждого пользователя. Для набора прав доступа кэширование используется для каждого из прав доступа. Если одна часть страницы отличается для каждого пользователя, а другая для прав доступа, то Drupal должен быть достаточно умным, чтобы использовать различия только для каждого пользователя. Именно здесь Drupal может использовать информацию иерархии, чтобы не создавать ненужных изменений кэша.

Синтаксис

  • точки разделяют родительские элементы от дочерних
  • Имя кэша во множественном числе указывает, что может использоваться параметр: добавьте двоеточие, затем укажите желаемый параметр (если параметр не указан, будут собраны все возможные параметры, например, все аргументы запроса)

Контексты кэша ядра Drupal 8

Ядро Drupal 8 поставляется со следующей иерархией контекстов кэша:

Примечание. Чтобы использовать контекст кэширования url.path.is_front в предыдущих ветках/релизах, см. запись об изменении.

Везде, где используются контексты кэша, указывается вся эта иерархия, которая имеет 3 преимущества:

  • нет двусмысленности: понятно, на чем основан родительский контекст кэша, где бы он ни использовался
  • Сравнение (и сворачивание) контекстов кэша становится проще: если присутствуют и a.b.c, и a.b, очевидно, что a.b включает в себя a.b.c, и, следовательно, понятно, почему a.b.c можно опустить, почему его можно «свернуть» в родительский объект
  • не нужно заботиться о том, чтобы каждый уровень дерева был уникальным во всем дереве

Итак, примеры контекстов кэша из этой иерархии:

Оптимизация/сворачивание/объединение/упрощение контекстов кэша

Drupal автоматически использует информацию об иерархии, чтобы максимально упростить контексты кэша. Например, когда одна часть страницы изменяется для пользователя (контекст кэша user), а другая часть страницы изменяется для разрешения (контекст кэша user.permissions), тогда нет смысла изменять конечный результат в разрешениях, так как изменения будут для каждого пользователя отдельно.
Другими словами: optimize([user, user.permissions]) = [user].

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

Вот почему контексты кэша, которые зависят от конфигурации, которая может меняться со временем, могут связывать метаданные кэшируемости: теги кэша и максимальный возраст (max-age). Когда такой контекст кэша оптимизируется, его теги кэша ассоциируются с элементом кэша. Следовательно, всякий раз, когда назначенные разрешения изменяются, элемент кэша также становится недействительным.

(Помните, что «кэширование» - это, по сути, «избежание ненужных вычислений». Поэтому оптимизацию контекста можно рассматривать как кэширование результата метода getContext() службы контекста. В данном случае это неявный кеш (значение отбрасывается вместо того, чтобы сохранять), но эффект тот же: при попадании в кеш метод getContext() не вызывается, следовательно: вычислений избегают. А когда мы что-то кешируем, мы связываем кешируемость этой вещи, поэтому в случае кешируем контексты, мы связываем теги и max-age.)

Аналогичным, но более сложным примером являются node grants. Node grants применяются к конкретному пользователю, поэтому контекст кэша разрешений ноды имеет вид user.node_grants За исключением того, что разрешения ноды могут быть чрезвычайно динамичными (они могут, например, зависеть от времени и изменяться каждые несколько минут). Это зависит от реализаций хуков node grant, представленных на сайте. Следовательно, лучше использовать контекст кеша node grants, с max-age = 0, означающий, что он не может быть кеширован (то есть оптимизирован). Следовательно, optimize([user, user.node_grants]) = [user, user.node_grants].

Определенные сайты могут переопределить реализацию контекста кэширования разрешений для узла по умолчанию и вместо этого указать max-age = 3600, указывая, что все их перехватчики разрешений узла позволяют кэшировать результаты доступа не более часа. На таких сайтах оптимизируйте optimize([user, user.node_grants]) = [user].

Как распознать, определить и создать?

Контексты кэша - это сервисы с тегами cache.context. Таким образом, любой модуль может добавить контексты кеша. Они реализуют \Drupal\Core\Cache\Context\CacheContextInterface или \Drupal\Core\Cache\Context\CalculatedCacheContextInterface (для контекстов кэша, которые принимают параметры, т.е. контексты кэша, которые принимают суффикс :parameter).

Следовательно, все, что вам нужно сделать, чтобы найти все контексты кэша, которые у вас есть для использования, - это перейти к CacheContextInterface и CalculatedCacheContextInterface и использовать вашу IDE, чтобы найти все его реализации. (В PHPStorm: Иерархия типов → Иерархия подтипов в NetBeans: щелкните правой кнопкой мыши имя интерфейса → Найти использование → Найти все подтипы.)

В качестве альтернативы вы можете использовать консоль Drupal (drupal debug:cache:context) для отображения всех текущих контекстов кэша для вашего сайта или приложения:

В каждом найденном вами классе вы увидите такой комментарий \Drupal\Core\Cache\Context\UserCacheContext:

Это означает, что 'user' - это фактический контекст кэша, который вы можете указать в коде. (В качестве альтернативы найдите, где этот класс используется в файле *.services.yml, и посмотрите идентификатор службы. Подробнее об этом ниже.)

Совет: Вы можете получить актуальный полный список всех контекстов кеша в ядре Drupal, только взглянув на сервисы, помеченные cache_context!

Идентификатор услуги стандартизирован. Он всегда начинается с cache_context., За которым следуют родители контекста кеша, и, наконец, имя контекста кеша. Так, например: cache_context (обязательный префикс) + route (parent) + book_navigation (имя этого контекста кэша):

Это определяет контекст кеша route.book_navigation.

Отладка

Все вышеперечисленное является полезной информацией при отладке чего-либо, что кэшируется. Но есть еще одна вещь: скажем, что-то кешируется с ключами кэша ['foo', 'bar'] и контекстами кэша ['languages:language_interface', 'user.permissions', 'route']. Затем соответствующий элемент кэша будет кэшироваться в конкретном контейнере кэша с CID (идентификатором кэша):

  • ключи кеша перечислены первыми, в указанном порядке
  • контексты кэша перечисляются вторыми в алфавитном порядке и приводят к частям CID в форме [<cache context name>]=<cache context value>
  • все эти части CID объединяются с помощью двоеточий

Это должно облегчить анализ и отладку кешей!

Заголовки (отладка)

И наконец: легко увидеть, от каких контекстов кэша зависит определенный ответ (и, следовательно, он варьируется): достаточно взглянуть только на заголовок X-Drupal-Cache-Contexts!

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

Динамический кэш страницы

Всестороннее использование контекстов кэша в Drupal 8 позволяет Drupal 8 поставляться с включенным по умолчанию динамическим кэшем страниц. (Ранее известный как «Smart Cache»)

Внутренний кэш страницы

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

Смотрите также

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.

image

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

Один из примеров использования кэша в Drupal — это кэш меню. В большинстве случаев меню не является часто изменяемой частью сайта. Не имеет смысла каждый раз перестраивать (получать все пункты, их зависимость друг от друга, выводить их в шаблон) меню для вывода пользователю при его заходе на новую страничку сайта. Тем более, что если это меню каталога из 1000 пунктов, оно может перестраиваться для вывода достаточно долгое время. Зачем же заставлять пользователя ждать? Поэтому Drupal кэширует однажды построенное меню на указанное администратором время и выводит его пользователю из кэша, избегая долгой операции по перестраиванию меню.

Drupal содержит встроенный кэш (в своих базовых модулях), который можно настроить на странице: /admin/settings/performance. Нужно не забывать его периодически чистить, когда вы добавляете новую функциональность в каких-либо своих разработках (будь то шаблоны или модули).

  • С помощью кнопки «Очистить кэш» на странице /admin/settings/performance
  • Установить модуль admin_menu и выбрать в самой левой вкладке Flush all caches (Очистить все кэши)
  • С помощью ссылки «Empty cache» (очистить кэш) блока Devel Block (модуль Devel)
  • Выполнив команду Drush: drush cache-clear theme (чистится только кэш темы)
  • Программно, вызвав функцию drupal_rebuild_theme (чистится только кэш темы)

Кэш Drupal разбит по сегментам, а не хранится в одном единственном месте. По умолчанию каждый сегмент кэша хранится в виде отдельной таблицы в базе данных. Это позволяет выносить часто обновляемые сегменты кэша в другие системы хранения кэша, например в Memcached или Boost. Так же это повышает производительность работы с кэшем — в меньших объёмах данных работа с записями происходят быстрее. Более того, при определённых действиях кэш может очищаться частично (сегментно).

Drupal насчитывает множество различных сегментов кэша. Сегменты кэша похожи для версий 7.XX и 6.XX:

1. — сегмент для общего хранилища кэша. Сюда попадают данные, которые невозможно классифицировать, либо же нет смысла создавать под них новый сегмент кэша.

2. — добавляется при включении модуля Block (входит в ядро). При загрузке региона темы Drupal производится загрузка данных по всем блокам этого региона и при необходимости производится построение блока или отображение его из кэша, пропуская вызов хука hook_block_view(). Стоит учесть, что кэширование для блоков отключается, если включаются модули по работе с доступами к материалу, использующие hook_node_access(). Так же необходимо знать, что при программном создании блока через hook_block_info() можно управлять параметрами кэширования для блока (подробнее — в документации).

3. — модуль Filter создает свою таблицу для хранения кэша для обработанного фильтрами текста. Чем сложнее фильтр, тем больше процессорного времени тратится на обработку текста. Поэтому по возможности все вызовы check_markup() кэшируются. Cache ID для таблицы собирается по правилу название_формата: язык: хэш_текста.

4. — если остальные кэшируемые данные хранятся для ускорения работы сайта, то этот кэш на производительность никак не влияет. Он необходим, чтобы формы, построенные с помощью Forms API, были абсолютно безопасными с точки зрения уязвимостей. Каждый раз при построении формы она сохраняется в сегменте . Если форм и посетителей много, то имеет свойство разрастаться до внушительных размеров, если не запускать cron для очистки кэша каждый час-два.

5. — включается при включении модуля Menu и является хранилищем ссылок из всех меню, созданными через интерфейс. Cache ID строится по правилу links: имя_меню:tree-data: язык: хэш_параметров.

6. — хранит закэшированные данные страниц для анонимных пользователей. Если найден кэш для текущей страницы, то будут вызваны только 2 хука: hook_boot() и hook_exit(). Остальные же хуки (включая hook_init() и прочие) будут пропущены. Это именно тот кэш, который включается на сайте в разделе настроек производительности (admin/config/development/performance) галочкой «Кэшировать страницы для анонимных пользователей».

7. — модуль Update manager добавляет данный сегмент. Он хранит данные по всем релизам для включенных модулей.

Сегменты кэша, имеющиеся в Drupal версии 7.XX (нет в версии 6.XX):

1. — хранит соответствие между системным путём и его алиасами для более быстрого поиска алиаса по системному пути.

2. — зарезервирована модулем Image и может использоваться как хранение сведений о проведении различных манипуляций над изображениями.

3. — сегмент кэша, в котором хранятся данные, инициализируемые при загрузке Drupal.

4. — в данном сегменте хранятся данные по всем полям (fields). Cache ID формируется по правилу field: тип_сущности:id_сущности.

  • cache_hacked
  • cache_l10n_update
  • cache_token
  • cache_views
  • cache_views_data

Жизненный цикл страницы

При запросе страницы у веб-сервера браузером пользователя происходит следующее (на примере Drupal версии 7.XX):

  • DRUPAL_BOOTSTRAP_CONFIGURATION: Инициализирует только конфигурацию.
  • DRUPAL_BOOTSTRAP_PAGE_CACHE: Инициализация слоя кэширования.
  • DRUPAL_BOOTSTRAP_DATABASE: Инициализация слоя базы данных.
  • DRUPAL_BOOTSTRAP_VARIABLES: Инициализация слоя переменных.
  • DRUPAL_BOOTSTRAP_SESSION: Инициализация работы с сессиями.
  • DRUPAL_BOOTSTRAP_PAGE_HEADER: Инициализация слоя работы с заголовками.
  • DRUPAL_BOOTSTRAP_LANGUAGE: Инициализация слоя работы с языком страницы.
  • DRUPAL_BOOTSTRAP_FULL: Полностью загружает Drupal. А также добавляет функции проверки и исправления введенных данных.
  • Подключение файлов системных функций.
  • Инициализация всех слоёв и первичных настроек.
  • Подключение файлов всех включённых модулей.
  • Инициализация переменных и системных функций для работы с путями и их алиасами в Drupal.
  • Инициализация включённой темы оформления.
  • Производится выполнении module_invoke_all(). Реализует API для загрузки и взаимодействия с модулями Drupal, регистрируя все хуки текущих включённых модулей.
  • Функции drupal_deliver_html_page(), которая возвращает данные страницы в виде HTML в браузер пользователя. Внутри этой функции вызывается функция drupal_render(), которая не только выводит данные, но и сохраняет в один из сегментов кэша и достаёт их оттуда при их наличии вместо повторной генерации страницы с использованием шаблонизатора.
  • Функции drupal_page_footer(), которая устанавливает кэш страницы ('cache_path' и 'cache_bootstrap'), если это необходимо, и позволяет модулям реагировать на закрытии страницы по hook_exit (). Тут же при необходимости производится запуск Cron.
  1. Производится инициализация всех необходимых переменных и функций.
  2. Производится проверка, имеется ли кэш по данному URL (). Если имеется, то он возвращается, иначе производятся дальнейшие действия.
  3. Производится проверка имеется ли кэш полей (), контента (), меню (), блоков (), а так же изображений () и алиасов (). Если кэш не имеется, то производится операция по получение и обработки необходимых данных с сохранением в кэш. Полученные данные передаются в функцию темизации.
  4. Функция темизации строит страницу и кэширует её по данному URL ().
  5. Данные возвращаются пользователю.

Самым распространённым вариантом работы с кэшем является сохранение данных разрабатываемого модуля в кэш используя функцию cache_set. А также извлечение их из него, используя функцию cache_get.


Очистить данные кэша с именем my_module_data можно, вызвав одну из функций:


Drupal позволяет создавать свои сегменты кэша для хранения данных. Создадим для этого модуль: mymodule. Для этого в каталоге сайта: ./sites/default/modules создадим папку: mymodule. В ней создадим файл описания модуля mymodule.info с содержимым:


Так же создадим файл mymodule.install в котором, используя hook_schema(), создадим новую таблицу для хранения данных своего сегмента кэша:


Существует малоизвестная функция cache_is_empty, с помощью которой можно узнать, хранятся ли в кэше с заданным именем какие-либо данные:

Вынесение кэша из базы данных

Кэш сегментов можно перенести, например в Memcached или Redis.

В данной статье рассмотрим вынесение кэша в Redis, который мне нравится более простой настройкой по сравнению с Memcached. А сравнительные тесты скорости обоих хранилищ рассмотрим в другой статье.


Не забывайте читать файл README.txt в папке модуля, так как в нём описаны все настройки модуля.

Где это можно применить?

image

Один из вариантов применения описанных знаний вынесение части данных сайта в блоки загружающиеся после основной загрузки страницы, как для ускорения загрузки сайта, так и для общего ускорения работы сайта. Достаточно лишь взять за основу модуль Ajax Blocks, интегрировать его с модулем High-performance JavaScript callback handler, а кэш данных поместить в своё хранилище в Redis, используя данную статью.

Drupal 8 имеет множество улучшений по сравнению со своим предшественником, которого мы полюбили и ненавидим. Помимо известных систем, таких как Views в ядре, управления конфигурацией или полезной службы перевода, есть и менее известные изменения, но они одинаково важны для понимания и использования. Одним из таких улучшений стал API кеша, который решает многие проблемы с производительностью, которые есть у нас в Drupal 7.

drupal8wide

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

Кроме того, я подготовил небольшую демонстрацию в виде модуля, который вы можете установить для тестирования влияния API-интерфейса кеша. Это простая страница, которая в своей логике рендеринга выполняет внешний вызов API (для фиктивной конечной точки JSON ) и кэширует свои результаты. Затем на странице отображается фактическое время, необходимое для этого, в отличие от времени внешнего вызова и времени версии в кэше.

Новый API кеша

Концепция кеширования.

Бункеры

Новый API кеша (с хранилищем DatabaseBackend по умолчанию) хранится в нескольких ячейках, которые отображаются в таблицы, начинающиеся с префикса cache_ . При взаимодействии с кешем мы всегда начинаем с запроса кеша:

Где $cache будет экземпляром объекта DatabaseBackend , представляющим корзину по умолчанию ( cache_default ). Для запроса конкретного бина мы передаем имя в конструкторе:

Где $render_cache будет представлять корзину кэша рендеринга (что является новым в Drupal 8 и должно улучшить производительность рендеринга по всем направлениям).

Как видите, мы запрашиваем службу кэширования статически, используя класс \Drupal . Если мы работаем внутри классов, лучше всего внедрить сервис из контейнера . Вы можете сделать это, указав в качестве аргумента для вашей службы соответствующую службу кеша (например, cache.default ). Здесь вы можете получить список всех основных служб, в том числе связанных с кешем.

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

Извлечение кэшированных объектов

Как только мы узнаем, с каким бином мы хотим работать (для пользовательских модулей это обычно будет бин по умолчанию ), мы можем извлечь и сохранить элементы кэша.

Это так просто. $cache будет объектом stdClass содержащим некоторые метаданные об элементе кэша плюс фактические данные, доступные в свойстве $cache->data . Параметр my_value является идентификатором кэша.

Важно помнить, что использование метода get() без второго параметра не вернет элемент кэша, если он был признан недействительным (либо программно, либо по истечении срока действия). Передача логического true в качестве второго параметра заставит его вернуть данные.

Хотя хранить новые элементы в кэше так же просто, как и извлекать их, у нас есть больше возможностей для этого. Для хранения элемента мы используем метод set() (вместо get() как раньше), метод, который принимает 2 обязательных параметра и 2 необязательных:

В качестве примера:

Это установит постоянный элемент кэша, помеченный двумя тегами, и сохранит сериализованную версию $my_object в качестве данных.

Аннулирование и удаление кэша

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

Как уже упоминалось выше, при хранении элемента кэша мы можем указать время истечения. По истечении этого времени элемент кэша становится недействительным, но все еще существует в корзине и может быть получен. Однако мы также можем аннулировать элементы вручную, используя методы invalidate() , invalidateMultiple() или invalidateAll() объекта CacheBackend.

Удаление элементов в целом можно выполнить с помощью методов delete() , deleteMultiple() или deleteAll() . Эти действия также происходят только в том случае, если CacheBackend упаковывает и полностью удаляет соответствующие записи таблицы.

Теги кеша

Чтобы вручную сделать недействительными кэши с помощью тегов, мы можем использовать метод invalidateTags() статически в классе \Drupal\Core\Cache\Cache :

Это вызовет службу аннулирования кэша и my_tag недействительными все элементы кэша, помеченные node:5 и my_tag .

Кроме того, для сущностей Drupal нам не нужно создавать собственные теги, но мы можем извлечь их из системы сущностей:

  • \Drupal\Core\Entity\EntityInterface::getCacheTags()
  • \Drupal\Core\Entity\EntityTypeInterface::getListCacheTags()

Это сохраняет тэги для сущностей Drupal единообразными по всем направлениям.

Демонстрация API кеша

Как я уже упоминал ранее, я создал небольшой модуль, который позволяет нам увидеть преимущества кэширования данных. Вы можете найти модуль в этом git-репозитории, но вот суть его:

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

Файл маршрута, который добавляет новый маршрут к пути /cache-demo :

И класс контроллера, который возвращает страницу внутри src/Controller/CacheDemoController.php :

Вывод

В этой статье мы рассмотрели, как просто использовать Cache API в Drupal 8. Есть несколько очень простых методов класса, которые мы можем использовать для управления элементами кэша, и стало слишком просто, чтобы мы не начали использовать его в наши пользовательские модули. Я призываю вас проверить его, поиграться с API и убедиться, насколько легко им пользоваться.

Ну и чо там?

Из Symfony в Drupal 8 привита всеобщая кэшируемость. Теперь для любого объекта, который участвует в рендеринге, можно задать свои параметры кэширования.

Всего 4 параметра (указывать все необязательно):

keys – массив значений, из которых будет сформировано название для кэша (ID). Типичный набора:
'keys' = > array ( 'entity_view' , $this - > entityTypeId , $entity - > id ( ) , $view_mode )

tags – зависимость от конкретных объектов, например от 5-ой ноды, или пользователя с Интересно, что можно задавать значения типа config:block_list (зависимость от конфигурации блоков), или config:filter.format.basic_html. А еще node_list.
В значениях тега не должно быть пробелов, т.к. пробел используются в качестве разделителя при передаче через header (странно, конечно, что выбран пробел, ну да не о том речь). Этот самый заголовок (X-Drupal-Cache-Tags) интересен для настройки супербыстрой раздачи через систему обратного проксирования (Varnish, CDN).

max-age – время хранения кэша в секундах (0 – не хранить, Cache::PERMANENT (-1) – без ограничения)

Не надо бла-бла, давай пример

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

При рендеринге блока нет трудоемких задач, но его результат все равно будем кэшировать (иначе нафига этот пример). Чтобы убедиться, что кэш работает, кроме значения выведем еще и время, когда это значение было сохранено.

namespace Drupal \ cacheable_block \ Plugin \ Block ;

Drupal ;
use Drupal \ Core \ Block \ BlockBase ;
use Drupal \ Core \ Annotation \ Translation ;
use Drupal \ Core \ Routing ;

/**
* Provides a 'Cacheable Block' block.
*
* Block(
* id = "cacheable_block",
* admin_label = Translation("Cacheable block"),
* )
*/
class CacheableBlock extends BlockBase

$key = 'xxx' ;
$message = "" ;
$value = Drupal :: request ()-> query -> get ( $key );

$value ) $time = date ( "Y-m-d H:i:s" );
$vars = array( 'value' => $value , 'time' => $time );
$message = $this -> t ( 'value (time)' , $vars );
>

my.site?xxx=Kate - > Kate ( 2016 -02-07 11 : 11 : 11 )
my.site?xxx=Ann - > Ann ( 2016 -02-07 22 : 22 : 22 )
my.site / node / 666 ?xxx=Ann - > Ann ( 2016 -02-07 22 : 22 : 22 )
my.site?xxx=Kate - > Kate ( 2016 -02-07 11 : 11 : 11 )

Т.е. если xxx повторяется – значение берется из кэша, независимо от времени и страницы, и наоборот, стоит xxx измениться, и блок выдает другое значение (которое тоже кэширует).

Правда если зайти под другим пользователем, то будет другой кэш, хоть никакой зависимости от пользователей и не указано. И так и не понял, как задать
'cache' = > DRUPAL_CACHE_GLOBAL

Но, можно делать свой кэш с нужным значением и ключами:

<?php
$value = Drupal :: request ()-> query -> get ( $key );
$message = Drupal :: cache ()-> get ( "cacheable_block- $key - $value " )-> data ;
if( $value && ! $message ) $time = date ( "Y-m-d H:i:s" );
$vars = array( 'value' => $value , 'time' => $time );
$message = $this -> t ( 'value (time)' , $vars );
>
Drupal :: cache ()-> set ( "cacheable_block- $key - $value " , $message );
?>

Помни! Если кто-то вобьёт мильярд разных вариантов xxx – ничем хорошим это не закончится. Прямая зависимость кэша от столь легко меняющейся (и бесконечновариантной) зависимости – крайне не рекомендуется.

Еще пример

В блоге Acquia Dev есть пример, в котором рассматривается конвертация изображения в asci-символы. Вот краткая выжимка:

Как тебе такое решение?

Здесь клёвая картинка ламы будет преобразована в ASCII символы. И, будь уверен, преобразование просто прекрасно! Но сейчас разговор не об искусстве ASCII. Динамическая генерация данных на основе изображения, разве это не медленно, спросишь ты. Ясен день! В конце-то концов, как следует преобразовать пушистую ламу в набор символов не так-то и просто. Нет, без шуток, можно придумать кучу случаев затратного рендеринга (требующего сложных вычислений и кучи запросов к бд). Так что кэширование результатов здорово бы помогло. И вот как это можно устроить:

Что за магические значения?

Завязывать кэш на конкретные значения (5-ую ноду, 3-го пользователя) – это, конечно, не солидно. А главное, вряд ли нужные значения известны. Поэтому в реальности, конечно, всё описывается программно.

Например, нужно связать кэш со списком нод из какой-то выборки

Яма, яма, яма, ямллл…

Кстати, простые настройки можно указывать и через YML

renderer.config:
auto_placeholder_conditions:
max-age: 0
contexts: [ 'session' , 'user' ]
tags: [ ]

Настройка через API:

$metadata = new CacheableMetadata ( ) ;
$metadata - > setCacheContexts ( [ 'qux' ] )
- > setCacheTags ( [ 'foo:bar' ] )
- > setCacheMaxAge ( 600 ) ;

Хочу свой рендеринг с кешем и зависимостями

$config = \ Drupal :: config ( 'system.site' );
$current_user = \ Drupal :: currentUser ();

// Merges the cache contexts, cache tags and max-age of the config object
// and user entity that the render array depend on.
$renderer -> addCacheableDependency ( $build , $config );
$renderer -> addCacheableDependency ( $build , \ Drupal \ user \ Entity \ User :: load ( $current_user -> id ()));
?>

Какие есть еще API?

Теги и контексты – обычные массивы, и ничто не мешает их склеить обычным сложением
$tags = $account - > getCacheTags ( ) + $comment - > getCacheTags ( )
Но престижней использовать специально обученные метод, ведь это и инкапсуляция и избавления от повторок
Cache:: mergeTags ( $main_tags , $add_tags ) ;
Все это верно и для contexts, и для max-age.
Если в запросе нет подходящего параметра, чтобы подставить в keys, можно использовать его hash (sha256), через метод keyFromQuery.
Еще есть validateTags, invalidateTags и getBins (bins – контейнеры, в которых хранятся кэши, обычно по названию модуля, к которому принадлежат их значения)

Entity и Config – готовы, а ты?

У всех entity или configuration уже настроены параметры кэширования. Получить их можно так:

\Drupal:: entityManager ( ) - > getDefinition ( 'node' ) - > getListCacheTags ( ) ;
Или через конкретные объекты:
$node - > getEntityType ( ) - > getListCacheTags ( )
(вместо $node, может быть $user, $view…)

Аналогично для contexts и max-age
$this - > entityType - > getListCacheContexts ( )

Что там есть в Examples/cache_example

Хоть там todo больше, чем кода, но можно глянуть как вручную сохранять/получать/удалять кэш:

<?php
cacheBackend -> set ( 'название_кэша' , 'содержимое_кэша' , параметры_кэширования );
$cache = cacheBackend -> get ( 'название_кэша' ); // и потом $cache->data
cacheBackend -> delete ( 'название_кэша' );
?>

Где cacheBackend - это объект реализующий интерфейс CacheBackendInterface.
Там же, в качестве примера, подсчитывают количество файлов в ядре, угадаешь сколько? А вот и нет, всего лишь 5928.

Так кому, что и почему надо знать?

При описании «революционных изменений» Drupal 8, часто упоминают «кэширование по умолчанию». Но это не просто кэширование. Два модуля, Internal Page Cache и Dynamic Page Cache затащили это дело на новый уровень. Вот как описывает историю их создания ведущий разработчик Вим Лирс (вкратце):

Как-то Дрис начал парить мне голову вопросами о ESI. Я сказал, что то, что у нас называется "поддержкой ESI" - бред, но есть реальный шанс сделать хорошо. Дриса это так проняло, что он даже выложил пост А мне пришлось изрядно напрячь башку, чтобы реализовать то, что посулил в запале.

Сначала наша команда довела до ума кэш тэги, благодаря чему Page Cache (ныне Internal Page Cache) стал работать так хорошо, что мы включили его в сборку и включили по умолчанию. А затем добили и контексты кэша. Это далось не просто, пробовали и так и сяк. В резульате на пару с Фабьеном запили через пузырёк. Потом еще 7 месяцев просыхали фиксили, но это того стоило. И теперь Dynamic Page Cache (бывший Smart Cache) тоже в сборке, и тоже по умолчанию.

Конечно, еще есть над чем работать, напрягает и время перед запуском и всякая другая лабуда, но у нас еще есть идеи на этот счет. Кстати, как вам BigPipe?

И еще раз

То, что эти модули включены по умолчанию, означает, что каким бы ты ни был лохом, кэширование на сайте Drupal 8 будет огонь! Только не выключай их. Хотя, если для анонимных пользователей нужны разные результаты (например, с учетом их сессии), то Internal Page Cache придется отключить (либо мутить через AJAX), но это уже другая история.

А в этой истории речь о том, что теперь больше не нужны никакие танцы с Authcache, где нужно учитывать весь код сайта. Более того, опять пошли разговоры, что владелец сайта (админ, маускликер, сайт-билдер) может забыть, что значить фраза «очистить кэш». Поскольку теперь разработчики модулей могут и должны сами настроить зависимости кэша. Контриб-модули даже обязаны предоставить тесты на годность в режиме кэширования.

Но если Dynamic Page Cache мешает запалу разработки, можно временно его отключить, для этого в папке sites/название_сайта/ создается settings.local.php с кодом:

$settings [ 'cache' ] [ 'bins' ] [ 'render' ] = 'cache.backend.null' ;

Когда это будет в 7-ке?

Никогда. В Drupal 7 не появится мгновенного обновления кэша (в Drupal 8 кэш обновляется сразу по факту устаревания, не дожидаясь запроса, ога). Не появится Dynamic Cache Page. И не будет BigPipe. Как-то так.

А где же та фраза?

«There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton»

settings.local.php — файл с настройками локального окружения сайта. Является дополнением settings.php и использует все доступные его настройки.

Данный файл заменят, дополняет или выключает определённые настройки и поведение сайта для локальной системы. Используется при разработке проекта.

¶Создание файла

По умолчанию данный файл отсутствует. Для него поставляется стандартный пример example.settings.local.php который можно найти в директории /sites .

Для создания собственного файла достаточно скопировать example.settings.local.php в папку сайта, где уже находится основной settings.php и переименовать его в settings.local.php .

¶Подключение

Данный файл подключается из основного файлы settings.php . В конце этого файла вы можете найти следующие строки:

Вам достаточно раскомментировать их и настройки из settings.local.php начнут загружаться и использоваться. Вы можете менять данное условие и поведение так как вам угодно. Данный файл должен подключаться в самом конце settings.php для того чтобы он мог изменять все основные настройки.

Убедитесь что данный файл не подключается на продакшене. Это приведёт к серьезному снижению производительности.

¶Применение

Файл settings.local.php применяется на локальных окружения в процессе разработки и заменяет некоторые настройки системы на специальные. Например, отключается кеширование, сжатие и объединение JavaScript и CSS файлов и прочие изменения необходимые для разработки, но не нужны на рабочем проекте.

Эти изменения производятся в settings.local.php для того чтобы эти настройки были явно отражены и было удобно переносить проект, делиться изменениями с командой и т.д.

¶Настройки по умолчанию

В данном разделе рассмотрены все настройки по умолчанию, который указаны в example.settings.local.php файле и подойдут для большинства проектов и задач.

¶Assertions

Drupal использует сравнения (assert), для того чтобы сообщать об ошибках использования API. Когда обнаружена проблема, запрос будет провален и выдана ошибка.

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

Если вы используете PHP 7.0 или выше, то рекомендуется установить настройку zend.assertions=1 в php.ini файле (данную настройку нельзя задавать через .htaccess или ini_set() ). На продакшен сайте убедитесь что данная опция отключена.

Пример:

¶Сервисы для разработки

В данном файле подключается файл development.services.yml с сервисами и параметрами для разработки, которые будут загружены в контейнер.

Пример:

¶Подробное логирование

Для конфигурации system.logging задаётся степень детализации ошибок на подробные ( verbose ). Это значит, что все ошибки будут выводиться, включая стэк вызова.

¶Агрегация JS и CSS

В конфигурации system.performance отключается обработка JavaScript и CSS файлов. Это значит что о ни не будут объединяться, сжиматься и кешироваться. Так вы сможете видеть изменения на сайте сразу после их внесения без необходимости сброса кеша.

¶Кеш рендера

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

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

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

Пример:

¶Кеш миграций

Кеш миграций хранит в себе информацию о всех объявленных миграциях. Если вы активно пишите миграции, вы можете переключить хранение миграций в память, чтобы они обнаруживались сразу как только вы их объявляете.

Это поведение влияет только на официальный способ создания миграций (те что создаются в /MODULENAME/migrations ). Если вы используете Migrate Plus который проксирует миграции, данная настройка не окажет никакого влияния.

Пример:

¶Кеш страниц

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

Вы должны проверять работоспособность сайта и его функционала с включенным Internal Page Cache, для того чтобы убедиться, что кеш собирается корректно.

¶Динамический кеш страниц

Динамический кеш страниц, который предоставляется модулем Dynamic Page Cache, хранит в себе готовые результаты страниц, в зависимости от роли пользователя и прочих контекстов.

Вы должны проверять работоспособность сайта и его функционала с включенным Dynamic Page Cache, для того чтобы убедиться, что кеш собирается корректно.

¶Включить обнаружение тестовых расширений

По умолчанию доступны только расширения (модули, темы оформления) которые не помечены как тестовые. При помощи данной настройки, вы можете включить их обнаружение и отображение в административном интерфейсе.

Пример:

¶Доступ к ребилду

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

Для того чтобы эти кеши были очищены нужно запустить ребилд системы. Для этого с Drupal поставляется файл rebuild.php , который не будет делать ничего, пока данная настройка отключена.

Вы можете использовать команду Drush drush cache:rebuild для полного ребилда кеша. Она будет работать даже с отключенной опцией.

Пример:

¶Отключение принудительного изменения прав на запись для директории сайта

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

¶Смотрите также

🌱 Помогите нам сделать документацию лучше!

Вся документация Druki с отрытым исходным кодом. Нашли ошибку или неточность? Создайте pull request.

Читайте также: