How to show data from different table in laravel? - php

Terms table
term_id
name
slug
Term_taxonomy table
term_taxonomy_id
term_id
description
i want to show all record like "term_id , name , description
my Term model
public function TermTaxonomy(){
return $this->hasOne('TermTaxonomy');
}
my TermTaxonomy model
public function Term(){
return $this->belongsTo('Term');
}
my route
$term = new Term;
$categories = $term->all(['term_id', 'name']);
foreach($categories as $category){
echo $category->term_id . " " . $category->name . " " . "description of term_id should here" ;}
trying this code but Error Undefined property: Illuminate\Database\Eloquent\Collection::$TermTaxonomy
$e = new Term;
$f = $e->all(['term_id','name']);
echo $f->TermTaxonomy->description;
}
with the above code i want to return all description of each term_id, but i am confusing why i can show description if the object just 1 , like this code below
$a = new Term;
$b = $a->all(['term_id','name'])->find(8);
echo $b->TermTaxonomy->description . "<br>"; // work return description of $b;
so what is exactly one to one relationship function ? is one to one only work when the object just 1 ?
what about in my case ? is my logic wrong to show all description using relationship method ? then what must i do to show term id , name , description lists ?
thanks in advance, i am totally newbie in laravel.

You can't access relationships on collections directly. I mean, what would you even expect? All descriptions as comma separated list?
Instead you just access the relation when you loop over all of them anyways. (That's probably in the view so I'm going to use Blade syntax in this example)
#foreach($terms as $term)
{{ $term->term_id }} {{ $term->name }} {{ ($term->TermTaxonomy ? $term->TermTaxonomy->description : '') }}
#endforeach
($term->TermTaxonomy ? $term->TermTaxonomy->description : '') is a shorthand if. It means:
if($term->TermTaxonomy){
echo $term->TermTaxonomy->description;
}
else {
echo '';
}
It works because if the Term has no TermTaxonomy assigned, $term->TermTaxonomy will be null. With this code we only try to access ->description if TermTaxonomy exists and can therefore avoid a Trying to get property of non-object exception.
Attention: While this works you definitely should eager load the TermTaxonomy relationship. You see if we leave it like that, each time you do $term->TermTaxonomy a DB query will be run. To avoid n+1 queries, use with to eager load relationships:
$terms = Term::with('TermTaxonomy')->get(['term_id','name']);
Regarding your question in the comments, yes you can limit the fields that you select from term_taxonomy:
$terms = Term::with(['TermTaxonomy' => function($q){
$q->select('term_id', 'description');
}])->get(['term_id','name']);
Just make sure you include the columns necessary to make the relationship (in this case term_id)

If you do a $e-all, you get an array with the TermTaxanomies. When you do a specific search (->find(8)) you only get that object with id = 8.
All you need to do is use a foreach or use an index number:
$f = $e->all(['term_id','name']);
foreach($f as $tax){
var_dump($tax);
}
Or
$f = $e->all(['term_id','name']);
var_dump($f[1]);
var_dump($f[4]);
I think that should work.

oops! Looks like you're trying to implement raw php code into Laravel. Please get rid of that , follow the instructions bellow.
make a Route:
Route::get('/term' , array('uses' => 'TermsController#showTerm'));
Now make a Controller named TermsController.php and try something like bellow:
<?php
class TermsController extends BaseController {
public function showTerm(){
$terms = Term::all();
return View::make('show_term.blade.php')->with('terms' , $terms);
}
}//class ends
Now make a Model named Term.php :
<?php
class Terms extends \Eloquent{
protected $fillable = array();
protected $table = 'terms'; //terms is your database table name
}?>
Now make a show_term.blade.php :
#extends(layouts.master)
#section('content)
foreach($terms as term){
{{$term->id}} , {{$term->name}} , {{$term->slug}}}
#stop
if you don't have the layouts.master then create a layouts folder inside you View folder. Then create a master.blade.php write the basic html and inside the body try like this:
<div class="container">
#yield('content')
</div>
Thank you . Let me know if you need anything else.

Related

How to fetch product name from orders table which contain product_id in laravel?

I am unable to fetch the product name according to matching id but i am getting same name in table as shown below
this is the ordered list of products
Please check table for reference ill be showing below (order_list table)
order_list table
Table products
products table
My Controller
public function details($id)
{
$orders = Order_model::find($id);
$Order_lists = Order_list::orderBy('id', 'asc')->where('user_id', '=', Auth::user()->id)->where('order_id', '=', $id)->get();
foreach($Order_lists as $order_list)
{
$prod_name = DB::table("products")->where('id', $order_list->product_id)->value('name');
}
$address = DB::table("delivery_address")->where('user_id', '=', Auth::user()->id)->get();
if(Auth::user()->role == 'customer')
{
return view('customer.orders.details',['Order_lists' => $Order_lists, 'orders' => $orders, 'address' => $address, 'prod_name' => $prod_name]);
}
}
please Help me out as i am at learning stage and any help would be glad to hear thanks.
the problem is $prod_name is a single variable and you running it in loop. so it only replace every iteration and just get last iteration name. so if you want get every product name with $order_list , you can easily create Model for products table. then
create one to one Order_list. eg:
https://laravel.com/docs/7.x/eloquent-relationships#one-to-one
class Order_list extends Model
{
public function products()
{
return $this->hasOne('App\Products',"product_id"); //your model name and path
}
}
then you can get all order list data with product like this:
$Order_lists = Order_list::orderBy('id', 'asc')->where('user_id', '=', Auth::user()->id)->where('order_id', '=', $id)->with('products')->get();
product details should in $Order_lists[0]->products->name
edit: to run this in blade file
#foreach($Order_lists as $Order_list)
////other <td>s
<td>{{$Order_list->products->name}}</td>
#endforeach
if above method is complex you can create separate array to name
$prod_name =[];
foreach($Order_lists as $order_list)
{
$prod_name[$order_list->product_id] = DB::table("products")->where('id', $order_list->product_id)->value('name');
}
then read it on blade file like this:
{{$prod_name[$order_list->product_id]}}
edit:
to print elements in second method you can use blade syntax.
first send veriables to .blade file
eg: view('your.blade.php,compact('Order_lists','prod_name'));
//then print in .blade file
#foreach($Order_lists as $Order_list)
////other <td>s
<td>{{$prod_name[$order_list->product_id]}}</td>
#endforeach

How to have multiple selected item in drop-down if saved in id laravel?

I am selecting the multiple id of classes in creating leadtype via explode,how can i get all the selected id of classes in dropdown in edit function
Classes table
id 1 name class one
id 2 name class two
id 3 name class three
Leadtype table
id 1 class_id 1,2,3,
id 2 class_id 1,2
id 3 class_id 2,1
I am saving only id of classes in leadtype table but when i edit i want
all the value selected instead of id
my route
Route::get('admin/leadtypes/form', 'LeadTypesController#form'); add
Route::post('admin/leadtypes/post', 'LeadTypesController#update'); store
Route::get('admin/leadtypes/form/{id}', 'LeadTypesController#editForm'); edit
Add function
public function form() {
$classes = Classes::pluck('name','id');
return view('leadtypes.form',$data,compact('classes'));
}
My store/update function
public function update(Request $request)
{
$data = \Input::except(array('_token')) ;
$rule=array(
'name' => 'required',
);
$validator = \Validator::make($data,$rule);
if ($validator->fails())
{
return redirect()->back()->withInput()->withErrors($validator->messages());
}
$inputs = $request->all();
if(!empty($inputs['id'])){
$item = LeadTypes::findOrFail($inputs['id']);
}else{
$item = new LeadTypes;
}
if(is_array($request->name)){
$item->name = implode(',', $request->name);
}
$item->status = $inputs['status'];
$item->save();
flash('success','record_added_successfully', 'success');
return redirect('admin/leadtypes');
}
edit function
public function editForm($id)
{
$item = LeadTypes::findOrFail($id);
$data['active_class'] = 'Lead type';
$data['title'] = getPhrase('Lead type');
$classes = Classes::pluck('name','id');
$item->name = explode(',', $item->name);
return view('leadtypes.form',$data,compact('item','classes'));
}
My view dropdown
{!! Form::select('name[]', $classes, !empty($item->name) ? $item->name : explode(',',old('name')) ,['class' =>'form-control ' ,'required'=>'true','multiple'=>'true']); !!}
I think you may be pushing the LaravelCollective Form::() method to a place it's not happy with. It is a bit finicky to start, and there are a few issues with what you have above.
The $item->name is actually a string as stored, I think. If it is set in the DB, it is going to come through to your last line of code as a string:
!empty($item->name) ? $item->name : explode(...)
You need to explode the DB-stored string in the FIRST part of your operation above as well, to get this to match whatever the $classes array is for the second parameter in that same statement. String <--> array won't work, and thus won't ever allow for a value to be selected from the model.
I'm pretty sure this will solve it. However, I would also possibly reconsider your architecture on this. Storing those arrays of IDs in a single field (and a field named singular 'name') is a little confusing, and is also making life difficult for you. Perhaps consider pulling those LeadTypes into their own belongsToMany relationship with their own sub table. Then you can just store the two ids and simplify everything. If that works -- but the above should answer your question.

Limit related records in polymorphic many-to-many relationship with Laravel

I am using Laravel 5.1 and I need to limit the number of related records I am pulling using a polymorphic many-to-many relationship.
What I would like to do is get a list of categories by parent_id. For each category then I'd like to only pull four posts.
I have have this working with the code below, but it results in a bunch of extra queries. I'd like to just hit the database once if possible. I'd like to use the Laravel/Eloquent framework if at all possible, but am open to whatever works at this point.
#foreach ($categories as $category)
#if ($category->posts->count() > 0)
<h2>{{ $category->name }}</h2>
See more
{-- This part is the wonky part --}
#foreach ($category->posts()->take(4)->get() as $post)
{{ $post->body }}
#endforeach
#endif
#endforeach
PostsController
public function index(Category $category)
{
$categories = $category->with('posts')
->whereParentId(2)
->get();
return view('posts.index')->with(compact('categories'));
}
Database
posts
id - integer
body - string
categories
id - integer
name - string
parent_id - integer
categorizables
category_id - integer
categorizable_id - integer
categorizable_type - string
Post Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function categories()
{
return $this->morphToMany('App\Category', 'categorizable');
}
Category Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function category()
{
return $this->belongsTo('App\Category', 'parent_id');
}
public function subcategories()
{
return $this->hasMany('App\Category', 'parent_id')->orderBy('order', 'asc');
}
public function posts()
{
return $this->morphedByMany('App\Post', 'categorizable');
}
I have seen a number of links to this on the web, but nothing that has actually worked for me.
I have tried this solution without any luck.
$categories = $category->with('posts')
->whereParentId(2)
->posts()
->take(4)
->get();
I have looked into this solution by Jarek at SoftOnTheSofa, but it is for a hasMany relationship and to be honest is a bit beyond my sql skill for me to adapt it for my needs.
Edit
I added a github repo for this setup, if it is useful to anybody.
Edit your Category model
public function fourPosts() {
// This is your relation object
return $this->morphedByMany('App\Post', 'categorizable')
// We will join the same instance of it and will add a temporary incrementing
// Number to each post
->leftJoin(\DB::raw('(' . $this->morphedByMany('App\Post', 'categorizable')->select(\DB::raw('*,#post_rank := IF(#current_category = category_id, #post_rank + 1, 1) AS post_rank, #current_category := category_id'))
->whereRaw("categorizable_type = 'App\\\\Post'")
->orderBy('category_id', 'ASC')->toSql() . ') as joined'), function($query) {
$query->on('posts.id', '=', 'joined.id');
// And at the end we will get only posts with post rank of 4 or below
})->where('post_rank', '<=', 4);
}
Then in your controller all categories you get with this
$categories = Category::whereParentId(1)->with('fourPosts')->get();
Will have only four posts. To test this do (remember that now you will load your posts with fourPosts method, so you have to access the four posts with this property):
foreach ($categories as $category) {
echo 'Category ' . $category->id . ' has ' . count($category->fourPosts) . ' posts<br/>';
}
In short you add a subquery to the morph object that allows us to assign temporary incrementing number for each post in category. Then you can just get the rows that have this temporary number less or equal to 4 :)
Does this work for you?:
$categories = $category->with(['posts' => function($query)
{
$query->take(4);
})
->whereParentId(2)
->get();
I think the most cross-DBMS way to do this would be using union all. Maybe something like this:
public function index(Category $category)
{
$categories = $category->whereParentId(2)->get();
$query = null;
foreach($categories as $category) {
$subquery = Post::select('*', DB::raw("$category->id as category_id"))
->whereHas('categories', function($q) use ($category) {
$q->where('id', $category->id);
})->take(4);
if (!$query) {
$query = $subquery;
continue;
}
$query->unionAll($subquery->getQuery());
}
$posts = $query->get()->groupBy('category_id');
foreach ($categories as $category) {
$categoryPosts = isset($posts[$category->id]) ? $posts[$category->id] : collect([]);
$category->setRelation('posts', $categoryPosts);
}
return view('posts.index')->with(compact('categories'));
}
And then you'd be able to loop through the categories and their posts in the view. Not necessarily the nicest looking solution but it would cut it down to 2 queries. Cutting it down to 1 query would probably require using window functions (row_number(), in particular), which MySQL doesn't support without some tricks to emulate it (More on that here.). I'd be glad to be proven wrong, though.
Here's a "half answer". The half I give you is to show you the MySQL code. The half I can't give you is translating it into Laravel.
Here's an example of finding the 3 most populous cities in each province of Canada:
SELECT
province, n, city, population
FROM
( SELECT #prev := '', #n := 0 ) init
JOIN
( SELECT #n := if(province != #prev, 1, #n + 1) AS n,
#prev := province,
province, city, population
FROM Canada
ORDER BY
province ASC,
population DESC
) x
WHERE n <= 3
ORDER BY province, n;
More details and explanation are found in my blog on groupwise-max.
I think the best option (without using raw queries) would be to setup a custom method to be used with the eager loading.
So in the Category model you could do something like:
<?php
public function my_custom_method()
{
return $this->morphedByMany('App\Post', 'categorizable')->take(4);
}
And then use that method when eager loading:
<?php
App\Category::with('my_custom_method')->get();
Make sure to use my_custom_method() instead of posts() in your view:
$category->my_custom_method()
You can try this one, that work for me!
$projects = Project::with(['todo'])->orderBy('id', 'asc')->get()->map(function($sql) {
return $sql->setRelation('todo', $sql->todo->take(4));
});

Retrieving relation of users and usermeta table from wordpress database using Eloquent

I am trying to access a user's first_name in my custom script which uses Eloquent to retrieve data (in Laravel 5 actually )
So,
Here is how i defined relationship (one to many ) // is that correct ?? Wp Guru may tell
In User Model, i have
public function usermeta() {
return $this->hasMany('App\Usermeta','user_id');
}
In my UserController I have
$users = \App\User::with('usermeta')->get();
And here how i access it in my views
#foreach ($users as $user)
<tr>
<th>{{$user->ID}}</th>
<th>{{$user->usermeta->/*how to access particular meta key here*/}}</th>
<th>{{$user->display_name}}</th>
</tr>
#endforeach
So the problem is, everything works except when i try to access the usermeta relation, I'm actually not sure how to query a particular meta key's value by passing meta_key as an argument either in my relation or in foreach loop
I tried directly accessing like $user->usermeta->first_name but that is incorrect for sure.
How can i retrive the meta_value from a usermata table in wordpress database using Eloquent Model?
Edit 1
trying the accessor method approach by #james-flight
https://stackoverflow.com/a/30871346/1679510
It works when i know the position of the record in collection object.
if ($usermeta->count() > 0) {
return $usermeta[0]->meta_value;
}
However, since the meta_key can be anything, and may reside at other position.
if the meta_key is first_name , then $usermeta[1] have the array of column values for it, and so on.
if ($usermeta->count() > 0) {
return $usermeta[/*This cannot be hard code */]->meta_value;
}
How to get it resolved
Usermeta is a hasMany relationship, which means Eloquent will return a Collection object containing multiple Usermeta models.
You could instead do this:
{{ $user->usermeta[0]->first_name }}
Or this:
#foreach($user->usermeta as $usermeta)
{{ $usermeta->first_name }}
#endforeach
Edit
To use meta_key and meta_value as a key value pair, you could write an accessor method on User:
public function getMetaValue($key) {
$usermeta = $this->usermeta->filter(function ($usermeta) use ($key) {
return $usermeta->meta_key === $key;
});
if ($usermeta->count() > 0) {
return $usermeta[0]->meta_value;
}
}
And then access in blade like so:
{{ $user->getMetaValue('first_name') }}
This will get slow at high volume though.
Edit 2
The above method should in fact be as follows, to ensure the array key exists:
public function getMetaValue($key) {
$usermeta = $this->usermeta->filter(function ($usermeta) use ($key) {
return $usermeta->meta_key === $key;
});
if ($usermeta->count() > 0) {
return $usermeta->first()->meta_value;
}
}

How to retrieve information from an association table using Idiorm and Paris with only one query?

I am using Paris (which is built on top of Idiorm).
I have the following Model classes (example inspired from the documentation on github):
<?php
class Post extends Model {
public function user() {
return $this->belongs_to('User');
}
}
class User extends Model {
public function posts() {
return $this->has_many('Post'); // Note we use the model name literally - not a pluralised version
}
}
So now I can do the following (works well):
// Select a particular user from the database
$user = Model::factory('User')->find_one($user_id);
// Find the posts associated with the user
$posts = $user->posts()->find_many();
// Select a particular post from the database
$post = Model::factory('Post')->find_one($post_id);
// Find the user associated with the post
$user = $post->user()->find_one();
But I'd like to do the following aswell:
$posts = Model::factory('Post')->find_many();
foreach ($posts as $post) {
echo($post->user()->find_one()->username); // generates a query each iteration
}
Unfortunately this creates a query for each iteration. Is there a way to tell Paris or Idiorm to take the associated information in the first find_many query ?
How are you supposed to retrieve information with Paris to minimize the numbers of query ? I'd like not to have to manually specify the join condition (this is the reason why I am using Paris and not Idiorm)
I am the current maintainer of the Paris and Idiorm projects. Unfortunately what you describe here is a case for a custom query and not something that Paris was ever built to solve. The philosophy of Paris and Idiorm is to stick as close to the 80/20 principle as possible and your use case is in the 20.
It would be interesting to know how you ended up solving this problem.
I've had exactly the same problem, and ended up with this (a bit ugly) solution:
$posts = Model::factory('Post')...->limit($perpage)->find_many();
$user_ids = $user_lookup = array();
foreach($posts as $post) $user_ids[] = $post->user_id;
$users = Model::factory('User')->where_id_in($user_ids)->find_many();
foreach($users as $user) $user_lookup[$user->id] = $user;
Only 2 selects. And later in template:
{% for post in posts %}
<h2>{{ post.title }}</h2>
by author: {{ user_lookup[post.user_id].username }}
{% endfor %}
But it only works if you don't have hundreds of posts showing on one page.

Categories