Asked  7 Months ago    Answers:  5   Viewed   31 times

Some friends and I decided to start working on a project and we came across Laravel and thought it might be a good tool. We started using it locally to develop out some of our pages and noticed something strange.

When we update a view with different information, it would take almost 5 to 10 minutes before the views information would change. It's like Laravel is caching the view and put a TTL on it.

I know this isn't anything I am doing on my local web server because I have used other frameworks and I have never encountered this issue.

Upon searching the Internet, I can't find a great answer on how to disable this. I want to use Laravel, but find it worthless if it takes a while for my views to update each time I want to make a change. In fact, it sounds counter productive.

Is there any way to disable this? Why are my views taking forever to update right out of the box?

 Answers

70

The #laravel IRC channel is a God send. This had nothing to do with Laravel's behavior at all. This was actually something PHP 5.5 was doing.

The reason this was so baffling is because I upgraded my PHP version from 5.3 and never had this issue.

In your .ini file, you need to tweak your OPcache settings. For me, these settings began at line 1087 in the .ini file and looked something like this:

opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1

Take particular note of the opcache.revalidate_freq=60. This is what is actually making your views cache. If this is not the desired behavior, set the value to 0 and your views will update every time you make a change. Yay!

EDIT AUGUST 21, 2014

As mentioned by Matt below, make sure to restart your web server to see your changes take effect after you have changed your .ini file.

Wednesday, March 31, 2021
 
tadman
answered 7 Months ago
33

Quick and Dirty

Well, one option, as I'm sure you know, is to cache the items inside of controllers as the View is being rendered. I suspect you don't want to do that, as it's less maintainable in the long-run.

More maintainable(?) method

However, if the View loader/renderer doesn't fire an event where you want, you can create one. Because every package/library in Laravel 4 is set in the App container, you can actually replace the View library with your own.

The steps I would take is:

  1. Create a library/package. The goal is to create a class which extends Laravel's view logic. After taking a look, you might want to extend this one - This is the View facade
  2. If you extended the View facade with your own (aka if my assumption on the file in step 1 is correct), you'll then just need to replace the alias for View in app/config/app.php with your own.

Edit- I played with this a bit. Although I don't necessarily agree with caching a View result, vs caching sql queries or the "heavier lifts", here is how I'd go about doing this in Laravel 4:

The View rendering in Laravel 4 doesn't fire an event that let's us cache the result of a view. Here's how I've added in that functionality to cache a view's result.

You may want to consider the ramifications of caching a view's result. For instance, this doesn't get around doing the hard work of talking to a datbase to get the data needed for the view. In any case, this gives a good overview on extending or replacing core items.

First, create a package and set up its autoloading. I'll use the namespace FideloperView. It's autoloading in composer.json will looks like this:

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

Next, create a class to replace the View facade. In our case, that means we'll be extending IlluminateViewEnvironment.

In this class, we'll take the result of the View being rendered and add some logic to cache (or not cache) it. Here is Fideloper/View/Environment.php:

<?php namespace FideloperView;

use IlluminateViewEnvironment as BaseEnvironment;
use IlluminateViewView;

class Environment extends BaseEnvironment {

    /**
     * Get a evaluated view contents for the given view.
     *
     * @param  string  $view
     * @param  array   $data
     * @param  array   $mergeData
     * @return IlluminateViewView
     */
    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;
    }

}

So, that's where the bulk of your work will be - filling out that // Cache Logic Here. However, we have some plumbing left to do.

Next, we need to set up our new Environment class to work as a Facade. I have a blog post about creating Laravel facades. Here's how to accomplish that in this case:

Create the facade for our new Environment. We'll name it fideloper.view in code.

<?php namespace FideloperView;

use IlluminateSupportFacadesFacade;

class ViewFacade extends Facade {

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

}

Then, create the Service Provider which will tell Laravel what to create when fideloper.view is called. Note that this needs to mimic functionality of the IlluminateViewViewServiceProvider for creating the extended Environment class.

<?php namespace FideloperView;

use IlluminateSupportServiceProvider;

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;
        });
    }

}

Lastly, we need to hook this all together and tell Laravel to load our Service Provider and replace Illuminate's View facade with our own. Edit app/config/app.php:

Add the Service Provider:

'providers' => array(

    // Other providers

    'FideloperViewViewServiceProvider',

),

Replace the View facade with our own:

'aliases' => array(

    // Other Aliases

    //'View'            => 'IlluminateSupportFacadesView',
    'View'            => 'FideloperViewViewFacade',

),

You'll then be able to use whatever logic you wish in the View::make() method!

Finally

It's worth noting that there are some patterns to load in multiple "requests" per web request. Symfony, for instance, let's you define controllers as servers. Zend has (had?) a concept of Action Stacks, which let you

... effectively help you create a queue of [controller] actions to execute during the request.

Perhaps you'd like to explore that possibility within Laravel, and cache the results of those "actions" (vs caching a view directly).

Just a thought, not a recommendation.

Wednesday, March 31, 2021
 
AlterPHP
answered 7 Months ago
61

Putting a

<?php xdebug_break(); ?>

into your blade file works pretty well. Even in my tests, PHPstorm jumps to the next PHP statement in some cases.

Why this works:

Laravel processes the blade file to a normal PHP file in the cache folder. But the PHP statement xdebug_break(); will be transferred there and cause the program to halt at the position you want it to (in the cache file).

Wednesday, March 31, 2021
 
employeegts
answered 7 Months ago
31

I guess you try to show the search results after searching. The problem is this line.

return Redirect::to('property/search', compact('properties'));

After you get the search result you should call a view, not redirect.

return view('property.search', compact('properties'));

But make sure you have the view file.

Source

Wednesday, March 31, 2021
 
cyber_truite
answered 7 Months ago
63

Framelayouts (and anything extending View) are designed to be drawn on a Canvas element in 2D. It is not possible to draw these using openGL. If you want to draw a GUI in 3D/GL then you will have to code that up from scratch or find a library which has already done this. I'm sure there are a few out there but I haven't had the need for one yet.

You can get some fake looking 3D effects on views by using scale animations, though these will only work if the animation is done fast so the user doesn't notice. This probably isn't what you are after.

<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
    android:fromXScale="1.0" android:toXScale="0.0"
    android:fromYScale="1.0" android:toYScale="1.0"
    android:pivotX="50%" android:pivotY="0%"
    android:duration="@android:integer/config_shortAnimTime"
/>

Saturday, August 21, 2021
 
Kumar112
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :