I had some (major) performance issues on a project I'm working on and after logging all the queries that get executed, I realised many of them are executed multiple times and I cannot get to the root of the problem.
All the queries that get executed multiple times are in my view composer provider.
This is what my view composer looks like:
public function boot()
{
view()->composer('partials.sidebar', function ($view) {
$currentCategory = $this->getCurrentCategory();
$sidebarCategories = SidebarCategory::category($currentCategory)
->order()
->get();
$view
->with('sidebarCategories', $sidebarCategories);
});
view()->composer('partials.footer', function ($view) {
$footerLinks = FooterCategory::with('links.translations')->order()->get();
$footerColumn1 = $footerLinks->filter(function ($value, $key) {
return $value->column == 1;
});
$footerColumn2 = $footerLinks->filter(function ($value, $key) {
return $value->column == 2;
});
$footerColumn3 = $footerLinks->filter(function ($value, $key) {
return $value->column == 3;
});
$footerColumn4 = $footerLinks->filter(function ($value, $key) {
return $value->column == 4;
});
$view
->with(compact('footerColumn1', 'footerColumn2', 'footerColumn3', 'footerColumn4'));
});
}
Both of these queries (Sidbar and Footer categories) get executed about 6 times, even though each partials is called exactly once. They are both called in master view with @include('partialname').
I've tried this:
if($view->offsetExists('sidebarCategory'))
return;
But the offsetExists always returns false (even after its called for 5. time).
Any idea why this is happening and what I'm doing wrong?
Edit:
I've realised where the issue is. On the page that I'm visiting (where those multiple queries get executed) there are some 404 elements (images mostly). Each time a file is not found a new 404 exception is thrown. And each time a 404 exception is thrown the 404 view gets executed => meaning footer/sidebar queries get executed as well (as they're a part of 404 view). Example: http://imgur.com/a/RrmOD
So the follow up question is how to prevent the view from getting rendered when there is no need to (example the 404 is an image that wasnt found).
Here is a piece of code from my routes, that I assume is the reason that this is happening:
Route::get('{slug}', ['as' => 'findBySlug', 'uses' => function($slug) {
if(\App\DynamicCategory::findBySlug($slug)->count() > 0)
return App::make('App\Http\Controllers\GeneralController')->getDynamicCategoryIndex($slug);
else if(\App\DynamicPage::noCategory()->findBySlug($slug)->count() > 0)
return App::make('App\Http\Controllers\GeneralController')->getDynamicPage($slug);
else
abort(404);
}]);
PS: I know this piece of code is extremely unoptimized (as it basically executes the same query twice, once to see if the item exists, another time actually in the controller). This is work in progress and it's on todo list.
Edit 2:
I've come up with the next solution, I'm open to improvements as this is a somewhat hack-ish way (if I add more folders, I will need to keep in mind to update this as well). I only have 3 direct subfolders in public folder: something, files and resources.
The solution is to check the url's first segment when rendering the exception (in file app/Exceptions/Handler.php) and return 404 response without the view if it matches one of the 3 folders:
public function render($request, Exception $e)
{
$firstSegment = $request->segment(1);
if(starts_with($firstSegment, 'files') || starts_with($firstSegment, 'something') || starts_with($firstSegment, 'resources')) {
return response('Stran ne obstaja', 404);
}
return parent::render($request, $e);
}
Thanks in advance
Views are stored in the resources/views directory. return view('greeting', ['name' => 'James']); }); As you can see, the first argument passed to the view helper corresponds to the name of the view file in the resources/views directory.
View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.
Views contain the html code required by your application, and it is a method in Laravel that separates the controller logic and domain logic from the presentation logic. Views are located in the resources folder, and its path is resources/views. Let's see the simple example of views.
Don't route file requests through laravel and serve a blank image on 404
.htaccess sample:
RewriteEngine On
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png|ico)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /no_picture.png [L]
You would post this above the rules that redirect to index.php
This is assuming that pictures are served from the website and not by streaming database contents.
Basically what happens is this:
So what you want to do in the last step is prevent the image request even reaching laravel, by serving your own image as per defined by .htaccess rules. That way your webserver can respond much faster on the missing image.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With