Laravel 5.2视图编辑器被多次执行

时间:2016-12-23 10:21:21

标签: php laravel laravel-5

我在一个项目上遇到了一些(主要的)性能问题,我记录了所有执行的查询后,我意识到其中很多都被执行多次,我无法找到问题的根源

多次执行的所有查询都在我的视图编辑器提供程序中。

这是我的视图作曲家的样子:

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

这两个查询(Sidbar和Footer类别)执行大约6次,即使每个部分只调用一次。它们都在主视图中使用@include(' partialname')进行调用。

我试过这个:

if($view->offsetExists('sidebarCategory'))
    return;

但是offsetExists总是返回false(即使在它被调用了5.时间之后)。

知道为什么会发生这种情况以及我做错了什么?

修改

我已经意识到问题出在哪里。在我访问的页面(执行多个查询的位置)上有一些404元素(大多数是图像)。每次找不到文件时,都会抛出新的404异常。每次抛出404异常时,404视图都会被执行=>意思是页脚/侧边栏查询也被执行(因为它们是404视图的一部分)。示例:http://imgur.com/a/RrmOD

因此,后续问题是如何在不需要时防止视图被渲染(例如404是未找到的图像)。

以下是我的路线中的一段代码,我假设这是发生这种情况的原因:

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:我知道这段代码是非常不优化的(因为它基本上执行相同的查询两次,一次查看项目是否存在,另一次实际在控制器中)。这是正在进行的工作,它在待办事项清单上。

编辑2:

我已经提出了下一个解决方案,我可以接受改进,因为这是一种有点黑客的方式(如果我添加更多文件夹,我需要记住将其更新为好)。我在公共文件夹中只有3个直接子文件夹:东西,文件和资源。

解决方案是在呈现异常时(在文件app / Exceptions / Handler.php中)检查url的第一个段,如果它与3个文件夹中的一个匹配,则返回没有视图的404响应:

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

提前致谢

3 个答案:

答案 0 :(得分:5)

不要通过laravel路由文件请求并在404

上提供空白图像

.htaccess样本:

RewriteEngine On
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png|ico)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .*$ /no_picture.png [L]

您可以在重定向到index.php的规则上面发布此内容

这假设图片是从网站提供的,而不是通过流式数据库内容提供的。

基本上会发生这样的事情:

  • 后端用户上传图片:
  • laravel将图像存储在/some/path/to/store/data/public/12a/4d8/458/12a4d8458.gif
  • laravel将图像存储为数据库中的12a4d8458.gif
  • --------------------时间过去------------------------ < / LI>
  • 访客请求页面。
  • 请求与文件不匹配。重定向到index.php(根据.htaccess)
  • 请求被发送到index.php
  • laravel构建页面。查找图片
  • laravel撰写完整的公共网址路径
  • www.awesome.com/data/public/12a/4d8/458/12a4d8458.gif
  • 组成的html内容被推送给访问者
  • ----------------毫秒传递------------------------
  • 访客请求图片/data/public/12a/4d8/458/12a4d8458.gif
  • 请求匹配文件文件由apache提供
  • laravel仍然幸福地没有意识到请求
  • -----------------不是毫秒已经过了-------------
  • 访客请求图片/data/public/4e8/d44/98f/4e8d4498f.gif
  • 请求与文件不匹配。重定向到index.php(根据.htaccess)
  • laravel构建页面。找不到路线。
  • laravel调用404例程
  • laravel构建包含所有触发器的404页面
  • laravel向用户提供404

因此,您希望在最后一步中执行的操作是通过根据.htaccess规则定义提供您自己的图像来防止图像请求达到laravel。 这样,您的网络服务器就可以更快地对丢失的图像做出响应。

答案 1 :(得分:1)

检查文件扩展名

而不是检查特定路径的网址段,如果你说它只是图像。因此,如果只有具有特定扩展名的东西才需要它,您可以检查它并返回更简单的404响应:)

/* \app\Exceptions\Handler.php */

public function render($request, Exception $exception)
{
    if ($exception instanceof NotFoundHttpException) {
        $ext = pathinfo($request->url(), PATHINFO_EXTENSION);
        if (in_array($ext, ['jpg', 'png'])) {
            return response('Nope');
        }
    }

    return parent::render($request, $exception);
}

缓存

刚刚意识到它提出了很多要求。也许是这样的,将结果缓存1分钟,这应该足够长,以便页面上的下一个404请求获取缓存而不是运行查询:)

public function boot()
{
    // Sidebar
    $sidebarCategories = Cache::store('file')->remember('sidebarCategories', 1, function () {
        $currentCategory = $this->getCurrentCategory();
        return SidebarCategory::category($currentCategory)->order()->get();
    });

    view()->composer('partials.sidebar', function ($view) use ($sidebarCategories) {
        $view->with('sidebarCategories', $sidebarCategories);
    });


    // Footer
    $footerColumns = Cache::store('file')->remember('footerColumns', 1, function () {
        $footerLinks = FooterCategory::with('links.translations')->order()->get();
        return [
            1 => $footerLinks->filter(function ($value, $key) { return $value->column == 1; }),
            2 => $footerLinks->filter(function ($value, $key) { return $value->column == 2; }),
            3 => $footerLinks->filter(function ($value, $key) { return $value->column == 3; }),
            4 => $footerLinks->filter(function ($value, $key) { return $value->column == 4; }),
        ];
    });

    view()->composer('partials.footer', function ($view) use ($footerColumns) {
        $view->with([
            'footerColumn1' => $footerColumns[1],
            'footerColumn2' => $footerColumns[2],
            'footerColumn3' => $footerColumns[3],
            'footerColumn4' => $footerColumns[4],
        ]);
    });
}

答案 2 :(得分:0)

您可以在此处使用配置来解决视图组合的多次查询运行问题。例如显示下面的代码。

公共函数compose(查看$view) {

if(!Config::has('composeVars')) 
{
    Config::set('composeVars') = [
      'data' => User::all();  
    ];
}

$view->with('*', Config::get('composeVars'));

}