如何使用 Laravel 和 Google Analytics 创建热门列表
发布于 作者 Eric L. Barnes
在 Laravel 新闻网站上,我想要生成过去七天中最热门文章的列表,并将结果从最热门到最不热门排序显示。
为了解决这个问题,我想到了两种方案。第一种是自己构建跟踪系统,以便我可以记录访问次数,然后用它进行排序。但是,这可能会产生大量数据,并且看起来像是一个分析跟踪服务可以处理的解决方案。
当我浏览 Google Analytics API 时,我发现 Spatie.be 开发了一个名为 Laravel Analytics 的包,它可以让你轻松地从你的 Google Analytics 帐户中获取数据,并且看起来是解决这个问题的最佳方法。让我们看看我是如何使用它来生成 Laravel 新闻网站上热门文章的列表的。
安装和设置
安装过程与任何 Laravel 包类似,首先通过 Composer 安装包
composer require spatie/laravel-analytics
接下来,将服务提供商添加到 config/app.php
中
'providers' => [ Spatie\Analytics\AnalyticsServiceProvider::class,];
最后,将 Facade 添加到相同的 config/app.php
中
'aliases' => [ 'Analytics' => Spatie\Analytics\AnalyticsFacade::class,];
完成这些设置后,最困难的部分开始了,但这并非包本身的错误。只是 Google 的凭据生成系统非常复杂。最好访问 自述文件中的这一部分,它将带你逐步完成设置过程,并配有截图。
获取最热门的文章
Analytics 包使获取数据变得非常简单,以下是一个示例,展示了如何获取过去七天中最热门页面,并设置限制
$pages = Analytics::fetchMostVisitedPages(Period::days(7), $limit);
然后它返回一个 Laravel 集合,其中包含类似于以下内容的结果
Collection {#400 ▼ #items: array:17 [▼ 0 => array:3 [▼ "url" => "/" "pageTitle" => "Laravel News" "pageViews" => 10 ] 1 => array:3 [▼ "url" => "/" "pageTitle" => "Laravel News - News and information about Laravel" "pageViews" => 9 ] 2 => array:3 [▼ "url" => "/2016/06/look-whats-coming-laravel-5-3/" "pageTitle" => "A look at what’s coming to Laravel 5.3" "pageViews" => 8 ] 3 => array:3 [▼ "url" => "/2016/06/look-whats-coming-laravel-5-3/" "pageTitle" => "A look at what's coming to Laravel 5.3 - Laravel News" "pageViews" => 7 ] 4 => array:3 [▼ "url" => "/2016/08/laravel-5-3-rc1-is-now-released/" "pageTitle" => "Laravel 5.3 RC1 is now released" "pageViews" => 6 ] ]}
如果你注意到,前两个结果是首页,而接下来的两个结果是同一篇文章,它们显示两次的原因是标题不同。一组是在我更改网站标题之前,另一组是在之后。
另一个问题是,我不希望首页出现在列表中。我更希望只显示文章。
让我们在完成集成过程中清理这些结果。
构建包装类
现在我已获取到结果,并且知道需要对其进行解析,所以我决定创建一个类来处理获取和处理过程。
我创建了一个名为 app/Services/Trending.php
的新文件,并用基本的获取代码对其进行了填充
<?php namespace App\Services; use Analytics;use Spatie\Analytics\Period; class Trending{ public function week($limit = 15) { return $this->getResults(7); } protected function getResults($days, $limit=15) { return Analytics::fetchMostVisitedPages(Period::days($days), $limit); }}
现在调用该类应该会得到与之前相同的结果,以下是一个示例调用
$trending = app('App\Services\Trending')->week();
接下来,它需要另一个方法来解析结果。如前所述,它需要移除任何重复项,移除任何不是实际文章的页面,以及移除 Google 报告的标题中的 “ – Laravel 新闻” 后缀。
由于 fetchMostVisitedPages 返回的结果是一个集合,因此我们可以轻松地使用其所有方法,以下展示了该方法的完成代码
protected function parseResults($data){ return $data->reject(function($item){ return $item['url'] == '/' or $item['url'] == '/blog' or starts_with($item['url'], '/category'); })->unique('url')->transform(function($item){ $item['pageTitle'] = str_replace(' - Laravel News', '', $item['pageTitle']); return $item; });}
如果我们逐步执行此方法,它首先会 **拒绝** 任何 url 为 “/”,或 “/blog”,或 url **以** “/category” 开头的项。这些是我三个主要的栏目,它们会生成足够的流量,并可能出现在列表中。
接下来,它调用 ->unique('url')
来防止任何重复的 url 传递。
最后,它调用 ->transform()
来移除 “ – Laravel 新闻” 后缀。
接下来,修改 getResults
以使用解析器
protected function getResults($days, $limit=15){ $data = Analytics::fetchMostVisitedPages(Period::days($days), $limit); return $this->parseResults($data);}
现在,如果我们再次运行它,所有返回的数据都应该是正确的
Collection {#396 ▼ #items: array:11 [▼ 2 => array:3 [▼ "url" => "/2016/06/look-whats-coming-laravel-5-3/" "pageTitle" => "A look at what’s coming to Laravel 5.3" "pageViews" => 10 ] 4 => array:3 [▼ "url" => "/2016/08/laravel-5-3-rc1-is-now-released/" "pageTitle" => "Laravel 5.3 RC1 is now released" "pageViews" => 9 ] 5 => array:3 [▼ "url" => "/2016/07/laravel-5-3-recap/" "pageTitle" => "Laracon: Laravel 5.3 Recap" "pageViews" => 8 ] 6 => array:3 [▶] 7 => array:3 [▶] 8 => array:3 [▶] 9 => array:3 [▶] 12 => array:3 [▶] 13 => array:3 [▶] 14 => array:3 [▶] 15 => array:3 [▶] ]}
它似乎正常工作,但请注意,我们想要 15 个项目,但结果只有 11 个。这是因为我们最初获取了 15 个热门项目,然后拒绝了任何重复项。这导致我们获得的项目少于我们想要的 15 个。
我想到的解决方案是请求比我们需要更多的数据,然后 **截取** 我们真正需要的数量。首先,将 getResults 修改为获取比需要更多的数据
protected function getResults($days, $limit=15){ $data = Analytics::fetchMostVisitedPages(Period::days($days), $limit + 10); return $this->parseResults($data, $limit);}
请注意,它不再将限制传递给 fetchMostVisitedPages,而是添加了 10 个。这样,我们就有了额外项目的缓冲区。
接下来,修改 parseResults 在所有解析操作完成后 **截取** 限制
protected function parseResults($data, $limit){ return $data->reject(function($item){ return $item['url'] == '/' or $item['url'] == '/blog' or starts_with($item['url'], '/category'); })->unique('url')->transform(function($item){ $item['pageTitle'] = str_replace(' - Laravel News', '', $item['pageTitle']); return $item; })->splice(0, $limit);}
现在,它会返回正确的结果
Collection {#353 ▼ #items: array:15 [▶]}
所有这些都正常工作后,是时候将它实现到视图中,我相信这将是视图组合器的一个很好的用例。
创建视图组合器
如果你不熟悉视图组合器,以下是如何根据文档描述它们
视图组合器是回调函数或类方法,它们在渲染视图时被调用。如果你想将某些数据绑定到每个渲染的视图,视图组合器可以帮助你将这些逻辑组织到一个单独的位置。
由于这些数据只会在侧边栏中显示,并且可以从任何控制器调用,因此它非常适合作为视图组合器。
要设置这个视图组合器,创建 app/Http/ViewComposers/PopularityComposer.php
并添加以下类
<?php namespace App\Http\ViewComposers; use App\Services\Trending;use Illuminate\View\View; class PopularityComposer{ private $trending; public function __construct(Trending $trending) { $this->trending = $trending; } public function compose(View $view) { $view->with('popular', $this->trending->week()); }}
这将我们的之前定义的 Trending
类设置为依赖项,然后在 compose
方法中添加一个名为 “popular” 的视图变量,它将保存我们的结果集合。
接下来,打开 app/Providers/ComposerServiceProvider.php
并注册我们新创建的组合器
view()->composer( 'sidebar', PopularityComposer::class);
这将注册我们刚刚创建的 PopularityComposer 类到侧边栏视图。
将列表添加到视图
最后一步是将实际的列表添加到侧边栏。创建 resources/views/sidebar.blade.php
并添加一个简单的列表,如下所示
<ol> @foreach ($popular as $post) <li><a href="{{ $post['url'] }}">{{ $post['pageTitle'] }}</a></li> @endforeach</ol>
就这样。你现在应该在侧边栏中看到一个漂亮的最热门文章列表。
总结
如你所见,通过使用社区包、Laravel 集合和视图组合器,我能够快速轻松地设置一个最热门文章列表。