Кеширане на изхода на изгледа в Laravel 4

Знам, че Blade вече кешира компилирания PHP за всички изгледи на блейд, но бих искал да направя тази крачка напред. Уебсайт, върху който работя, е модулиран в изгледи на компоненти и след това е събран заедно в контролера по подразбиране. Всеки от "джаджите" има собствен изглед, който рядко променя съдържанието (с изключение на няколко често актуализиращи се). И така, бих искал да кеширам HTML изхода на тези рядко променящи се изгледи, за да предотвратя тяхното оценяване при всяко зареждане на страница.

В Laravel 3 бихме могли да направим нещо подобно (кредитирайте форумите на Laravel):

Event::listen(View::loader, function($bundle, $view)
{
  return Cache::get($bundle.'::'.$view, View::file($bundle, $view, 
                                                  Bundle::path($bundle).'view'));
});

За съжаление, View::loader е изчезнал напълно в Laravel 4. Когато ровех в \Illuminate\View\View и \Illuminate\View\Environment, открих, че всеки изглед изпраща събитие с име "composing: {view_name}". Слушането за това събитие предоставя името на изгледа и данните, които му се предават при всяко изобразяване на изглед, но връщането от обратното извикване няма същия ефект, както в Laravel 3:

Event::listen('composing: *', function($view) {
  if(!in_array($view->getName(), Config::get('view.alwaysFresh'))) {
    // Hacky way of removing data that we didn't pass in
    // that have nasty cyclic references (like __env, app, and errors)
    $passedData = array_diff_key($view->getData(), $view->getEnvironment()
                                                                  ->getShared());

    return Cache::forever($view->getName() . json_encode($passedData), function() {
      return 'test view data -- this should appear in the browser';
    });
}, 99);

Горното не заобикаля нормалния изглед, включително и процеса на изобразяване.

И така, как можете да заобиколите нормалното рендиране на изглед и да върнете кеширано съдържание от това събитие за композиране? Възможно ли е в момента в Laravel без някакво грозно хакерство?


person Bailey Parker    schedule 04.07.2013    source източник
comment
Мога ли да попитам дали правите това по начин, за да избегнете повторното създаване на данните за изгледа? Все още ли трябва да използвате базата данни, за да създадете изгледи, дори ако самият резултат от изгледа е записан в кеша? Може да имате по-голям късмет да кеширате резултата от посещения в базата данни и т.н.   -  person fideloper    schedule 07.07.2013


Отговори (2)


Бързо и мръсно

Е, една опция, както съм сигурен, че знаете, е да кеширате елементите вътре в контролерите, докато изгледът се изобразява. Подозирам, че не искате да правите това, тъй като е по-малко поддържаемо в дългосрочен план.

По-лесен за поддръжка (?) метод

Ако обаче програмата за зареждане/изобразяване на View не задейства събитие, където искате, можете да създадете такова. Тъй като всеки пакет/библиотека в Laravel 4 е зададен в контейнера на приложението, вие всъщност можете да замените библиотеката View с ваша собствена.

Стъпките, които бих предприел са:

  1. Създайте библиотека/пакет. Целта е да се създаде клас, който разширява логиката на изгледа на Laravel. След като разгледате, може да искате да разширите този - Това е фасадата View
  2. Ако сте разширили фасадата на View с ваша собствена (известна още като ако моето предположение за файла в стъпка 1 е правилно), тогава просто ще трябва да замените псевдоним за View в app/config/app.php с вашия собствен.

Редактиране - Поиграх си малко с това. Въпреки че не съм непременно съгласен с кеширането на резултат от View, срещу кеширането на sql заявки или „по-тежките повдигания“, ето как бих направил това в Laravel 4:

Изобразяването на изглед в Laravel 4 не задейства събитие, което ни позволява да кешираме резултата от изглед. Ето как добавих тази функционалност за кеширане на резултата от изглед.

Може да помислите за последиците от кеширането на резултата от изглед. Например, това не заобикаля упоритата работа на разговора с база данни, за да получите данните, необходими за изгледа. Във всеки случай това дава добър преглед на разширяването или замяната на основните елементи.

Първо създайте пакет и настройте автоматичното му зареждане. Ще използвам пространството от имена Fideloper\View. Автоматичното зареждане в composer.json ще изглежда така:

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php"
    ],
    "psr-0": {
        "Fideloper": "app/"
    }
},

След това създайте клас, който да замени фасадата View. В нашия случай това означава, че ще разширим Illuminate\ Изглед\Среда.

В този клас ще вземем резултата от изобразения View и ще добавим някаква логика, за да го кешираме (или не кешираме). Ето го Fideloper/View/Environment.php:

<?php namespace Fideloper\View;

use Illuminate\View\Environment as BaseEnvironment;
use Illuminate\View\View;

class Environment extends BaseEnvironment {

    /**
     * Get a evaluated view contents for the given view.
     *
     * @param  string  $view
     * @param  array   $data
     * @param  array   $mergeData
     * @return \Illuminate\View\View
     */
    public function make($view, $data = array(), $mergeData = array())
    {
        $path = $this->finder->find($view);

        $data = array_merge($mergeData, $this->parseData($data));

        $newView = new View($this, $this->getEngineFromPath($path), $view, $path, $data);

        // Cache Logic Here

        return $newView;
    }

}

И така, там ще бъде по-голямата част от вашата работа - попълването на това // Cache Logic Here. Въпреки това ни остават водопроводни инсталации.

След това трябва да настроим нашия нов клас Environment да работи като фасада. Имам публикация в блог за създаване на фасади на Laravel. Ето как да го постигнете в този случай:

Създайте фасадата за нашата нова среда. Ще го кръстим fideloper.view в код.

<?php namespace Fideloper\View;

use Illuminate\Support\Facades\Facade;

class ViewFacade extends Facade {

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'fideloper.view'; }

}

След това създайте доставчик на услуги, който ще каже на Laravel какво да създаде, когато се извика fideloper.view. Имайте предвид, че това трябва да имитира функционалността на Illuminate\View\ViewServiceProvider за създаване на разширения Environment клас.

<?php namespace Fideloper\View;

use Illuminate\Support\ServiceProvider;

class ViewServiceProvider extends ServiceProvider {

    public function register()
    {
        $this->app['fideloper.view'] = $this->app->share(function($app)
        {
            // Next we need to grab the engine resolver instance that will be used by the
            // environment. The resolver will be used by an environment to get each of
            // the various engine implementations such as plain PHP or Blade engine.
            $resolver = $app['view.engine.resolver'];

            $finder = $app['view.finder'];

            $env = new Environment($resolver, $finder, $app['events']);

            // We will also set the container instance on this view environment since the
            // view composers may be classes registered in the container, which allows
            // for great testable, flexible composers for the application developer.
            $env->setContainer($app);

            $env->share('app', $app);

            return $env;
        });
    }

}

И накрая, трябва да свържем всичко това заедно и да кажем на Laravel да зареди нашия доставчик на услуги и да замени фасадата View на Illuminate с нашата собствена. Редактиране app/config/app.php:

Добавяне на доставчик на услуги:

'providers' => array(

    // Other providers

    'Fideloper\View\ViewServiceProvider',

),

Заменете фасадата View с нашата собствена:

'aliases' => array(

    // Other Aliases

    //'View'            => 'Illuminate\Support\Facades\View',
    'View'            => 'Fideloper\View\ViewFacade',

),

След това ще можете да използвате каквато желаете логика в метода View::make()!

Най-накрая

Струва си да се отбележи, че има някои модели за зареждане в множество „заявки“ на уеб заявка. Symfony, например, ви позволява да дефинирате контролерите като сървъри. Zend има (има?) концепция за Action Stacks, която ви позволява

... ефективно ви помага да създадете опашка от действия на [контролера], които да се изпълнят по време на заявката.

Може би бихте искали да проучите тази възможност в Laravel и да кеширате резултатите от тези „действия“ (срещу директно кеширане на изглед).

Просто мисъл, не препоръка.

person fideloper    schedule 07.07.2013
comment
+1 за страхотно подробно ръководство за доставчици на услуги и фасади (бих +2 или +3, ако можех!). Избягвах да чета за тях, но вие ме убедихте в обратното. Това е чудесен случай за използването им и добра отправна точка за разширяване на функционалността на Laravel. Благодаря! - person Bailey Parker; 07.07.2013
comment
И за да отговоря на въпроса ви, да, кеширам заявки за DB, така че кеширането на изхода за изглед вероятно е ненужна микрооптимизация. Но е добре да знаете тази процедура за разширяване на функционалността на Laravel. - person Bailey Parker; 07.07.2013
comment
Просто искам да изясня нещо. Кеширането на изгледа заобикаля необходимостта от общуване с базата данни, стига да имате метод, който проверява състоянието на кеша и времето на кеширания HTML. Във вашия метод на контролер вие просто проверявате състоянието на кеша в горната част на метода, ПРЕДИ да извикате нещо от моделите. Ако състоянието на кеша все още е валидно, пропуснете всички неща от DB и просто върнете HTML. Ако състоянието на кеша вече не е валидно, изпълнете нормалната заявка и кеширайте отново резултатите. Ето как използвате Smarty например. - person AgmLauncher; 30.01.2014
comment
Валидно е и за файлове, които може да правят много изобразяване. Имам един конкретен изглед, който отнема около 100 милисекунди при ново рендиране, поради всички части, цикли... и т.н. и никога (почти никога) не се променя. Лесно кеширане и съкращаване на 100ms от времето за зареждане на тази страница :) - person Oddman; 06.01.2015

Има библиотека за кеширане на изгледи/части в Laravel (и не само) - Flatten.

Това е мощна кеш система за кеширане на страници по време на изпълнение. Това, което прави, е доста просто: вие му казвате коя страница да бъде кеширана, кога кешът да бъде прочистен и оттам Flatten обработва всичко. Той тихо ще изравни вашите страници до обикновен HTML и ще ги съхрани. Ето защо, ако потребител посети страница, която вече е изравнена, целият PHP се превзема, за да покаже вместо това проста HTML страница. Това ще осигури съществен тласък на скоростта на вашето приложение, тъй като кешът на страницата ви се опреснява само когато се направи промяна в данните, които показва.

За да кеширате всички разрешени страници във вашето приложение чрез командата artisan flatten:build. Той ще обходи вашето приложение и ще премине от страница на страница, като кешира всички страници, които сте му позволили.

Зачервяване

Понякога може да искате да изтриете конкретна страница или модел. Ако например кеширате профилите на вашите потребители, може да искате да ги изчистите, когато потребителят редактира информацията си. Можете да го направите чрез следните методи:

// Manual flushing
Flatten::flushAll();
Flatten::flushPattern('users/.+');
Flatten::flushUrl('http://localhost/users/taylorotwell');

// Flushing via an UrlGenerator
Flatten::flushRoute('user', 'taylorotwell');
Flatten::flushAction('UsersController@user', 'taylorotwell');

// Flushing template sections (see below)
Flatten::flushSection('articles');

връзка към - https://github.com/Anahkiasen/flatten

person Yaroslav    schedule 04.05.2015