В 14-ом уроке мы разберем одну из важных тем для оптимизации ваших Symfony-приложений, это кэширование. Кэширование позволяет ускорить загрузку страниц, снизить нагрузку на сервер и улучшить пользовательский опыт. В Symfony есть множество инструментов для работы с кэшем и в этом уроке мы подробно изучим их все, от кэширования шаблонов Twig до настройки Redis и Memcached.
Зачем нужно кэширование?
Допустим ваш сайт обрабатывает тысячи запросов в минуту. Каждый раз сервер выполняет одни и те же операции генерирует шаблоны, запрашивает данные из базы, вычисляет сложную логику. Это ресурсоемко и медленно. Кэширование решает эту проблему, сохраняя «тяжелые» вычисления и отдавая их из быстрого хранилища при повторных запросах. Результат — страницы грузятся быстрее, сервер «дышит свободнее», пользователи довольны.
Типы кэширования в Symfony
Symfony поддерживает несколько уровней кэширования. Давайте разберем каждый из них.
1. Кэш приложения
Этот тип кэша хранит результаты дорогостоящих операций, например, результаты запросов к базе данных или вычислений. Symfony использует компонент Cache из Symfony Contracts, который поддерживает различные хранилища: файлы, Redis, Memcached, базы данных.
Пример конфигурации в config/packages/cache.yaml:
framework: cache: app: cache.adapter.redis default_redis_provider: 'redis://localhost:6379'
2. HTTP-кэширование
HTTP-кэширование работает на уровне протокола HTTP. Сервер отправляет клиенту (браузеру или прокси-серверу) заголовки, указывающие, как долго можно хранить копию страницы. Это уменьшает количество запросов к вашему серверу.
3. Кэширование данных
Используется для хранения часто запрашиваемых данных, например, результатов API-запросов или списка товаров. Symfony позволяет гибко настраивать время жизни кэша (TTL) и зависимости между данными.
Кэширование шаблонов Twig
Twig автоматически кэширует скомпилированные шаблоны в виде PHP-кода. Но вы можете вручную управлять кэшированием блоков внутри шаблонов.
Базовое кэширование блоков
Используйте тег {% cache %}, чтобы закэшировать часть шаблона. Например, кэшируем список статей:
{% cache 'article_list' 3600 %} <ul> {% for article in articles %} <li>{{ article.title }}</li> {% endfor %} </ul> {% endcache %}
'article_list'— уникальный ключ кэша.3600— время жизни кэша в секундах (1 час).
Динамический кэш с зависимостями
Если данные зависят от пользователя, добавьте в ключ уникальный идентификатор:
{% cache ['user_profile', user.id] 600 %} <div>Профиль: {{ user.username }}</div> {% endcache %}
Практическая задача
Задача 1: Добавьте кэширование блока с последними комментариями в шаблоне templates/blog/comments.html.twig. Кэш должен обновляться каждые 30 минут.
Решение:
{# templates/blog/comments.html.twig #} {% cache 'latest_comments' 1800 %} <div class="comments"> {% for comment in comments %} <p>{{ comment.text }}</p> {% endfor %} </div> {% endcache %}
HTTP-кэширование с заголовками
Symfony упрощает работу с HTTP-кэшированием через методы класса Response. Рассмотрим основные подходы.
Заголовок Cache-Control
Управляет тем, как кэшируется контент. Пример настройки в контроллере:
use Symfony\Component\HttpFoundation\Response; public function index(): Response { $response = new Response($content); $response->setSharedMaxAge(3600); // Кэшировать на 1 час для всех пользователей return $response; }
setSharedMaxAge()— указывает максимальное время хранения кэша для публичных ресурсов (например, списка статей).setMaxAge()— для приватных ресурсов (например, персональной страницы пользователя).
Валидация кэша с ETag и Last-Modified
Если данные изменились, клиент должен получить новую версию. Для этого используются:
- ETag — хэш контента.
- Last-Modified — дата последнего изменения.
Пример с ETag:
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; public function showArticle(Request $request, Article $article): Response { $response = new Response($this->renderView('article/show.html.twig', [ 'article' => $article, ])); // Генерируем ETag на основе содержимого статьи $etag = md5($response->getContent()); $response->setEtag($etag); // Проверяем, актуален ли кэш у клиента if ($response->isNotModified($request)) { return $response; } return $response; }
Практическая задача
Задача 2: Реализуйте HTTP-кэширование для страницы профиля пользователя. Используйте ETag на основе даты обновления профиля.
Решение:
public function userProfile(Request $request, User $user): Response { $response = new Response($this->renderView('user/profile.html.twig', [ 'user' => $user, ])); // ETag на основе времени последнего обновления $etag = md5($user->getUpdatedAt()->format('Y-m-d H:i:s')); $response->setEtag($etag); if ($response->isNotModified($request)) { return $response; } return $response; }
Redis и Memcached для кэша данных
Файловый кэш подходит для небольших проектов, но для высоконагруженных сайтов лучше использовать Redis или Memcached. Они хранят данные в оперативной памяти, что ускоряет чтение/запись.
Настройка Redis в Symfony
- Установите пакеты:
composer require symfony/cache predis/predis
- Настройте подключение в
.env:
REDIS_URL=redis://localhost:6379
- Используйте Redis для кэша в
config/packages/cache.yaml:
framework: cache: app: cache.adapter.redis default_redis_provider: '%env(REDIS_URL)%'
Пример кэширования данных
Кэшируем результат запроса к базе данных:
use Symfony\Contracts\Cache\ItemInterface; use Symfony\Component\Cache\Adapter\RedisAdapter; class ArticleRepository extends ServiceEntityRepository { public function findCachedArticles(): array { $cache = new RedisAdapter( RedisAdapter::createConnection('redis://localhost:6379'), 'articles_' ); return $cache->get('latest_articles', function (ItemInterface $item) { $item->expiresAfter(3600); // Время жизни 1 час return $this->createQueryBuilder('a') ->orderBy('a.publishedAt', 'DESC') ->setMaxResults(10) ->getQuery() ->getResult(); }); } }
Практическая задача
Задача 3: Перенесите кэш данных для списка товаров из файлового хранилища в Redis. Установите TTL = 2 часа.
Решение:
// В ProductRepository public function findCachedProducts(): array { $cache = new RedisAdapter( RedisAdapter::createConnection('%env(REDIS_URL)%'), 'products_' ); return $cache->get('featured_products', function (ItemInterface $item) { $item->expiresAfter(7200); return $this->createQueryBuilder('p') ->where('p.isFeatured = true') ->getQuery() ->getResult(); }); }
Итоги 14-го урока
Сегодня мы разобрали:
- Типы кэширования в Symfony.
- Работу с кэшем Twig-шаблонов.
- Настройку HTTP-кэширования через заголовки.
- Интеграцию Redis и Memcached.
Не кэшируйте всё подряд. Анализируйте медленные части приложения (например, через Symfony Profiler) и применяйте кэш точечно.
Хотите освоить Symfony? Перейти к полному курсу по Symfony для начинающих.
Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.


