Running into a problem here and been trying to find a solution for days now.
I want to be able to count the number of Online users in my Laravel application.
I already have build in a system for showing the online and offline user status in my application in the admin panel.
However i am trying to get a counter to just show the numerical value of online users.
Under is the code i used for showing the online offline status.
But now im trying to call while using the count(Cache::has('user-is-online')
However i cant get it working.
Hope somebody can help the way i can call this.
For what i did manage to build i used the following:
Created middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
use Cache;
use Carbon\Carbon;
class LastUserActivity
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check()) {
$expiresAt = Carbon::now()->addMinutes(1);
Cache::put('user-is-online-' . Auth::user()->id, true, $expiresAt);
}
return $next($request);
}
}
Created controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use DB;
use Cache;
class UserController extends Controller
{
/**
* Show user online status.
*
*/
public function userOnlineStatus()
{
$users = DB::table('users')->get();
foreach ($users as $user) {
if (Cache::has('user-is-online-' . $user->id))
echo "User " . $user->name . " is online.";
else
echo "User " . $user->name . " is offline.";
}
}
}
Created route:
Route::get('/check', 'StatusController#userOnlineStatus');
And i call it with:
<td>
#if(Cache::has('user-is-online-' . $user->id))
<span class="badge badge-warning rounded-0 w-100">Online</span>
#else
<span class="badge badge-danger rounded-0 w-100">Offline</span>
#endif
</td>
Because you've unique key for the each user in the cache. You can't find it by partial key in your case. You can keep a counter like you're doing in the userOnlineStatus function and print the results after that. Look below.
/**
* Show number of online users.
*
*/
public function numberOfOnlineUsers()
{
$users = DB::table('users')->get();
$counter = 0;
foreach ($users as $user) {
if (Cache::has('user-is-online-' . $user->id)) {
$counter++;
}
}
//Passing $counter to the view
return view("your_blade_file_name", ['counter' => $counter]);
}
To access in blade file
The number of online users are {{ $counter }}
I have a module in my Laravel app (it could also be a composer package).
This module has a view composer which sets an array to all views containing the routes which should be included in the main navigation of the app.
The composer looks like this:
class ContactNavigationComposer
{
/**
* Bind data to the view.
*
* #param \Illuminate\View\View $view
* #return void
*/
public function compose(View $view)
{
$view->with('contactNavigation', config('contact.navigation'));
}
}
Then in the mainNav of the app this variable $contactNavigation becomes iterated to generate the entries:
<ul>
# ...
<li>
<a
class="{{ (request()->is('navigations/areas')) ? 'active' : '' }}"
href="{{ route('areas.index') }}">
Navigation Areas
</a>
</li>
<li>
<a
class="{{ (request()->is('languages')) ? 'active' : '' }}"
href="{{ route('languages.index') }}">
Languages
</a>
</li>
#foreach($contactNavigation as $text => $url)
<li>
<a
class="{{ (request()->is($url)) ? 'active' : '' }}"
href="{{ $url }}">
{{ $text }}
</a>
</li>
#endforeach
</ul>
This works perfectly fine but I was wondering if I can have this behavior in a more dynamic way and let composers of different modules using the same array e.g. $modules which contains navigation entries (and other stuff) of different modules.
This way I wouldn't have to add module extensions to the applications views later on.
So my suggested solution would be smth. like that:
class ContactNavigationComposer
{
/**
* Bind data to the view.
*
* #param \Illuminate\View\View $view
* #return void
*/
public function compose(View $view)
{
$view->with('modules.navigation.contact', config('contact.navigation'));
}
}
<ul>
# ...
#if (isset($modules['navigation']))
#foreach($modules['navigation'] as $moduleNavigation)
#foreach($moduleNavigation as $text => $url)
<li>
<a
class="{{ (request()->is($url)) ? 'active' : '' }}"
href="{{ $url }}">
{{ $text }}
</a>
</li>
#endforeach
#endforeach
#endif
</ul>
Of course with the dot-notation, this modules.navigation.contact-key is never translated into a view variable especially not as an array.
Is there any way to achieve something like that?
For those who came across this issue as well:
I changed my compose method to this
// ViewComposer
class ContactNavigationComposer extends BaseComposer
{
public function compose(View $view)
{
$moduleDataBag = $this->getModuleDataBag($view);
$moduleData = $moduleDataBag->mergeRecursive([
'contact' => [
'navigation' => config('contact.navigation.entries')
]
]);
$view->with('modules', $moduleData);
}
}
The getModuleDataBag-method comes from the BaseComposer-class from which each ViewComposer inherits from.
class BaseComposer
{
protected function getModuleDataBag(View $view)
{
if (!array_key_exists(config('contact.view.dataKey'), $view->gatherData())) {
ViewFacade::share(config('contact.view.dataKey'), collect([]));
}
return $view->gatherData()[config('contact.view.dataKey')];
}
}
The key in which all the configuration is stored is defined in the (publishable) config. This way this setup is flexible for modifications by the surrounding application.
(The package is called contact, that's why the view data key is in the contact-config.)
If the expected key is not found, the BaseComposer sets it to all views using the ::share-method on the View-facade as an empty collection.
Each ViewComposer always call the getModuleDataBag-method first to receive the current data probably already set by other ViewComposers.
As this $moduleDataBag is a collection, all additional values can be merged into as long as they are arrays. This is done recursively so that each existing key and value is preserved.
Hope that can help someone later on.
I want to show the emails that the logged in user has sent from the database
This is the route code:
Route::get('/myEmails/{id}','PagesController#myEmailsShow');
This is the function in the controller:
public function myEmailsShow($id)
{
$myEmails = DB::table('emails')->where('user_id',$id)->get();
return view('content.myEmails', compact('myEmails'));
}
This is the a link where the user click to open the page:
#if(Auth::check())
<a class="nav-link text-white" href="/myEmails/{id}"> my emails</a>
#endif
And here where i want to show the data (i am showing only the name for test):
<div class="row">
#foreach($myEmails as $myEmail)
{{$myEmail->name}}
#endforeach
</div>
I think the best way to accomplish your goals here would be using a hasMany relationship between User and Emails (if emails is a Model).
//User.php
public function emails()
{
return $this->hasMany('App\Models\Email');
}
In the controller, apply the Auth middleware to the myEmailsShow method in a constructor:
//PagesController.php
public function __construct()
{
$this->middleware('auth')->only(['myEmailsShow']);
}
Then, in your myEmailsShow method, do something like the following:
//PagesController.php
public function myEmailsShow()
{
// Middleware Eliminates the need for ID in the function.
$user = auth()->user();
$myEmails = $user->emails;
return view('content.myEmails', compact('myEmails'));
}
You can remove the ID parameter from the route and just make it something like Route::get('/myEmails', 'PagesController#myEmailsShow');. Only users who are logged in will be able to access this page, and they will only see emails belonging to them.
Route::get('/myEmails/{user}','PagesController#myEmailsShow')->name('myemails');
with the controller
use App\Email;
use App\User;
public function myEmailsShow(User $user)
{
///calling the model Email at parameters instead of $id eloquent automatically the data from DB
$myEmails = Email::where('user_id',$user->id)->get();
return view('content.myEmails')->with('myEmails', $myEmails);
}
The link has little modifications
#if(Auth::check())
<a class="nav-link text-white" href="{{route('myemails', $user->id)}}"> my emails</a>
#endif
displaying the value
#foreach($myEmails as $myEmail)
{{$myEmail->name}}
#endforeach
i'm trying to view the profile page of my website and keeps redirecting me to homepage instead of vendors profile
No visible error is been displayed.
can someone help please
here is the link i'm trying to view https://booksafariafrica.com/en/profile/32
this is the code
<div class="owner-info widget-box">
<div class="media">
<div class="media-left">
<a href="{{route('user.profile',['id'=>$vendor->id])}}" target="_blank" >
#if($avatar_url = $vendor->getAvatarUrl())
<img class="avatar avatar-96 photo origin round" src="{{$avatar_url}}" alt="{{$vendor->getDisplayName()}}">
#else
<span class="avatar-text">{{ucfirst($vendor->getDisplayName()[0])}}</span>
#endif
</a>
</div>
My controller
<?php
/**
* Created by PhpStorm.
* User: h2 gaming
* Date: 8/17/2019
* Time: 3:05 PM
*/
namespace Modules\User\Controllers;
use App\User;
use Illuminate\Http\Request;
use Modules\FrontendController;
class ProfileController extends FrontendController
{
public function profile(Request $request,$id){
$user = User::find($id);
if(empty($user)){
abort(404);
}
if(!$user->hasPermissionTo('dashboard_vendor_access'))
{
return redirect('/');
}
$data['user'] = $user;
$data['page_title'] = $user->getDisplayName();
$this->registerCss('module/user/css/profile.css');
return view('User::frontend.profile.profile',$data);
}
My routes
Route::group(['prefix'=>'profile'],function(){
Route::match(['get'],'/{id}','ProfileController#profile')->name("user.profile");
if(!$user->hasPermissionTo('dashboard_vendor_access'))
{
return redirect('/');
}
Your problem is probably being caused by this code block, as it does a redirect to the homepage if the condition is met.
So make sure the $user has the proper permissions assigned to it.
wow, thank's for giving me proper solution
the problem was
if(!$user->hasPermissionTo('dashboard_vendor_access'))
{
return redirect('/');
}
then have to remove the Exclamation mark and worked just fine.
Thank you very much
I'm using laravel-5.4 pagination like the following:
public function index()
{
$jobs = Job::paginate(5);
return view('job.index', compact('jobs'));
}
In the view:
{{ $jobs->links() }}
There is a problem of generating two typical pages: /job and /job?page=1 the two page has the same contents.
I want to do anything that removes the query string page from the first page of the pagination.
I have tried the following:
if ($jobs->onFirstPage()){
$jobs->setPageName('');
}
But this corrupt the pagination, i.e the links of pages does not load correctly and the query string value remains for all pages.
The effective solution for this issue that I have found is to edit the pagination template.
First publish the pagination template from the vendors using the following command from the root of the project:
php artisan vendor:publish --tag=laravel-pagination
Now a file at resources/views/vendor/pagination/default.blade.php should be found and it could be edited like the following using str_replace() for the urls of each page and back navigation button:
<li>{{$foxPrev}}</li>
and
<li>{{ $page }}</li>
Update:
A bug was found with ?page=10 so instead of using str_replace we should using preg_replace like the following:
<li>{{ $page }}</li>
Update 2:
In case of using any customized name for the page number parameter other than page, we could use the paginator getter for the $pageName property like the following in the pagination template:
<li>{{ $page }}</li>
To know more about how to use more than one pagination on the same page or how to customize the page number parameter $pageName from view, checkout this answer
You can extend LengthAwarePaginator method url($page)
/**
* Get the URL for a given page number.
*
* #param int $page
* #return string
*/
public function url($page)
{
if ($page <= 0) {
$page = 1;
}
// If we have any extra query string key / value pairs that need to be added
// onto the URL, we will put them in query string form and then attach it
// to the URL. This allows for extra information like sortings storage.
$parameters = ($page > 1) ? [$this->pageName => $page] : [];
if (count($this->query) > 0) {
$parameters = array_merge($this->query, $parameters);
}
return rtrim($this->path
.(Str::contains($this->path, '?') ? '&' : '?')
.http_build_query($parameters, '', '&')
.$this->buildFragment(), '?');
}
improved Aksi answer
app/Services/CustomLengthAwarePaginator.php
<?php
namespace App\Services;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class CustomLengthAwarePaginator extends LengthAwarePaginator
{
/**
* Get the URL for a given page number.
*
* #param int $page
* #return string
*/
public function url($page)
{
if ($page <= 0) {
$page = 1;
}
// If we have any extra query string key / value pairs that need to be added
// onto the URL, we will put them in query string form and then attach it
// to the URL. This allows for extra information like sortings storage.
$parameters = ($page > 1) ? [$this->pageName => $page] : [];
if (count($this->query) > 0) {
$parameters = array_merge($this->query, $parameters);
}
return $this->path()
. (count($parameters) > 0
? (Str::contains($this->path(), '?') ? '&' : '?')
: '')
. Arr::query($parameters)
. $this->buildFragment();
}
}
in AppServiceProvider.php or another
public function boot()
{
app()->bind(LengthAwarePaginator::class, CustomLengthAwarePaginator::class);
}
add canonical tag in if you care SEO
i don't have any idea...
if($pageNum==1){
return redirect()->to($path);
}
$pageNum id get Request or urself Class
$path = "/jobs"
In your routes, give a name to the route which leads to your function:
Route::get('/yourRoute','YourController#foo')->name('yourRouteName');
Then, In your function in the controller, use this:
public function foo() {
if( request()->page=='1' )
{
return redirect()->route('yourRouteName',[$id]);
}
else {
// Your function content
}
}
I think you can try this:
{{ $jobs->links() }}
To
{{ $jobs->nextPageUrl() }}
Hope this work for you!
You can simply modify the view like this:
#if ($page==1)
{{ $page }}
#else
{{ $page }}
#endif
I found the following works and takes into account page=10 issues:
After you export your pagination views, make the following 2 modifications:
MODIFICATION 1
Replace this:
{{ $paginator->previousPageUrl() }}
with this:
{{ preg_replace('/(?:(&|\\?)page=[1])(?!\\d)/ui','', $paginator->previousPageUrl()) }}
MODIFICATION 2
Replace this:
{{ $url }}
with this:
{{ preg_replace('/(?:(&|\\?)page=[1])(?!\\d)/ui','', $url ) }}
I've done it this way:
{{ $posts->currentPage() == 2 ? route('home') : $posts->previousPageUrl() }}
Just create a Middleware by using this command
php artisan make:middleware RemovePageQuery
Write this code inside middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class RemovePageQuery
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($request->page == 1)
{
return redirect(url()->current());
}
return $next($request);
}
}
Add middleware global in App/Http/Kernel.php inside $middleware.
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\RemovePageQuery::class, //Here
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
I was searching to fix similar issue to prevent content duplication but for symfony not laravel. I fixed it in my way and decided to publish it. May be it will help somebody.
In symfony I use KNP paginator. It provides paginator template, like this:
{{ page }}
'Query' array contains route params and the task is to remove page param if it == 1.
Very simple:
{% set page_seo = (page == 1) ? null : page %}
{{ page }}
Actually - set to null page if it == 1.
By this way you can remove form field from the request in Laravel Controller. It will work 100%. You will get in request without page param.
$request->request->remove('page');
Better answer than #SaidbakR has provided, as I it's not right. Why? Because you will receive link for the same page as URL will be empty. And for example if you make request from url?page=2, you'll get link to same url?page=2 where link to first page must appear.
My easy variant:
Also publish pagination views: php artisan vendor:publish --tag=laravel-pagination
Go to /views/vendor/pagination/default.blade.php
Add elseif case to previous page link:
#elseif($paginator->currentPage() === 2)
<li class="pagination-next-prev link">
<a class="prev page-url" href="?{{ http_build_query(Arr::except(Request::query(), 'page')) }}" rel="prev"
aria-label="#lang('pagination.previous')">
Prev
</a>
</li>
#else
Add similar elseif to array of links:
#elseif(1 === $page)
<li class="page">
<a class="page-url" href="?{{ http_build_query(Arr::except(Request::query(), 'page')) }}">
{{ $page }}
</a>
</li>
#else
This case is also working if you are using ajax request to another page for pagination.
Done
You will have link to the page you opened, but without params. Yes it will be showed as ? in the URL, but it's fair price to avoid duplications of URLs, as link with just question mark for google same as without.