Laravel: Tracking page views - php

I'm trying to implement a very simple page tracking system with Laravel, just to know which pages are most accessed.
At first I thought of create a table with access date, request URL (from Request::path()) and user id, as simple as that.
But I'd have to show page titles on reports, and for that I need some way to translate the request URI to its page title. Any ideas for that? Is there a better way to accomplish this?
Currently I set page titles from Blade view files, through #section('title', ...).
Thank you in advance!

You can use Google Analytics to show pretty and very efficient reports. With the API, you can also customize the reports and (for example) show the pages titles.
If you want to develop it by yourself, I think that the best solution is to write an after filter that can be called after each page loading. One way of setting the title, in this case, is to use flash session variable (http://laravel.com/docs/session#flash-data) :
// routes.php
Route::group(array('after' => 'log'), function()
{
Route::get('users', 'UserController#index');
}
// filters.php
Route::filter('log', function() {
Log::create(array('title' => Session::get('title'), '...' => '...'));
}
// UserController.php
public function index()
{
Session::flash('title', 'Users Page');
// ...
}
// layout.blade.php
<head>
<title>{{ Session::get('title') }}</title>
...

I know this has already been answered but I would like to add that I've published a package that can be easily implemented to track page views for Laravel (if they are Eloquent ORM instances) in specific date ranges: last day, week, month or all time.
https://github.com/marcanuy/popularity

Related

How do I effectively record page views on php [ laravel ]

Good day,
I am trying to record page views/visit on my page..
currently I added a helper function on my controller
my helper function:
function record_user_click($type=null,$item_id=null)
{
$referer = (array_key_exists('HTTP_REFERER',$_SERVER)) ? $_SERVER['HTTP_REFERER']:'direct_access';
\DB::table('click_statistics')->insert([
['user_id' => Auth::id(),'type'=>$type,'item_id'=>$item_id,'referer'=>$referer]
]);
}
and on my product controller I the helper function:
public function product_view($id){
record_user_click('product',$id);
-- controller codes here
}
this function records every visit/view but if I refresh the page fast, it also records them, which will add to its view statistics on the table.
my question is, how can I possibly make it more reliable something like stackoverflow's views function.
If you want to register to browse pages when it is fully loaded, you need to do this using javascript. Wait for fully loaded pages and send ajax with data to your backend portion and then register the user

Making sub category in laravel website

so i want to expand my site to have like region site, so when user open my site it will be ask to select which region he/she interested into and lets just say he interesting in London, then the site will generate a webpage that already all content related to that region...
i tried to just do the same way i create administrator page by group them in this route
Route::group(array('prefix'=>'admins','before' => 'auth'),function(){
Route::resource('partner','AdminPartnerController',array('except' => array('show')));
Route::get('partner/index_kategori/{id}',array(
'as' => 'admins.partner.index_kategori',
'uses' => 'AdminPartnerController#index_kategori'
});
but it's mean that i need to create a different controller function for each region i gonna create, so it's not very efficient.
what comes to my mind is just like making
www.websiteadress.com/region
so how i can catch that "/region" and add that value into each my function in controller? how to build that kind of routes?
update:
to make it more easily to understand, what become my problem is like i have this normal route:
Route::get('product/{id}',array( 'as' => 'product','uses' => 'PublicController#product'));
what this route do is pretty straight foward, when i type
www.websiteadress.com/product/12
it will open the product page for number 12, so my problem is if i add like this
www.websiteadress.com/Asia/product/12
how i make my PublicController to catch Asia and later in my product function i will just process that..?
Of course you don't need to create controller for each region. You want to use simple route with a variable:
Route::get('region/{region}', 'RegionController#show');
And just one controller for all regions:
public function show ($region)
{
// Logic here
return view('region.show', compact(['region']));
}
So, when user will load http://example.com/region/London, show action will have London in $region variable.
so after searching for days and asking around, i finally getting the best solution to answer my own question and i willing to share it to here, so someday maybe there is other people who want to do what want to...
so first in the route just create like this
Route::group(['prefix' => '{region}'], function(){
Route::get('member',array('as' => 'member','uses' => 'PublicController#member'));
});
and what this route do is just group it into prefix with value is in region variable and then i set the get route to where the controller will use to show the page and also taking region value into use
and then in my PublicController
public function sitemap($region){
if($region =='london'){
//do something
}else{
//do something
}
}
and so there it is.. i can get those region value from prefix and use it. in my case i use it to show certain page with different content.

Hiding View in a Route Group in Laravel

I have a Route Group
Route::group(['middleware' => ['auth','use.ssl']], function () {
})
This Route Group is Order Process in E-Commerce Project. I want to learn that can i hide a view in this Route Group ?
I want to disable header messages for visitor in this pages of this group.
It might works if you do something like that inside a middleware
View::composer('*', function($view) {
$view->with('group', true);
});
Then in your views you can test if $group exists and is true.
I feel i couldn't find best solution. But i solved problem in a different way.
view()->share('orderProcess', FALSE);
with this code i'm sharing $orderProcess variable with all views.
#if(!$orderProcess)
//A part of my view
#endif
This code will show the part of my view when $orderProcess if FALSE. Now in every page i'm showing my view.
In order process cart, orderAddress, orderPayment, orderResult i'm sending (orderProcess, TRUE) value to view. And it removes the part of my view.
This works but i want find better solutions.

Dynamic Routing in Laravel 5 Application

I am hoping that someone can help me out with dynamic routing for urls that can have multiple segments. I've been doing some searching all over the web, but nothing I find helps me out with my specific situation.
A little background ... several years ago, I developed a CMS package for custom client websites that was built on CodeIgniter. This CMS package has several modules (Pages, Blog, Calendar, Inquiries, etc). For the Pages module, I was caching the routes to a "custom routes" config file that associated the full route for the page (including parent, grandparent, etc) with the ID of the page. I did this so that I didn't have to do a database lookup to find the page to display.
I am currently working on rebuilding this CMS package using Laravel (5.1) [while I'm learning Laravel]. I need to figure out the routing situation before I can move on with my Pages module in the new version of the package.
I know that I can do something like ...
// routes.php
Route::get('{slug}', ['uses' => 'PageController#view']);
// PageController.php
class PageController extends Controller
{
public function view($slug)
{
// do a query to get the page by the slug
// display the view
}
}
And this would work if I didn't allow nested pages, but I do. And I only enforce uniqueness of the slug based on the parent. So there could be more than one page with a slug of fargo ...
locations/fargo
staff/fargo
As with the package that I built using CodeIgniter, I would like to be able to avoid extra database lookups to find the correct page to display.
My initial thought was to create a config file that would have the dynamic routes like I did with the old version of the system. The routes will only change at specific times (when page is created, when slug is modified, when parent is changed), so "caching" them would work great. But I'm still new to Laravel, so I'm not sure what the best way to go about this would be.
I did manage to figure out that the following routes work. But is this the best way to set this up?
Route::get('about/foobar', function(){
return App::make('\App\Http\Controllers\PageController')->callAction('view', [123]);
});
Route::get('foobar', function(){
return App::make('\App\Http\Controllers\PageController')->callAction('view', [345]);
});
Basically, I would like to bind a specific route to a specific page ID when the page is created (or when the slug or parent are changed).
Am I just overcomplicating things?
Any help or direction regarding this would be greatly appreciated.
Thanks!
The way I handle this is to use two routes, one for the home page (which generally contains more complex logic like news, pick up articles, banners, etc), and a catch all for any other page.
Routes
// Home page
Route::get('/', [
'as' => 'home',
'uses' => 'PageController#index'
]);
// Catch all page controller (place at the very bottom)
Route::get('{slug}', [
'uses' => 'PageController#getPage'
])->where('slug', '([A-Za-z0-9\-\/]+)');
The important part to note in the above is the ->where() method chained on the end of the route. This allows you to declare regex pattern matching for the route parameters. In this case I am allowing alphanumeric characters, hyphens and forward slashes for the {slug} parameter.
This will match slugs like
test-page
test-page/sub-page
another-page/sub-page
PageController Methods
public function index()
{
$page = Page::where('route', '/')->where('active', 1)->first();
return view($page->template)
->with('page', $page);
}
public function getPage($slug = null)
{
$page = Page::where('route', $slug)->where('active', 1);
$page = $page->firstOrFail();
return view($page->template)->with('page', $page);
}
I keep the template file information in the database, as I allow users to create templates in the content management system.
The response from the query on the database is then passed to the view where it can be output to the metadata, page, breadcrumbs, etc.
I was also looking for the same answer that is about creating a dynamic routing in laravel i come up with this:
In routes.php
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
$str=Request::url();
$del="/public/";
$pos=strpos($str, $del);
$important1=substr($str, $pos+strlen($del), strlen($str)-1);
$important=ucfirst($important1);
$asif=explode("/", $important);
$asif1=explode("/", $important1);
//echo $important;
$post=$asif1[0];
$post1=$asif1[1];
if(isset($asif1[2]))
{
$post2=$asif1[2];
}
if(!(isset($post2)))
{
Route::match(array('GET','POST'),$important1, $asif[0].'Controller#'.$asif[1]);
}
if(isset($post2))
{ Route::match(array('GET','POST'),$post.'/'.$post1.'/{id}',$asif[0].'Controller#'.$asif[1]);
}
Route::get('/', function () {
return view('welcome');
});
Ex
if you have PostController with method hello in laravel. You can use this url http://localhost/shortproject/public/post/hello. Where shortproject is your project folder name.

Laravel - set variable globally

I have a few vars in my app that I would like to share through multiple views and requests. Basically I have a custom Layout which I load like that:
#section('stylesheet')
{{ HTML::style(URL::to('custom_stylesheet/'.$slug)) }}
#stop
I somehow have to send the "slug" var to every request and action and/or controller I need and I need a few. It's a shop from a startpage to checkout, last step.
How can I achieve that? Is View::share() a solution or a cookie?
The URL structure is like that:
www.domain.tld/name/{client_slug}/{event_slug}/<all other variables>
like /overview or /checkout or /details/{event_id}
Thanks!
If you need to specify views, use a View Composer:
View::composer(['view-a', 'view-b'], function($view)
{
$client_slug = 'whatever you need to do to calculate the slug';
$view->with('client_slug', $client_slug);
$view->with('event_slug', $event_slug);
$view->with('variable1', $variable1);
});
Or, as you said, View Share to share with all of them:
View::share('client_slug', $client_slug);
You can create a file for this purpose, something like app/composers.php and load it in your app/start/global.php:
require app_path().'/composers.php';
And you can consider using Session vars too, which keeps data through multiple requests:
Session::put('client_slug', $client_slug);
And get it with
$client slug = Session::put('client_slug');
But if this is a View thing only, View Composers are the way to go.
Using Session and View Composer them togheter is simple, you can set in one request:
Session::put('client_slug', $client_slug);
And in the next request you can send it to your views:
View::composer(['view-a', 'view-b'], function($view)
{
if (Session::has('client_slug'))
{
$view->with('client_slug', Session::get('client_slug'));
}
else
{
$view->with('client_slug', 'default-slug-or-whatever-you-would-do');
}
});
I'm pretty sure you can do this:
if (Cache::has('slug'))
{
View::share('slug', Cache::get('slug'););
}
Then just place that in your route file, or perhaps your base controller constructor, where ever you want it.
Then when you first get given the slug:
Cache::put('slug', $slug, 60); //60 minutes

Categories