pagination and factory in laravel4 - php

Consider this code taken from here.
public function getIndex()
{
$posts = Post::orderBy('id','desc')->paginate(10);
// For Laravel 4.2 use getFactory() instead of getEnvironment() method.
$posts->getEnvironment()->setViewName('pagination::simple');
$this->layout->title = 'Home Page | Laravel 4 Blog';
$this->layout->main = View::make('home')->nest('content','index',compact('posts'));
}
As I understand it, pagination limits the number of rows, so I think paginate(10) means select first ten rows in the database. But I absolutely don't understand this.
// For Laravel 4.2 use getFactory() instead of getEnvironment() method.
$posts->getEnvironment()->setViewName('pagination::simple');
or
$posts->getFactory()->setViewName('pagination::simple');
And everything below. Mainly I don't understand what factory means and how it relates to pagination. I went to the laravel docs on Illuminate\Pagination\Factory and Illuminate\View\View but I can't find the meaning of factory. Can anyone explain the code above?

You are essentially setting how the pagination is output in HTML by selecting a specific paginator view, this allows you to have more than one type in an application or use different to the default.
Using multiple pagination types in the same application
Sometimes, you may want to use different pagination types across your
application. By default, Laravel will use the type specified in your
app/config/view.php file, so you need to override this setting when
you wish to use another type. Here is how to do so.
// This code should be in a controller or a route Closure.
// Let’s use the good old example of a list of blog posts.
$articles = Article::paginate(5);
Paginator::setViewName('pagination::simple');
/*
Alternatively, you could also use this to achieve the same result:
$articles->getEnvironment()->setViewName('pagination::simple');
For those who would like to know what’s happening under the hood, here is a more
detailed explanation:
1. Calling paginate() on an Eloquent model or a query builder will return an
instance of \Illuminate\Pagination\Paginator
2. Then, we need to get the related \Illuminate\Pagination\Environment of this
paginator via the well-named getEnvironment() method.
3. Finally, we can specify the pagination type we need. The default value is
'pagination::slider'.
The pagination types that are available by default are located in the
vendor/laravel/framework/src/Illuminate/Pagination/views directory.
*/
Source: http://laravel-tricks.com/tricks/using-multiple-pagination-types-in-the-same-application

Related

It is possible to pass 2 differents types of parameters to a Laravel controller?

I already have a GET route with an URI /projects/{id} which displays Infos of a project with a given id. I also have a GET index route (/projects), which shows all my projects.
My problem is that I currently try to create different indexes (for example one which only displays the projects where I am assigned [e.g. on /projects/mines], or the projects which are pending administrator approval [e.g. on /projects/proposals], and still others displays).
So I want to know if I can have two GET routes /projects/{id}and /projects/{display_mode} which will be calling two differents methods of my ProjectController (respectively show and index).
Thanks for your help! :)
You may have one route /projects which returns all projects as default.
If there is query parameter like
/projects?displayMode=proposals
then you can apply filters.
In your controller it would look something like this
$projects = Project::query();
if ($request->query('displayMode') == 'proposals')
$projects->where('pending', true)
return $projects->get();
You can add multiple filters too in the same way
I'm not sure about specific Laravel options for the route definitions (sorry!), but if the {id} will always be an integer and {display_mode} will always have non-digits in it, you could keep just one route, but do the conditional handling in your controller. Just have the mainAction do something like…
return preg_match('/^\d+$/', $param) ? idHelperAction($param) : displayModeHelperAction($param);
Then create those two helper functions and have them return whatever you want.
$param is supposed to be whatever you get from that route parameter -- /projects/{param}.
That should call the idHelperAction for routes where $param is all digits and nothing else; otherwise, it should call the displayModeHelperAction. Either way, it sends the same $param to the helper function and returns whatever that helper function returns -- effectively splitting one route definition into two possible actions.
Of course, you might have to add some context in the code sample. If the functions are all defined in the same class, you might need to use $this->idHelperAction($param) or self::idHelperAction($param) (and the same with the other helper action), depending on whether it's static or not; or tell it where to find the functions if you put them in another class, etc., etc. -- all the normal contextual requirements.

Same url for different routes laravel

I have this two routes
Route::get('/books/{book}', 'FrontEnd\BooksController#show');
Route::get('/books/{main_category}', 'SearchController#getProducts')->name('getProducts');
Is there any way I can make both running ..
When the urls got the same parameter types/length or any other structure, there is no way to distinguish them.
But when there are differences you can use regular-expression-constraints.
You can't make them both running, as Laravel can't differentiate between these route, since they basically have the same URL. If both of your controllers show results on the same page (ex: books index), a workaround could be to make one route, with an optional parameter:
Route::get('/books/{book}/{main_category?}', 'FrontEnd\BooksController#show');
Then you can lead both routes to the same method, and make queries there depending on the parameters you get:
public function show(Request $request){
$books = Book::query(); //initiate query on Book model
if($request->book){
$books = $books->where('...'); //Override the query with new results using book parameter
}
if($request->main_category){
$books = $books->where('...'); //Override the query with new results using book main_category
}
$books = $books->get(); //Retrieve all the results
}
Note: This is not tested, just a quick idea how you could improve your code and use one controller with one method to show book results, instead of using two different controllers. Hope I could give you some ideas with this.
Here you can read more about Laravels optional parameters.
How is the Router supposed to know which route you meant with /books/Harry Potter - And The Goblet of Fire or /books/Fantasy? There is no way to distinct these routes from each other.
Your best bet would be to use query parameters to filter the books - e.g.
/books/?name=Harry Potter - And The Goblet Of Fire
/books/?category=Fantasy
But the /books/{whatever} should be reserved for the primary key of a book. So you could do something like /books/1/author or /books/32784893/ratings.
The same route would only work if you can distinguish the values for sure (as Pilan stated in his answer).

FOSElasticaBundle: Is it possible to change "query_builder_method" in controller?

According to FOSElasticaBundle documentation it is possible to configure application to use custom query builder method like this:
user:
persistence:
elastica_to_model_transformer:
query_builder_method: createSearchQueryBuilder
But is it possible to choose QB method live, e.g. in controller action?
I'd like to be able to control what's being fetched from DB while transforming Elastica results to Doctrine entities. E.g. sometimes I'll want to do eager fetch on some relations, but can't do that by default.
Since FOSElasticaBundle documentation is not very precise, I went through its code and found it impossible to control what query builder is used on controller level.
It is possible to change whole elastica_to_model_transformer to a custom service, but still it's statically defined in configuration. Maybe with some dirty solution it would be possible going this way, but I don't think it's worth it.
I decided to just not using this feature of FOSElasticaBundle. The main problem I had was that when you use fos_elastica.index instead of fos_elastica.finder or elastica repository (in order to get plain not transformed results Elastica\Resultset), there's no findPaginated method with returns Pagerfanta paginator object, which is very helpful in my case.
Fortunately although it's not mentioned in documentation it's possible to create the Pagerfanta this way too, but a little bit more manually.
Here's a code snippet:
//generate ElaticaQuery somehow.
$browseQuery = $browseData->getBrowseQuery();
$search = $this->container->get('fos_elastica.index.indexName.typName');
//create pagerfanta's adapter manually
$adapter = new \Pagerfanta\Adapter\ElasticaAdapterElasticaAdapter($search, $browseQuery);
// now you can create the paginator too.
$pager = new Pagerfanta($adapter);
//do some paging work on it...
$pager->setMaxPerPage($browseData->getPerPage());
try {
$pager->setCurrentPage($browseData->getPage());
} catch(OutOfRangeCurrentPageException $e) {
$pager->setCurrentPage(1);
}
//and get current page results.
/** #var Result[] $elasticaResults */
$elasticaResults = $pager->getCurrentPageResults();
// we have to grab ids manyally, but it's done the same way inside FOSElasticaBundle with previous approach
$ids = array();
foreach($elasticaResults as $elasticaResult) {
$ids[] = $elasticaResult->getId();
}
//use regular Doctrine's repository to fetch Entities any way you want.
$entities = $this->getDoctrine()->getRepository(MyEntity::class)->findByIdentifiers($ids);
This actually has a few advantages. In general it gives you back control over your data and doesn't tie ElasticSearch with Doctrine. Therefore you can resign on fetching data from Doctrine if you have all needed data in ElasticSearch (if they are read only data of course). This lets you optimize your application performance but reducing amount of SQL queries.
The code above may be wrapped with some kind of service in order to prevent making mess in controllers.

How to define routes with multiple parameters without pretty urls in Laravel

I am using Laravel. I would like users to be able to perform a search on my website using up to 3 criteria. These criteria are: Class, Brand and Model.
They should be free to use any or all of them when searching. As the relationship between these isn't as simple as Many->1, Many->1, Many->1, and also given the criteria will be numbered if blank, I dont want to use pretty urls to post the search criteria as they would look like this:
/SearchResults/0/BMW/0
which is meaningless to users and search engines. I therefore want to use normal dynamic addresses for this route as follows:
/SearchResults/?Class=0&Brand="BMW"&Model=0
How do I define a route that allows me to extract these three criteria and pass it to a custom method in my resource controller?
I have tried this but it isnt working:
Route::get('/SearchResults/?Class={$class}&Brand={$brand}&Model={$type}', 'AdvertController#searchResults');
Many thanks
The Symfony Routing components fetch the REQUEST_URI server variable for matching routes, and thus Laravel's Route Facade would not pick up URL parameters.
Instead, make use of Input::get() to fetch them.
For example, you would start by checking if the class param exists by using Input::has('class'), and then fetching it with Input::get('class'). Once you have all three, or just some of them, you'd start your model/SQL query so that you may return your results to the user.
You will need to route all to the same method and then, within the controller, reroute that given action to the correct method within the controller.
For that, I recommend using the strategy pattern (read more here).
I would do something like this:
route.php
Route::get('/SearchResults', 'AdvertController#searchResults');
AdvertController.php
use Input;
...
private $strategy = [];
public function __construct(){
$strategy = [
/*class => handler*/
'0'=> $this->class0Handler,
'1'=>$this->class1Handler,
...];
}
private function class0Handler(){
//your handler method
}
public function searchResults(){
if( !array_key_exists(Input::get('class'),$this->strategy))
abort(404);
return $this->strategy[Input::get('class')]();
}
In case you are breaking down search by other types, you define the handler in the $strategy variable.
Strategy pattern has a lot of benefits. I would strongly recommend it.

how to create a method on the fly in ci

I'm writing a control panel for my image site. I have a controller called category which looks like this:
class category extends ci_controller
{
function index(){}// the default and when it called it returns all categories
function edit(){}
function delete(){}
function get_posts($id)//to get all the posts associated with submitted category name
{
}
}
What I need is when I call http://mysite/category/category_name I get all the posts without having to call the get_posts() method having to call it from the url.
I want to do it without using the .haccess file or route.
Is there a way to create a method on the fly in CodeIgniter?
function index(){
$category = $this->uri->segment(2);
if($category)
{
get_posts($category); // you need to get id in there or before.
}
// handle view stuff here
}
The way I read your request is that you want index to handle everything based on whether or not there is a category in a uri segment. You COULD do it that way but really, why would you?
It is illogical to insist on NOT using a normal feature of a framework without explaining exactly why you don't want to. If you have access to this controller, you have access to routes. So why don't you want to use them?
EDIT
$route['category/:any'] = "category/get_posts";
That WOULD send edit and delete to get_posts, but you could also just define those above the category route
$route['category/edit/:num'] = "category/edit";
$route['category/delete/:num'] = "category/delete";
$route['category/:any'] = "category/get_posts";
That would resolve for the edit and delete before the category fetch. Since you only have 2 methods that conflict then this shouldn't really be that much of a concern.
To create method on the fly yii is the best among PHP framework.Quite simple and powerful with Gii & CRUD
http://www.yiiframework.com/doc/guide/1.1/en/quickstart.first-app
But I am a big CI fan not Yii. yii is also cool though.
but Codeigniter has an alternative , web solution.
http://formigniter.org/ here.

Categories