Route with multiple Id's (Laravel 5.2) - php

I want a URI like this
http://localhost:8000/category/1/3
The first id is Category_id and second is Food_id.
My route is:
Route::get('category/{Category_id?}/{Food_id?}', 'DetailsController#categ');
And in Controller I have:
public function categ($Category_id,$Food_id)
{
$category = Categories::with('food')->findOrFail($Category_id);
$food = Food::with('restaurant','categories')->findOrFail($Food_id);
return view('category', compact('category','food'));
}
But it gives error Missing argument 2 for App\Http\Controllers\Detailscontroller::categ().Can anyone tell where is the problem.I am new to laravel.What I want to do is first shows food items based on category_id and then shows the deatails of foods according to food_id.
For showing relevant category of foods,in my view I have
#foreach ($Category as $categories)
{{$categories->CategoryName}}
#endforeach
and it shows me food items.Then I want when I click on any food item it shows me detail based on food_id. so my nxt view look like:
#foreach ($category->food as $food)
{{ $food->FoodName }}
#endforeach

The comment Anish left was correct, however, you main problem will come when you're trying to find models with null. To get around this you could have something like:
public function categ($Category_id,$Food_id)
{
$category = is_null($Category_id) ? []: Categories::with('food')->findOrFail($Category_id);
$food = is_null($Food_id) ? [] : Food::with('restaurant','categories')->findOrFail($Food_id);
return view('category', compact('category','food'));
}
NB They may be more errors in your view file depending on if you're trying to access.
However, I would go with a much more RESTful approach: https://laravel.com/docs/5.2/controllers#restful-resource-controllers
Essentially, this would mean having a controller for you Categories:
public function index() {
//Code to get all categories (if you have a lot you may want to paginate them)
}
public function show($Category_Id) {
$category = Categories::with('food')->findOrFail($Category_id);
//etc
}
and then a controller for you Foods with just a show() method:
public function show($Food_Id) {
$food = Food::with('restaurant','categories')->findOrFail($Food_id);
}
OR depending on how you set your route up you could also include the category as well if you need to (but if it's just a one2Many relationship it might be redundant) so you would have
public function show($category_ID, $Food_Id) //etc
Your routes would then be set up like this:
Route::get('categories', 'CategoriesController#index');
Route::get('categories/{$category_id}', 'CategoriesController#show');
//Assuming you go with the first option - something like:
Route::get('foods/{$food_id}', 'FoodsController#show');
//Assuming you go with the section option for Foods
Route::get('categories/{$category_id}/{$food_id}', 'FoodsController#show');
Obviously, the above is just an example so feel free to set you controllers/routes up how you like.
If you do end up going down the RESTful route (recommended) you then might want to look at: https://laravel.com/docs/5.2/routing#route-model-binding
Hope this help!

Related

How to create a collection (or array) listing all parents and their children to pass to a view

I am quite new to Laravel. I know how I could do this but don't know if it is the best method. I have a system of items called "Flows". Each of them belong to a particular "FlowCategory". I would like to retrieve all the "FlowCategory" items and then their associated children ("flows") using the controller and pass that to the view.
The view I want will show a list of each Flow Category and it's associated flows.
I've set up Eloquent and the two items have a relationship. I have created a foreach loop in in the controller and have created an array manually but I'm insure if its correct.
foreach ($cats as $cat) {
$catid = $cat->id;
$flows[$catid] = \App\FlowCategory::find($catid)->flows;
}
Alright, maybe you to do something like that. But just to refresh the concept:
Flows belongsTo a Flow Category
Flow Category hasMany Flows.
Your models:
FlowCategory:
public function flows()
{
return $this->belongsTo('App\Flow', 'category_id');
}
Flow:
public function flowCategory()
{
return $this->hasMany('App\FlowCategory');
}
That is, if you want to display in your view all Flow Categories, with their respective items, you can do like that:
FooController.php
public function bar() {
// "with" is to avoid N+1 query problem
$flowsCategories = FlowCategory::with('flows')->get();
return view('yourview', compact('flowsCategories'));
}
And then, to display the items on your view, for each category you can do like that:
#foreach($flowsCategories as $flowCategory)
#foreach($flowCategory->flows as $flow)
Flow: {{ $flow->name }} – Flow Category: {{ $flowCategory->name }}
#endforeach
#endforeach

undefined variable when trying to fetch data from database laravel

Hi I'm having trouble getting data from database after adding a new function inside my controller. Can anyone explain to me this error and what should I do?
Background information: I have 3 different type of tables, personal_infos, user_infos and user_info1s table where personal_infos hasMany user_infos and user_info1s. I am using user_id as a foreign key to link together with personal_infos table
I'm using this video as a reference and want to do something like his end result (see 17.17 of video), but I get this error:
Error: Undefined variable: data
What I want to do:
Route.php
Route::get('/home/{id}', 'HomeController#getData')->name('home');
HomeController
public function getData($id) {
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
if (count($data) > 0) {
return view('home',$data)
->with('test', personal_info::find($id)); // --> after adding this got error
} else {
return view('home');
}
}
Home.blade.php
<table class="table table-bordered">
<tr>
<th><strong><big>Name: </big></strong></th>
</tr>
<td>
<tr>
#foreach($data as $value)
<tr>
<th>{{HTML::link_to_route('home',$value->Name, array($value->id)) }}</th>
</tr>
#endforeach
</tr>
</tr>
</table>
Code that I have now after some changes:
HomeController:
public function getData($id = null){
$data['data'] = DB::table('personal_infos')->orderBy('created_at', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
}
}
home.blade.php
<ul>
#foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
#endforeach
</ul>
Route
Route::get('/home/{id?}', 'HomeController#getData')->name('home');
personal_info model: (don't know if needed but just in case)
class personal_info extends Eloquent
{
protected $fillable = array('Email', 'Name', 'Mobile_No');
protected $table = 'personal_infos';
protected $primaryKey = 'id';
public function user_infos() {
return $this->hasMany('App\user_info','user_id');
}
public function user_info1s() {
return $this->hasMany('App\user_info1','user_id');
}
}
user_info1 and user_info (they are similar so I will just put 1 of them)
class user_info1 extends Eloquent
{
protected $fillable = array('hobby','sport','user_id');
public function personal_infos() {
return $this->belongsTo('App\personal_info', 'user_id', 'id');
}
}
I can tell you're learning Laravel. There are several issues with the code posted in your question. Let's walk through each of these to see if we can improve your understanding.
First, let's take a look at the controller method signature:
public function getData($id)
This method expects an $id parameter defined in the corresponding route. However, if we take a look at the route:
Route::get('/home/(:any)', 'HomeController#getData')->name('home');
...it doesn't properly declare that the URL contains a parameter (the video you're watching is about a very old version of Laravel). As described in the docs, we'll need to change the route signature to include a parameter for $id:
Route::get('/home/{id}', 'HomeController#getData')->name('home');
Next, let's see how the controller method fetches its data:
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
This query fetches all records from personal_infos into a Collection, and then sorts them by upload_time. This is fine, but database engines can usually sort data faster than our PHP application, so we can instruct the DB to sort our data for us:
$data['data'] = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
Notice how we changed the call to sortByDesc() on the collection to orderBy() for the database query. Now, the database sorts the results for us, so the collection doesn't need to.
Finally, let's try to fix the error you experience when passing the data to the view. Here's how your controller method currently does it:
if (count($data) > 0) {
return view('home', $data)
->with('test', personal_info::find($id)); // --> after adding this got error
} else {
return view('home');
}
There are a couple problems with the code above:
count($data) will always be greater than zero, because we're setting $data['data'] every time we call the method, so the else block will never execute. This is probably fine because...
...when count($data) equals zero, the controller doesn't pass the view any data, so $data in the view will be undefined.
The view in question uses #foreach to loop through each of the results, so we can simplify the code in the controller method because foreach won't iterate over an empty collection:
$personalInfos = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
The view will receive two variables from the method above: $personalInfos and $test. I took the liberty of renaming $data['data'] into a more meaningful variable. This becomes very important as the project grows. Here's how we can use the data in the view:
<ul>
#foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
#endforeach
</ul>
The template above outputs an unordered list as shown in the image in the question. The original table contains several row/column nesting errors and will not display the information like the question describes. As we can see, this template loops through each result in $personalInfos. If $personalInfos is empty, the list will not display any items.
If we want our controller method to handle the route with or without an ID, we'll need to tell Laravel that the ID is optional. For the route, a question mark (?) after the parameter makes it optional:
Route::get('/home/{id?}', 'HomeController#getData')->name('home');
Then, we can set a default value for the controller method that handles the route. In this case, we'll use null:
public function getData($id = null)
Of course, after we update this, we'll need to change the method to handle a null $id argument, which we use to fetch a personal_info for the view's $test variable. The question doesn't explain how the view uses $test, so I'll leave this as an exercise to the reader :)
Follow are two ways to pass multiple variables to view:
//Passing variable to view using with Method
return view('home')->with(['test'=>personal_info::find($id),'data'=>$data['data']]);
//Passing variable to view using Associative Array
return view('home', ['test'=>personal_info::find($id),'data'=>$data['data']]);

Laravel simplify a database query with relations

I'm just started to work with Laravel and think its a pretty good framework.
But there is a lot to learn and i can mostly find everything in the user guide except this part:
I'm trying to get items from my database they are sorted with a category id that relates to a other table item_catagories in this table are stored:
id
name
parent
In my url of the website I use the name of the category instead of the id.
http://example.com/catagory/subcatagory
when subcatagory has a value I want to search for the related items.
I now have it like this:
if($subcategory){
$foo = ItemCategories::where(['group' => $category, 'name'=> $subcategory])
->get()[0]->id;
$data['products'] = Items::where('category_id', $foo)->get();
}
but there must be a much simpler way to get the same results.
I hope someone can help me to understand how I can do it better
Edit
I forgot to add the relation code:
The item class:
public function categorie(){
return $this->hasOne('App\ItemCategories');
}
The categorie class:
public function items(){
return $this->belongsTo('App\Items');
}
You can use Laravel Eloquent's relationships for this. On your category model:
public function items() { return $this->hasMany('Items'); }
Once you've done that, on a category, you can do $category->items to fetch all of its related items.
Incidentally, when you do this:
->get()[0]
you can just do this:
->first()
If you wish to bring your results already populated, one way to do this is:
$foo = ItemCategories::where(['group' => $category, 'name'=> $subcategory])->with('items')->first();

store variables on user model laravel 4

my user model has 3 fields: username, password and category_id
so when i auth the auth object will have all of the 3 variables, but i want to add the name of the category that is on other model
and i get like:
$category = Category::find(Auth::user()->category_id);
$category_name = $category->name;
so the question is who can i add $category_name to the Auth::user() object, in order to retrive it every time he is logged like this:
Auth::user()->category_name
i try Session::put("category_name","Category 1") when you loggin, but when i close the windows and open it by the last closed windows, it delete that variable.
i want to store the variable since the person login, untill the person logout, but if the person has logged in and close the window and then the person re open the page the variable must be filled
You can use Eloquent Accessors
In User model
public function setCategoryNameAttribute()
{
$categoryID = $this->category_id;
$category = Category::find($categoryID);
return $category->name;
}
You can access category name like
Auth::user()->category_name
try this
in your User model add the following function
EDIT try this
public function category_name()
{
return \Cache::remember('category_' . $this->id , 60, function()
{
return $this->belongsTo('App\Category')->get();
});
}
now everytime you use
Auth::user()->category_name
you will have the name
this will eco the name in your View
{{ Auth::user()->category_name }}
NOTE : this code is not the best solution even if it worked for you, this is open for changes, i just want you to get the point that if you want to access something via Auth::user()->getname you have to add the getname function in the User model
and by the way can you show us the relation you set in you model? because that would make it easier
an exemple
if you have something like this in ur model(hasone)
public function category() {
return $this->hasOne('category');
}
you can do this
Auth::user()->category->name

Query foreign key data from Blade template

I have two models: MenuCategory and MenuItem, I want to display MenuItem data on my blade page along with its MenuCategory. I know its possible to do this by adding it to the return data in my controller however I would like to do it leveraging Eloquent instead, however I receive errors.
Here are my codes:
MenuCategory model
public function items()
{
return $this->hasMany('App\MenuItem');
}
MenuItem model
public function category()
{
return $this->belongsTo('App\MenuCategory');
}
Controller
public function show($id)
{
$item = MenuItem::findOrFail($id);
return view('menu.admin.single', compact('item'));
}
Blade Page
{{ $item->category->name }}
UPDATE:
Table menu_item
id
name
menu_category_id
Table menu_category
id
name
When using all the above I get the following error:
Trying to get property of non-object
This error is due to the naming convention of Eloquent.
Provide the optional foreign key variable in your relationship method to make it work, ie.
$this->belongsTo('App\MenuCategory', 'menu_category_id');
Probably every Item doesn't contain a related category but to make sure you may try something like this, it'll try to retrieve the name only if there is a related category is available:
{{ $item->category ? $item->category->name : 'No Name or empty string' }}
Alternatively you may try something like this:
$item = MenuItem::has('category') // check if there is a related category
->with('category') // if yes then load it with that category
->findOrFail($id);
You used a different foreign key than Laravel expect so explicitly mention it like:
public function category()
{
return $this->belongsTo('App\MenuCategory', 'menu_category_id', 'id');
}

Categories