Nested Controllers and routes - php

I'm creating a dashboard where the user can create Clients
Each Client will have: Categories, Employees, ...
Now I'm wondering how to structure the routes.
For example if I create the following: (pseudo code)
Route::get('clients/{id}/');
Route::get('clients/{id}/categories');
Route::get('clients/{id}/categories/{category}');
Route::get('clients/{id}/categories/{category}/questions/{question}');
This seems like a lot of unnecessary parameters..
How do you guys go about this? I really want to split the categories on a seperate page, the employees on a seperate page.
Thank you.

in all of my projects, i avoid using a lot of nested entities in the URL, so i access each one apart, this was also recommended by #jeffrey_way at Laracasts, the training website for laravel.
so, i would do the following:
Route::get('clients/{id}/');
Route::get('categories/{client_id}');
Route::get('categorie/{category}'); //not that i have removed the plural s from categorie(s)
Route::get('question/{question}');
Good luck

It honestly depends on how big your application is going to become, I would probably group them, so still keeping the same structure.
Route::group('clients/{id}', function()
{
Route::get('/');
Route::group('categories', function()
{
Route::get('/');
Route::get('{category}');
Route::get('{category}/questions/{question}');
})
})
Same as yours but I feel it a little cleaning for later if you expand on the categories or clients.

Here in such case I would rather prefer to use only one route will all parameters as in GET method. So, I would have add just one param as bellow:
Route::get('client/create', 'ClientController#store');
So, all the parameters will be maintained by the store method of ClientController like below:
public function store(Request $request){
$category = $request->get('category')
//......
//get other get parameters like this when required
}
When I need to trigger this route I would just do something like below:
Create link
As you know, we can pass our parameters here using our old global friend GET variable.

Related

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).

Laravel routing - two url addresses with similar names

I'm doing forum with Laravel.
I decides to have routes like this:
Route::get('/{topicName}', 'ForumController#showTopic');
Route::get('/{postSubject}', 'ForumController#showPost');
I have also another routes, but this two are on the bottom, because, when I write sth in URL (and laravel doesn't find passing address) then everything fall into this routes (especially the first one). I don't know how to programm this to work this two last routes.
When someone add my Topic name, then he's going on the site:
http:/forum/php
or
http:/forum/javaScript
Then user see all posts to this Topic. But when user want to see one specific post, then I want to be in url like this:
http:/forum/post_subject_name
And now user can see specific post.
How to do this, because now everything fall to my first controller - ForumController#showTopic'). Is this possible?
You can't, both those routes have the same requirement, if they are at the bottom of your routes, the topicName one will always take priority.
You should have routes such as
Route::get('/topics/{topicName}', 'ForumController#showTopic');
Route::get('/posts/{postSubject}', 'ForumController#showPost');
That way you can distinguish between them
Problem is that both routes consist of one parameter and nothing else. How is it supposed to know if the given parameter is a topic name or a post subject?
However, what you could do is having one route and do the rest in the controller method:
Route::get('/{topicOrPost}', 'ForumController#showTopicOrPost');
public function showTopicOrPost($topicOrPost)
{
$topic = Topic::where('name', $topicOrPost)->first();
if ($topic !== null) {
// show the topic
} else {
$post = Post::where('subject', $topicOrPost)->first();
if ($post !== null) {
// show the post
} else {
// neither topic or post found
}
}
}
But then, of course, you'd have to ensure that there aren't topic and post with the same name/subject.
in my opinion you could use pattern in route
Regular Expression Constraints
some example :
// This is what you might have right now
Route::get('users/{id}', 'UserController#getProfile')->where('id', '[\d+]+');
Route::get('products/{id}', 'ProductController#getProfile')->where('id', '[\d+]+');
Route::get('articles/{slug}', 'ArticleController#getFull')->where('slug', '[a-z0-9-]+');
Route::get('faq/{slug}', 'FaqController#getQuestion')->where('slug', '[a-z0-9-]+');
// and many more, now imagine you'll have to change the rule
// Instead, you could have a handy list of patterns and reuse them everywhere:
// Patterns
Route::pattern('id', '\d+');
Route::pattern('hash', '[a-z0-9]+');
Route::pattern('hex', '[a-f0-9]+');
Route::pattern('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}');
Route::pattern('base', '[a-zA-Z0-9]+');
Route::pattern('slug', '[a-z0-9-]+');
Route
::pattern('username', '[a-z0-9_-]{3,16}');
and for you I think you could use something like this:
Route::get('/{any}','SearchController#showPost')->where('any','^[post_]+$');
Route::get('/{any}','SearchController#showTopic');
but you have to use ShowTopic route after showpost

Custom route not working | Codeigniter Routing

I am working on an API via which I embed images of country flags on my website & several others.
I am taking in 3 parameters i.e
Country (Name of Country - ISO Code or Full Name)
Size (Dimension of Image)
Type (Styles like flat flag, shiny round flag etc...)
Now, have everything setup correctly but stuck in handling URI.
Controller -> flags.php
Function -> index()
What I have now is :
http://imageserver.com/flags?country=india&size=64&style=round
What I want
http://imageserver.com/flag/india/64/round
I went through some articles and made this route but all of them failed
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index/country/$1/size/$2/style/$3";
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index/$1/$2/$3";
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index?country=$1&size=$2&style=$3";
I have also been having trouble with routes while writing my custom cms. Reading through your question, I see a couple issues that might very well be the answer you are looking for.
For starters, let's look at the routes you have tried:
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index/country/$1/size/$2/style/$3";
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index/$1/$2/$3";
$route['flag/(:any)/(:num)/(:any)'] = "welcome/index?country=$1&size=$2&style=$3";
If you want to run the index method from your flags class, which it looks like you do, you don't want to route to the welcome class at all. Currently, however, you are. Your routes should look like:
$route['flag/(:any)/(:num)/(:any)'] = "flags/index";
That way, Codeigniter will run the index method from your flags class. You don't have to worry about the country, size, or style/type in the route. The best option there would be to use the URI segment function like this:
$country = $this->uri->segment(2); //this would return India as per your uri example.
$size = $this->uri->segment(3); //this would return 64 as per your uri example.
$style = $this->uri->segment(4); //this would return round as per your uri example.
You could then use those variables to query your database and get the correct flag or whatever else you need to do with them.
So to restate my answer with a little more explanation as to why:
The routes you have currently are running the welcome controller/class and the index function/method of that controller/class. This, obviously, is not what you want. So you need to make sure your routes are pointing to the correct controller and function like I did above. The extra segments of the URI don't need to be in your route declaration, so you would then just use the uri_segment() function to get the value of each segment and do what you need with them.
I hope this helps you. I may not have found an answer for my problem, but at least I could provide an answer for someone else. If this seems confusing to you, check out the user guide at http://ellislab.com/codeigniter/user-guide. The main links you need for this are:
http://ellislab.com/codeigniter/user-guide/libraries/uri.html
and
http://ellislab.com/codeigniter/user-guide/general/routing.html
Let me know if you need more help or if this helped solve your problem.

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.

CakePHP View including other views

I have a CakePHP application that in some moment will show a view with product media (pictures or videos) I want to know if, there is someway to include another view that threats the video or threats the pictures, depending on a flag. I want to use those "small views" to several other purposes, so It should be "like" a cake component, for reutilization.
What you guys suggest to use to be in Cake conventions (and not using a raw include('') command)
In the interest of having the information here in case someone stumbles upon this, it is important to note that the solution varies depending on the CakePHP version.
For CakePHP 1.1
$this->renderElement('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.thtml, where $flag will have the value of whatever you pass to it.
For CakePHP 1.2
$this->element('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.ctp, where $flag will have the value of whatever you pass to it.
In both versions the element will have access to all the data the view has access to + any values you pass to it. Furthermore, as someone pointed out, requestAction() is also an option, but it can take a heavy toll in performance if done without using cache, since it has to go through all the steps a normal action would.
In your controller (in this example the posts controller).
function something() {
return $this->Post->find('all');
}
In your elements directory (app/views/element) create a file called posts.ctp.
In posts.ctp:
$posts = $this->requestAction('posts/something');
foreach($posts as $post):
echo $post['Post']['title'];
endforeach;
Then in your view:
<?php echo $this->element('posts'); ?>
This is mostly taken from the CakePHP book here:
Creating Reusable Elements with requestAction
I do believe that using requestAction is quite expensive, so you will want to look into caching.
Simply use:
<?php include('/<other_view>.ctp'); ?>
in the .ctp your action ends up in.
For example, build an archived function
function archived() {
// do some stuff
// you can even hook the index() function
$myscope = array("archived = 1");
$this->index($myscope);
// coming back, so the archived view will be launched
$this->set("is_archived", true); // e.g. use this in your index.ctp for customization
}
Possibly adjust your index action:
function index($scope = array()) {
// ...
$this->set(items, $this->paginate($scope));
}
Your archive.ctp will be:
<?php include('/index.ctp'); ?>
Ideal reuse of code of controller actions and views.
For CakePHP 2.x
New for Cake 2.x is the abilty to extend a given view. So while elements are great for having little bits of reusable code, extending a view allows you to reuse whole views.
See the manual for more/better information
http://book.cakephp.org/2.0/en/views.html#extending-views
Elements work if you want them to have access to the same data that the calling view has access to.
If you want your embedded view to have access to its own set of data, you might want to use something like requestAction(). This allows you to embed a full-fledged view that would otherwise be stand-alone.
I want to use those "small views" to
several other purposes, so It should
be "like" a cake component, for
reutilization.
This is done with "Helpers", as described here. But I'm not sure that's really what you want. The "Elements" suggestion seems correct too. It heavily depends of what you're trying to accomplish. My two cents...
In CakePHP 3.x you can simple use:
$this->render('view')
This will render the view from the same directory as parent view.

Categories