Laravel 4.2 Page Views Counter - laravel

So i added this page view counter to my app that counts each visit on a artist page. Right now if you refresh the page the counter is +1 each refresh.
My question is how can i make it to count unique visits by day only?
My Controller:
if ( $artist ) {
$getartist = $this->_artist->get($artist, 'slug');
if ( $getartist ) {
$getsongs = $this->_song->collections($input, $getartist->id, 'ASC');
$this->_artist->updateVisits($getartist->id);
$data = [
'is_artist' => true,
'artist' => $getartist,
'songs' => $getsongs,
'randomsongs' => $this->randomsongs,
];
return $this->view('index', $data);
}
}
The code for counter is:
$this->_artist->updateVisits($getartist->id);
Then in my ArtistRepository:
public function updateVisits($artist_id)
{
$artist = $this->model->where("id",$artist_id)->first();
$artist->visits = $artist->visits+1;
$artist->save();
}
So how do i prevent counter from counting if user refresh the page?

Ok i found a solution around this with cookies
Heres my code.
public function updateVisits($artist_id)
{
$artist = $this->model->where("id",$artist_id)->first();
// Check if cookies exist
if(!isset($_COOKIE['visited_id' . $artist_id])) {
// If not set cookie and pass counter
setcookie('visited_id' . $artist_id, $artist_id, time()+30); /* expire in seconds */
$artist->visits = $artist->visits+1;
$artist->save();
// If cookie exist on user computer
} else {
//do nothing
}
}

First add a date field on DB table. Then change your function to following-
public function updateVisits($artist_id)
{
$artist = $this->model->firstOrCreate(['id' => $artist_id,'your_date_field_name'=>date('Y-m-d')]);
$artist->visits = $artist->visits+1;
$artist->save();
}
And don't forget to add id, your_date_field_name on fillable array to be mass assignable.

Related

Stuck at Error = Method Illuminate\Database\Eloquent\Collection::save does not exist

Trying to save data while open page but stuck at error :
"Method Illuminate\Database\Eloquent\Collection::save does not exist."
I have 2 database :
Buffalodata
Buffalomilkrecord
From 2nd table i need to get the avg of totalmilk and update the same to main database (1). This help me to show updated avgmilk data on dashboard front page.
Route:
Route:: get('buffalo-details', 'App\Http\Controllers\BuffalodataController#buffalodetails');
BuffalodataController Controller :
public function buffalodetails()
{
$buffalidforavgmilk = Buffalodata::groupBy('buffaloID')->get('buffaloID')->pluck('buffaloID')->toArray();
foreach ($buffalidforavgmilk as $id )
{
$milkperid = Buffalomilkrecord::where('buffaloID', $id)->sum('totalmilk');
$avgbuffalocount = Buffalomilkrecord::where('buffaloID',$id)->count();
$getavg = $milkperid / $avgbuffalocount;
$data = Buffalodata::find($buffalidforavgmilk);
$data->avgmilk = ($getavg);
$data->save ();
// dump([$milkperid,$avgbuffalocount,$getavg,$data,$id]);
}
return view ('pages.Buffalo.BuffaloDetails',[---------]);
}
Thanks again in Advance
When you pass an Array to ::find(), it returns a Collection, which doesn't have a save() method. This is your code:
// This is an Array of `buffaloID` values
$buffalidforavgmilk = Buffalodata::groupBy('buffaloID')->get('buffaloID')->pluck('buffaloID')->toArray();
...
// `$data` is now a `Collection` of `Buffalodata` instances
$data = Buffalodata::find($buffalidforavgmilk);
// This now fails, as `Collection` doesn't have a `save()` method
$data->save();
You can rewrite your code as follows:
Buffalodata::whereIn('buffaloID', $buffalidforavgmilk)->update(['avgmilk' => $getavg]);
This will update all records in a single call. If you want to iterate, that's an option too:
$data = Buffalodata::find($buffalidforavgmilk);
foreach ($data as $record) {
$record->avgmilk = $getavg;
$record->save();
}
Or, since you have $id already:
$record = Buffalodata::find($id);
$record->avgmilk = $getavg;
$record->save();

Using middleware in laravel to determine page visits

Public function handle($request, Closure $next)
{
$count = 0;
$time = now();
$visitor = "Someone";
if (request("visitor") == "Someone" && $count == 0) {
$count++;
\Mail::raw('You have a new page visit at ' . $time ' ' . $count . '', function ($note) {
$note->to('manager#mail.com');
});
return $next($request);
} else {
return abort (404);
}
This code is just a simple middleware to check a page visit in laravel. It‘a working fine and I’m receiving the email via log. However, the count is just 1 on every page hit. It doesn’t increase to 2, 3......
I really need help to be able to count the page hits regardless of who or what visits, even regardless of IP. Plus how do I fetch the counts to a view and also save it in the database. I really need help as I’m still a learner. Please help!
I did something similar once to this, but for the system's issues encountered by users. Since you want to measure traffic (using the database), the scenario is kinda similar. Let's say you have a table called traffic, so the logic in regards that traffic would be placed in the handle function at the middleware as you have but measuring traffic like this:
public function handle($request, Closure $next)
{
$time = now(); // #Todo: check timezone in the config/app.php
$visitor = $request->ip();
$traffic = Traffic::where('visitor', $visitor)->first();
if ($traffic) {
// Resident visitor
$traffic->visits++;
$traffic->update();
} else {
// New visitor
$traffic = new Traffic(['visitor' => $visitor]);
$traffic->save();
$totalTraffic = Traffic::all()->sum('visits');
$totalVisitors = Traffic::all()->count();
// Email notification
\Mail::raw("There is a new visitor at {$time} from ip {$visitor}.\nIn total there are {$totalVisitors} visitors, and over all you have {$totalTraffic} visits.", function ($note) {
$note->to('manager#mail.com');
});
}
return $next($request);
}
Keep in mind you can improve this solution by moving the traffic logic into the Traffic model by implementing a boot function inside the model, that would look cleaner. More info https://laravel.com/docs/7.x/eloquent#observers
Sorry I got late, hope it helps though...
Solution 2:
You could also create a migration or run the following statement in your database, setting a default column for visits as 1, since it won't change every time a new one is created.
ALTER TABLE traffic ALTER visits SET DEFAULT 1;
Traffic Model:
class Traffic extends Model
{
protected $fillable = ['visitor' , 'visits'];
protected static function boot()
{
parent::boot();
static::saving(function ($traffic) {
if ($traffic->visits) {
$traffic->visits++;
}
});
}
}
TrafficMiddleware:
public function handle($request, Closure $next)
{
$time = now();
$visitor = $request->ip();
$traffic = Traffic::firstOrCreate(['visitor' => $visitor]);
$traffic->save();
//Email notification
$totalTraffic = Traffic::all()->sum('visits');
$totalVisitors = Traffic::all()->count();
\Mail::raw("New visit at {$time} from {$visitor}. You have over all {$totalTraffic} visits from {$totalVisitors} visitors.", function ($note) {
$note->to('manager#mail.com');
});
return $next($request);
}
First, if you redeclare $count every time, it will never increase.
Second, you're checking if $count is equal to 0 before sending the message, so even if it did increase, you would not send the mail next time.
One way to persist the count value would be using cache.
public function handle($request, Closure $next)
{
// retrieve cached value for 'page_visits'. If it doesn't exist, return 0 instead
$count = cache('page_visits', 1);
$visitor = request()->ip();
$time = now();
\Mail::raw("You have a new page visit at {$time->isoFormat('LLLL')} from {$visitor}. Total: {$count}", function ($note) {
$note->to('manager#mail.com');
});
cache()->put('page_visits', ++$count);
return $next($request);
}

Laravel foreach only getting first value

I am doing a peer marking system which requires a function that lecturer adds id list and when students enroll in a course, he enters his id needed to match the id on lecturer id list.
Controller
public function store(Request $request)
{
$this->validate($request, [
'course_code' => 'required',
'studentid' => 'required'
]);
$enrollment = new Enrollment;
$enrollment->user_id = auth()->user()->id;
$enrollment->course_id = $request->course;
$enrollment->user_StudentID = $request->studentid;
$input_course_id = $request->input('course_code');
$input_studentid = $request->input('studentid');
$course = Course::find($enrollment->course_id);
$course_identifiers = $course->identifiers;
// Need all the data in the database course table for comparison
//$course represents the contents of the course table in all databases, then you need to loop first, then judge
//$course stands for list $signleCourse for each piece of data
foreach ($course_identifiers as $course_identifier) {
// if ($course_identifier->studentid == $input_studentid )
if ($input_studentid == $course_identifier->studentid) {
if ($request->course == $input_course_id) {
//if true,save and redirect
$enrollment->save();
return redirect('/enrollment')->with('success', 'Course Enrolled');
} else {
return redirect('/enrollment')->with('error', 'Please Enter Correct Confirmation Code');
//If false do nothing
}
} else {
return redirect('/enrollment')->with('error', 'Please Enter Correct Student ID');
//If false do nothing
}
}
}
It can only match the first value, but other values I enter cannot be recognized.
Turn off your redirects. It's really hard to understand the context of that code but it looks like if it fails to match it redirects so doesn't go through the second and subsequent values of $course_identifiers.

Laravel route : any slug takes all the requests

I have a route something like this. The $slug is a variable that is matched to the slugs stored in the database to add the pages dynamically to the website.
#slug variable for different values of page slug....
Route::get('/{slug?}', array(
'as' => 'page',
'uses' => 'AbcController#renderPage'
));
However, now I wish to add an admin side of the website and want routes to be prefixed with media-manager.
My problem is, whenever I make a call to another route in the file, the above mentioned route takes the request call and calls the renderPage method every time, no matter wherever the request is coming from.
This is my middleware where I check for whether request is coming from a URL like 'media-manager/*', if so I don't want to check for the language of the website and redirect it to the media-manager's page.
private $openRoute = ['media-manager/login', 'media-manager/postLogin', 'media-manager/media'];
public function handle($request, Closure $next)
{
foreach ($this->openRoute as $route) {
if ($request->is($route)) {
return $next($request);
}
}
// Make sure current locale exists.
$lang = $request->segment(1);
if(!isValidLang($lang)) {
$lang = getDefaultLang();
$segments = $request->segments();
array_unshift($segments, $lang);
$newUrl = implode('/', $segments);
if (array_key_exists('QUERY_STRING', $_SERVER))
$newUrl .= '?'.$_SERVER['QUERY_STRING'];
return $this->redirector->to($newUrl);
}
setLang($lang);
return $next($request);
}
This is the renderPage method where every time the request is being redirected, no matter what.
public function renderPage($slug = '')
{
if ($slug == 'login') {
return view ('site.login');
}
$page = Page::getBySlug($slug);
if(empty($page)){
return URL::to ('/');
}
if($slug == ''){//home page
$testimonial = DB::table('testimonial')->where('lang','=',$this->lang)->get();
$client_logo = DB::table('client_logo')->get();
return View::make('index', compact('data','page', 'testimonial', 'client_logo'));
}elseif($slug == 'services'){
return View::make('services', compact('page'));
}elseif($slug == 'portfolio'){
$categories = PortfolioCategory::getAll();
$portfolio = Portfolio::getAll();
return View::make('portfolio', compact('page', 'categories', 'portfolio'));
}elseif($slug == 'oshara'){
return View::make('oshara', compact('page'));
}elseif($slug == 'blog'){
$limit = 8;
$pageNum = 1;
$offset = ($pageNum-1)*$limit;
$totalPosts = BlogPost::totalPosts();
$totalPages = ceil($totalPosts/$limit);
$posts = BlogPost::getAll($offset, $limit);
$blog_posts = View::make('partials.blog_posts', compact('posts','pageNum','totalPages'));
return View::make('blog', compact('page', 'blog_posts', 'pageNum', 'totalPages'));
}elseif($slug == 'contact'){
$budgets = Budget::getAll();
return View::make('contact', compact('page', 'budgets'));
}
}
This is postLogin method in the controller that I want to call after user clicks on Login button on login page.
public function postLogin($request) {
# code...
//$request = $this->request;
$this->validate($request, [
'email1' => 'required|email',
'password' => 'required|string'
]);
if($user = User::whereEmail($request->email1)->first() ) {
if(Hash::check($request['password'], $user->getAttributes()['password'])) {
if(!$user->getAttributes()['is_active']) {
return redirect('/media-manager/login')->withErrors('Your Account is not Activated Yet!');
} else if($user->getAttributes()['is_deleted']) {
return redirect('/media-manager/login')->withErrors('Your Account is Banned!');
} else {
# Success
$cookie = Cookie::make('user_id', $user->getAttributes()['id'], 864000);
//echo "hello";
return view('site.media')->with('message', 'You have Successfully Logged In!')->withCookie($cookie);
}
} else {
return redirect('/media-manager/login')->withErrors('Your Login Information is Wrong!');
}
} else {
return redirect('/media-manager/login')->withErrors('Your Login Information is Wrong!');
}
}
Can any one please suggest me some way so that I can disable renderPage method on every call and have my normal routing perform perfectly.
In Laravel the first matching route is used. So I would guess you have your slug route defined above the others (at least above the media-manager ones), right?
So a simple solution would be to just put the slug route definition at the end of your routing file.
Another approach would be utilize conditions for the route. For more information you can read this or leave a comment!
Hope that helps!

CodeIgniter Unset A Signle Session Item In An Multidimensional Array

On my User.php library in my login function I create admin sessions by
$create_session = array(
'is_logged' => true,
'user_id' => $row->user_id
);
$this->CI->session->set_userdata('admin', $create_session);
The issue is when I try to unset admin session data individually it does not unset the session I select.
Var Dump:
Array
(
[__ci_last_regenerate] => 1449906266
[admin] => Array
(
[is_logged] => 1
[user_id] => 1
)
)
Logout function on library:
Does not Unset: Preferred Way
public function logout() {
$user_data = $this->CI->session->userdata('admin');
unset($user_data['is_logged']);
unset($user_data['user_id']);
}
But when I use this way below it works
public function logout() {
$this->CI->session->unset_userdata('admin');
}
For some reason will not let me unset session data individually from an array in sessions.
Question How am I able to unset codeigniter session data individually that are in my admin session array?
Full User.php library
<?php
class User {
private $user_id;
private $username;
public function __construct() {
$this->CI =& get_instance();
$this->CI->load->library('session');
}
public function login() {
if ($this->validate_password() == true) {
$this->CI->db->select('*');
$this->CI->db->from($this->CI->db->dbprefix . 'user');
$this->CI->db->where('username', $this->CI->input->post('username'));
$query = $this->CI->db->get();
if ($query->num_rows() > 0) {
$row = $query->row();
$create_session = array(
'is_logged' => true,
'user_id' => $row->user_id
);
$this->CI->session->set_userdata('admin', $create_session);
$this->user_id = $row->user_id;
$this->user_group_id = $row->user_group_id;
$this->username = $row->username;
return true;
} else {
return false;
}
}
}
public function is_logged() {
$get_session = $this->CI->session->userdata('admin');
return $get_session['is_logged'];
}
public function logout() {
$user_data = $this->CI->session->userdata('admin');
unset($user_data['is_logged']);
unset($user_data['user_id']);
}
public function validate_password() {
if (password_verify($this->CI->input->post('password'), $this->stored_hash())) {
return true;
} else {
return false;
}
}
public function stored_hash() {
$this->CI->db->where('username', $this->CI->input->post('username'));
$query = $this->CI->db->get($this->CI->db->dbprefix . 'user');
if ($query->num_rows() > 0) {
$row = $query->row();
return $row->password;
} else {
return FALSE;
}
}
}
Note:
I have two lots of sessions one admin for back end and catalog for front end that's why in array.
Using unset() by itself will not remove the values from the CodeIgniter session. You would need to save those changes to the session using $this->CI->session->userdata('admin', $user_data) again.
For example:
<?php
$user_data = $this->CI->session->userdata('admin');
print_r($user_data);
// Shows: Array ( [is_logged] => 1 [user_id] => 123 )
unset($user_data['is_logged']);
unset($user_data['user_id']);
print_r($user_data);
// Shows: Array ( )
// Check what values are saved in the session:
print_r($this->CI->session->userdata('admin'));
// Shows: Array ( [is_logged] => 1 [user_id] => 123 )
// Save your changes to the session
$this->CI->session->set_userdata('admin', $user_data);
// Check what values are saved in the session (now that we've updated the session)
print_r($this->CI->session->userdata('admin'));
// Shows: Array ( )
So, you need to do the following steps to update arrays stored in your session:
Get values from session: $arr = userdata('userdata')
Remove value(s) from array: unset($arr['key'])
Save changes to session: set_userdata('userdata', $arr)
As a workaround, you may be able to edit the $_SESSION directly, bypassing the CodeIgniter's Session library:
unset($_SESSION['admin']['is_logged']);
unset($_SESSION['admin']['user_id']);
I wouldn't advise bypassing the Session library like this, but it might suit your purposes more than the steps I've listed above.
Thanks to #Kirk Beard for advice I have found way to use CodeIgniter session and unset individually data that is in side my admin array();
I create the admin multidimensional array session
$create_session = array(
'is_logged' => true,
'other_item' => 'something'
);
$this->session->set_userdata('admin', $create_session);
Then if you need to unset a single item in the admin array.
unset($this->session->userdata['admin']['is_logged']);
Works for me.
To get multidimensional array session.
echo $this->session->userdata['admin']['is_logged'];
Or
$userdata = $this->session->userdata('admin');
echo $userdata['user_id'];
Generate sessions as $this->CI->session->set_userdata($create_session); instead of $this->CI->session->set_userdata('admin',$create_session);
such as
$create_session = array(
'is_logged' => true,
'user_id' => $row->user_id
);
$this->CI->session->set_userdata($create_session);
Now unset by name even individually
$this->CI->session->unset_userdata('is_logged');
$this->CI->session->unset_userdata('user_id');

Resources