Slim with laravel pagination, always page 1 - php

I required Illuminate/pagination into my Slim 3 project
I've the following in my route:
$this->get('/traces', 'UserController:getTraces')->setName('user.traces');
In the getTraces method:
public function getTraces($req, $res)
{
$loginRows = $this->db->table('login_history')->where('user_id', $_SESSION['user'])->orderBy('id', 'desc')->paginate(5);
$loginRows->setPath($this->router->pathFor('user.traces'));
$this->view->getEnvironment()->addGlobal('login_rows', $loginRows);
return $this->view->render($res, 'user/traces.twig');
}
In my view (I'm using Twig):
{{ login_rows.render() | raw }}
So everything is working just fine and also the pagination html links, but even if I go to ?page=2 or any other page. It always display first page 1 with same rows. It says that it detect the page number but obviously it's wrong, is there a way I can set the page number manually or a fix if the problem is actually in my code?
Thanks in advance.

If anyone interested, I just did that:
$loginRows = $this->db->table('login_history')->where('user_id', $_SESSION['user'])->orderBy('id', 'desc')->paginate(5, ['*'], 'page', $req->getParam('page'));
$loginRows->setPath($this->router->pathFor('user.traces'));
This is fixed my problem, I'm sure there is a better solution but at least this works!

The problem is that Eloquent's Paginator doesn't know how to extract the "page" parameter from Slim's router. But you can give it a new function to help. Here I've created a middleware that tells the Paginator how to find the "page" parameter.
<?php
/**
* Tells the Eloquent Paginator how to get the current page
*/
namespace App\Middleware;
class Pagination {
public function __invoke($request, $response, $next)
{
\Illuminate\Pagination\Paginator::currentPageResolver(function() use ($request) {
return $request->getParam('page');
});
return $next($request, $response);
}
}
Then when setting up the app, you can add this:
$app->add(new App\Middleware\Pagination);
Be aware that will be run for every page request (even those without pagination). I doubt it's really a performance hit. If concerned, you can apply it to specific routes. Or call currentPageResolver() just before your query.

Related

Laravel. conflict with routes

I have a problemwith my routes. When I call 'editPolicy' I dont know what execute but is not method editPolicy. I think I have got problem beteweeb this two routes:
My web.php ##
Route::get('admin/edit/{user_id}', 'PolicyController#listPolicy')->name('listPolicy');
Route::put('/admin/edit/{policy_id}','PolicyController#editPolicy')->name('editPolicy');
I call listPolicy route in all.blade.php view like this:
{{ $user->name }}
And call editPolicy route in edit.blade.php view like this:
Remove</td>
My PolicyController.php is:
public function listPolicy($user_id)
{
$policies = Policy::where('user_id', $user_id)->get();
return view('admin/edit',compact('policies'));
}
public function editPolicy($policy_id)
{
dd($policy_id);
}
But I dont know what happend when I call editPolicy route but editPolicy method not executing.
Any help please?
Best regards
Clicking an anchor will always trigger a GET request.
route('listPolicy', $user->id) and route('editPolicy', $policy->id) will both return admin/edit/{an_id} so when you click your anchor, listPolicy will be executed. If you want to call editPolicy, you have to send a PUT request via a form, as defined when you declared your route with Route::put.
Quick note, your two routes have the same URL but seem to do very different things, you should differentiate them to avoid disarray. It's ok to have multiple routes with the same url if they have an impact on the same resource and different methods. For example for showing, deleting or updating the same resource.
Have a look at the documentation.

Grouping all the laravel application routes using dynamic prefix

We have multiple client portal each one has a unique url like
xyz.com/ClientPotal123
xyz.com/ClientPotal234
xyz.com/ClientPotalXXX
We will be routing all these url's to
/var/www/html/Laravelapp/public
Laravelapp is our codebase which we use for all the clients.
Since ClientPotalXXX is dynamic and unique for all the clients, I need to get the value of ClientPotalXXX for loading client specific settings like url generation, database connection (We have different database for each client).
To achieve above I've done below changes..
My Web.php file is as below..
Route::pattern('ClientPortal','^ClientPortal([0-9]+)?');
Route::prefix('/{ClientPortal}')->group(function () {
Route::get('/user/list', 'UserController#list')->name('list');
Route::get('/user/edit/{id}', 'UserController#edit');
});
I've created Middleware with below code written in it..
public function handle($request, Closure $next)
{
$database_name = strtolower($request->ClientPortal).'_db';
config(['database.connections.mysql.database'=>$database_name]);
config(['app_settings.client'=>$request->ClientPortal]);
return $next($request);
}
And it's working fine but previously I used to access $id in edit function directly
public function edit($id){
echo $id; // 12
}
But now $id return the value of ClientPortalXX everytime.
If I access id from Request it works fine
public function edit(Request $request){
$id = $request->id; // 12
}
This is happening with all of the other routes where I'm using route parameters.
So I'm not sure if this happened because I'm using dynamic prefix for grouping all the routes?
And now for every route() method which I've used in blade files for url generation I have to pass the second parameter ie. Value of {ClientPortal}
{{route('register',['ClientPortal'=>config('app_settings.client')])}}
Is this right implementation? I know we can make any varibale accessible globally using service provider but will it be right to do so?
My Laravel Version is 5.5.xx.. I'm just a beginner so any Help/Suggestion/Advice will be appreciated Thanks :)
Update:
Nikola Gavric and Oluwafemi Sule had already clarified my doubt in comments below.
But since the group prefix is dynamic, How do I handle the route naming case?
If I had to generate user list url using list route name which is mentioned in above web.php file.
Now I've to change this line..
{{ route('list') }}
To
{{ route('list',['ClientPortal'=> 'ClientPortalXXX' ]) }}
Since prefix is also a route param.
Is this feasible option? Because I've to do this change everywhere where I've used route method for url generation.

rerouting after calling a function in Laravel 5

I'm getting my feet wet with Laravel 5 and I need a little advice on Routing.
I'm running in to a problem over and over and I feel like I'm definitely not grasping the proper way to do this.
Lets say I have a route:
Route::post('viewarticles', 'LoginController#user_check_article_list');
This is where I am taken after I login.
This route shows me my articles that I can edit. On the page this route takes you to I have a list of articles and delete buttons next to them. When I click delete I have it linked to
delete/{{ $article->id }}
I then have a route:
Route::get('delete/{id}', 'ArticleController#deleteArticle');
Which then goes to this function:
public function deleteArticle(Request $request, $id) {
$article = Article::find($id);
$article->delete();
$articles = Article::latest('published_at')->Published()->get();
return view('admin.article_edit_list',['articles'=>$articles]);
}
The last two lines of this is me rebuilding that article list and then loading the view.
THE PROBLEM: In my url the page is still ../delete/someid
I really just need a way to transfer back to the routes.
Instead of returning a view, return a redirect. This will cause the url to change:
public function deleteArticle(Request $request, $id)
{
$article = Article::find($id);
$article->delete();
return redirect('/some-url');
}
Or if using named routes:
return redirect()->route('some.route.name');
Source
so if your url is staying at /delete/{id} you need to redirect to the the display articles view
public function deleteArticle(Request $request, $id) {
$article = Article::find($id);
$article->delete();
return \Redirect::to('show_articles.view');
}
how do you send the delete request ? is it via ajax?
if so you need to redirect to your view in the success method of your ajax call using js / most likely jQuery?
.success(function(){
location.href = '/your/new/view';
});
its worth checking your variables are getting through to your controller as well
public function ...
echo $id; exit(); // or dd($id);
and checking your collection loaded
$articles = ...
dd($artcles);
retrun view(...
also if you go in to app/config/app.php and set debug=true you should get an error stack which will help debug the issue. Sorry for the delay internet went down before I could finish typing.

Laravel Routing to same view different function

I am trying to return values from a MySQL database into a datatable using Chumper. I am trying to obtain values from 2 tables; but I am having what I believe to be a routing issue as I do not know how to include 2 controller functions to the same view ie in my search view I want to render the result of 2 functions like : for a deeper understanding of what I am trying to accomplish see question : Laravel Chumper Datatable getting data into one datatable from multiple MySQL tables
Route::get('search', array('as' => 'instance.search', 'uses' => 'CRUDController#instances'));
Route::get('search', array('as' => 'accid.search', 'uses' => 'CRUDController#account_ids'));
any ideas ?
Only a single route will ever match any given URL requested of the system. I believe what Laravel will do is choose the second one (as in the second definition will overwrite the first).
You have some options here. All I can really tell from your question is that you want two methods to be executed when that route gets hit. This is indirectly possible, consider:
Route::get('search', 'MyController#instances');
class MyController extends Controller
{
public function instances()
{
$mydata = $this->account_ids();
$myotherdata = $this->getOtherData();
return View::make('myview')
->with('mydata', $mydata)
->with('myotherdata', $myotherdata);
}
private function getOtherData() { /* ... */ }
}
This isn't really clean, though, and eventually will lead to convoluted controller logic which is an anti-pattern in MVC. Fortunately, Laravel let's you use View Composers, which can greatly clean up your controller logic:
public function instances()
{
return View::make('myview');
}
Wow. Nice and simple. Now the view composer part:
// Inside of a service provider...
View::composer('search', 'App\Http\ViewComposers\AViewComposer');
use View;
class AViewComposer
{
public function compose(View $view)
{
$view->with('instances', $this->instances());
$view->with('accountIds', $this->accountIds());
}
public function instances()
{
// generate your instance data here and return it...
return $instances;
}
public function accountIds()
{
// generate your account id data here and return it...
return $accountIds;
}
}
You could take this a step further and inject another class into the constructor of this view composer to completely off-load the responsibility of determining what 'instances' and 'account ids' actually mean, should you need that same functionality elsewhere. This will help you keep your code extremely DRY.
You are having those 2 routes but with same domain so the second one is running over the second one.
Or you change the URL of on of them or you change the method for post instead of get

How can I setup Laravel 3 routes for pages of focus on my default controller?

There will be several high profile links for customers to focus on, for example:
Contact Us # domain.com/home/contact
About the Service # domain.com/home/service
Pricing # domain.com/home/pricing
How It Works # domain.com/home/how_it_works
Stuff like that. I would like to hide the home controller from the URL so the customer only sees /contact/, not /home/contact/. Same with /pricing/ not /home/pricing/
I know I can setup a controller or a route for each special page, but they will look the same except for content I want to pull from the database, and I would rather keep my code DRY.
I setup the following routes:
Route::get('/about_us', 'home#about_us');
Route::get('/featured_locations', 'home#featured_locations');
Which work well, but I am afraid of SEO trouble if I have duplicate content on the link with the controller in the URL. ( I don't plan on using both, but I have been known to do dumber things.)
So then made routes like these:
Route::get('/about_us', 'home#about_us');
Route::get('/home/about_us', function()
{
return Redirect::to('/about_us', 301);
});
Route::get('/featured_locations', 'home#featured_locations');
Route::get('/home/featured_locations', function()
{
return Redirect::to('/featured_locations', 301);
});
And now I have a redirect. It feels dumb, but it appears to be working the way I want. If I load the page at my shorter URL, it loads my content. If I try to visit the longer URL I get redirected.
It is only for about 8 or 9 special links, so I can easily manage the routes, but I feel there must be a smart way to do it.
Is this even an PHP problem, or is this an .htaccess / web.config problem?
What hell have I created with this redirection scheme. How do smart people do it? I have been searching for two hours but I cannot find a term to describe what I am doing.
Is there something built into laravel 4 that handles this?
UPDATE:
Here is my attempt to implement one of the answers. This is NOT working and I don't know what I am doing wrong.
application/routes.php
Route::controller('home');
Route::controller('Home_Controller', '/');
(you can see the edit history if you really want to look at some broken code)
And now domain.com/AboutYou and domain.com/aboutUs are returning 404. But the domain.com/home/AboutYou and domain.com/home/aboutUs are still returning as they should.
FINAL EDIT
I copied an idea from the PongoCMS routes.php (which is based on Laravel 3) and I see they used filters to get any URI segment and try to create a CMS page.
See my answer below using route filters. This new way doesn't require that I register every special route (good) but does give up redirects to the canonical (bad)
Put this in routes.php:
Route::controller('HomeController', '/');
This is telling you HomeController to route to the root of the website. Then, from your HomeController you can access any of the functions from there. Just make sure you prefix it with the correct verb. And keep in mind that laravel follows PSR-0 and PSR-1 standards, so methods are camelCased. So you'll have something like:
domain.com/aboutUs
In the HomeController:
<?php
class HomeController extends BaseController
{
public function getAboutUs()
{
return View::make('home.aboutus');
}
}
I used routes.php and filters to do it. I copied the idea from the nice looking PongoCMS
https://github.com/redbaron76/PongoCMS-Laravel-cms-bundle/blob/master/routes.php
application/routes.php
// automatically route all the items in the home controller
Route::controller('home');
// this is my last route, so it is a catch all. filter it
Route::get('(.*)', array('as' => 'layouts.locations', 'before' => 'checkWithHome', function() {}));
Route::filter('checkWithHome', function()
{
// if the view isn't a route already, then see if it is a view on the
// home controller. If not, then 404
$response = Controller::call('home#' . URI::segment(1));
if ( ! $response )
{
//didn't find it
return Response::error('404');
}
else
{
return $response;
}
});
They main problem I see is that the filter basically loads all the successful pages twice. I didn't see a method in the documentation that would detect if a page exists. I could probably write a library to do it.
Of course, with this final version, if I did find something I can just dump it on the page and stop processing the route. This way I only load all the resources once.
applicaiton/controllers/home.php
public function get_aboutUs()
{
$this->view_data['page_title'] = 'About Us';
$this->view_data['page_content'] = 'About Us';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_featured_locations()
{
$this->view_data['page_title'] = 'Featured Locations';
$this->view_data['page_content'] = 'Featured properties shown here in a pretty row';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_AboutYou()
{
//works when I return a view as use a layout
return View::make('home.index');
}

Categories