laravel querying multiple classes and or tables - php

How do I query more than two tables. What I want to do is have a list of products queryed by a genre and then query productvariations - where a product variation has a producttype_id = $producttype->id
Route::get('browse/{producttype_slug}/{genre_slug}', array(
'as' => 'products.viewbygenre',
function($productype_slug, $genre_slug)
{
$producttype = ProductTypes::where('slug', '=', $productype_slug)->firstOrFail();
$genre = GenreTypes::where('slug', '=', $genre_slug)->firstOrFail();
// error below
$products = Product::with(array('ProductVariations', 'GenreTypes'))
->where('genre', '=', $genre->id)->get();
return View::make('products.viewbygenre')->with(compact('productvariations', 'genre', 'producttype'));
}))->where('producttype_slug', '[A-Za-z\-]+')->where('genre_slug', '[A-Za-z\-]+');
products class
class Product extends \Eloquent {
protected $table = "products";
protected $fillable = ['keywords', 'description', 'title', 'slug', 'release_date', 'clip'];
public function productvariations() {
return $this->hasMany("ProductVariations");
}
public function variations() {
$variations = $this->productvariations()->get();
return $variations;
}
public function genres() {
return $this->belongsToMany('GenreTypes', 'product_genretypes', 'product_id', 'genretype_id')->withTimestamps();
}
}

I didn't quite understand the issue so I will just refer to this bit:
// error below
$products = Product::with(array('ProductVariations', 'GenreTypes'))
->where('genre', '=', $genre->id)->get();
I believe you cannot use a where clause this way on a 'with' array. I am not 100% sure if this works when you have more than one parameter in your with method but this is worth trying:
$products = \Product::with(array('ProductVariations', 'GenreTypes' => function ($query)
{
// Note I think you also had a mistake in your column name
// (genre should be genretype_id?)
// Also ... not sure how you are getting the $genre->id variable
// as I cannot see the the $genre object / collection in this method you provided !
$query->where('genretype_id', '=', $genre->id);
}))->get();
Let us know how you get on.

Related

How to get relationship counts without loading objects in laravel

I have a model customer and it has many projects. I want to find projects count without including its object.
Customer model includes:
public function numberOfProjects()
{
return $this->hasMany(Project::class)->count();
}
Query in my controller:
$customers = Customer::where(['is_active'=>1])
->with(['customerContactInformation'=> function ($query) {
$query->where('is_active',1);
}, 'numberOfProjects'])
->skip($skip)->take(10)
->get();
Its giving me error:Call to a member function addEagerConstraints() on integer
Try this
Customer Model
public function numberOfProjects()
{
return $this->hasMany(Project::class);
}
Controller
$customers = Customer::where(['is_active'=>1])
->with(['customerContactInformation'=> function ($query) {
$query->where('is_active',1);
}])
->withCount('numberOfProjects') //you can get count using this
->skip($skip)
->take(10)
->get();
That should be work
$customers = Customer::withCount('numberOfProjects')->get();
WithCount on the particular status
$customers = Customer::withCount([
'numberOfProjects',
'numberOfProjects as approved_count' => function ($query) {
$query->where('approved', true);
}
])
->get();
class Tutorial extends Model
{
function chapters()
{
return $this->hasMany('App\Chapter');
}
function videos()
{
return $this->hasManyThrough('App\Video', 'App\Chapter');
}
}
And then you can do:
Tutorial::withCount(['chapters', 'videos'])
Counting Related Models
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models. For example:
$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
You may add the "counts" for multiple relations as well as add constraints to the queries:
$posts = App\Post::withCount(['votes', 'comments' => function ($query) {
$query->where('content', 'like', 'foo%');
}])->get();
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;
You may also alias the relationship count result, allowing multiple counts on the same relationship:
$posts = App\Post::withCount([
'comments',
'comments as pending_comments_count' => function ($query) {
$query->where('approved', false);
}
])->get();
echo $posts[0]->comments_count;
echo $posts[0]->pending_comments_count;
If you're combining withCount with a select statement, ensure that you call withCount after the select method:
$posts = App\Post::select(['title', 'body'])->withCount('comments');
echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;

How to get next and previous records from a model with a parent child relationship

I have a parent child relationship in my model where a Section can have many subsections. so in my model I have joined the table onto itself and using a parent column I can determine which section is a parent / child.
My question is how would I retrieve the next and previous records for the subsections?
My Section model:
class Section extends Model
{
use BelongsToSortedManyTrait, SortableTrait;
public $fillable = [
'id',
'name',
'description',
'parent',
'position'
];
public function subsections() {
return $this->hasMany(self::class, 'parent')->sorted();
}
public function next(){
// get next record
return self::where('id', '>', $this->id)->orderBy('id','asc')->first();
}
public function previous(){
// get previous record
return self::where('id', '<', $this->id)->orderBy('id','desc')->first();
}
}
Notice the previous and next methods, at the moment they will work for all sections but won't take into account the parent / child relationship.
Any way I can achieve this?
This has not been tested but try:
self::where('parent', $this->parent)
->where('id', '<', $this->id)
->orderBy('id','desc')
->first();
Adding the parent to the query will restrict the next value to those with the same parent ID. You can then use like this:
$subsection = Section::find(2);
$next = $subsection->next();
$prev = $subsection->previous();
Furthermore, it may be better to make next and previous parent query optional:
public function next($parent = false) {
$query = self::query();
if ($parent) {
$query = $query->where('parent', $this->parent);
}
$query = $query->where('id', '<', $this->id)
->orderBy('id','desc')
->first();
}
This will allow you to check the next and previous section as well as subsections.
All the best.
Update (API solution - this has not been tested)
$section = Section::find($id); // Whatever the section id is;
$subsection = Section::where('parent', $section->id)->first();
return [
'section' => $section,
'next_section' => $section->next()->id,
'prev_section' => $section->prev()->id,
'subsection' => $subsection,
'next_subsection' => $subsection->next(true)->id,
'prev_subsection' => $subsection->prev(true)->id,
];
On the next section call, you can then pass the subsection id and run next/prev before returning the api:
$subsection = Section::find(1)->next();
Try this:
public function next(){
$id = $this->parent ?: $this->id;
return self::where('id', '>', $id)->orderBy('id','asc')->first();
}
public function previous(){
$id = $this->parent ?: $this->id;
return self::where('id', '<', $id)->orderBy('id','desc')->first();
}

Laravel 5.4: Storing the 'Where' clause in a variable

I want to write a dynamic update query in Laravel which accepts arguments and can be used in whole project.
Following is my Controller function:
public function editquery(Request $request)
{
$city_id = $request->input('city_id');
$city_name = $request->input('city_name');
$tbl = 'city';
$data = ['city_name'=>$city_name];
$wher = ('city_id',1);
General_model::editrecord($data,$wher,$tbl);
return redirect()->action('Admin_controller#cities_page')->with('status','Record Updated Successfully!');;
}
Below is my Model function:
public static function editrecord($data,$wher,$tbl)
{
return DB::table($tbl)->where($wher)->update($data);
}
The only problem here is that I cannot store the value ('city_id',1) in the $wher variable. This is the screenshot of the error:
link to the image file
Is there any other way to do this. Please Help.
The where method accepts an array of conditions.
$table = 'city';
$conditions = [
['city_id', '=', '1']
];
$data = ['city_name' => $city_name];
General_model::editRecord($table, $conditions, $data);
// In your model
public static function editRecord($table, $conditions, $data)
{
return DB::table($table)->where($conditions)->update($data);
}
You can also set multiple conditions.
$conditions = [
['city_id', '=', '1'],
['test', '=', 'test'],
];
Edit
This is the default where method
where($column, $operator = null, $value = null, $boolean = 'and')
Setting the fourth parameter to or will make the condition orWhere.
Example
$conditions = [
['city_id', '=', '1'],
['test', '=', 'test', 'or'],
];
You can't do this
public static function editrecord($data,$wher,$tbl)
{
return DB::table($tbl)->where($wher)->update($data);
}
Since, where is a function; it expects 2 or 3 arguments and not just 1 argument.
You will have to pass both the arguments like so
public static function editrecord($data, $where_column, $where_val, $tbl)
{
return DB::table($tbl)->where($where_column, $where_val)
->update($data);
}
Then, in your controller function
$where_column = 'city_id';
$where_val = 1;
General_model::editrecord($data,$where_column,$where_val,$tbl);
Your code is not exactly in the style of Laravel, why would you want to create a separate static function, if such tasks are easily solved by the standard features of Eloquent / Query Builder?
Eloquent example:
app/City.php
<?php
class City extends Model {
protected $table = 'city';
protected $primaryKey = 'city_id';
protected $fillable = ['city_name'];
}
In your controller:
City::findOrFail($city_id)->update([
'city_name' => $city_name
]);
Query Builder example:
DB::table('city')->where(['city_id' => $city_id])->update([
'city_name' => $city_name
]);
This is much easier to read, understand and support than functions that do similar things in an incomprehensible way.

Add a new item on laravel 4 using different tables

This is my Items model . Now i want to add a new item but i get this error: SQLSTATE[23000]: Integrity constraint violation: 1048
<?php
class Items extends Eloquent
{
protected $guarded = [
'id',
];
protected $fillable = [
'name',
'description',
'price',
'brand',
];
protected $table = 'items';
public function user()
{
return $this->hasOne('User', 'user_ID', 'id');
}
public function size()
{
return DB::table('sizes')->select('size')
->where('id', $this->size_ID)->first()->size;
}
public function color()
{
return DB::table('colors')->select('color')
->where('id', $this->color_ID)->first()->color;
}
public function condition()
{
return DB::table('conditions')->select('type')
->where('id', $this->condition_ID)->first()->type;
}
public function category()
{
return DB::table('categories')->select('category')
->where('id', $this->category_ID)->first()->category;
}
public function images()
{
return DB::table('images')->select('image')
->where('item_id', $this->id)->first()->image;
}
}
And this is my post method to save item.
public function store()
{
$item = new Items;
$item->user_ID = Auth::id();
$item->name = Input::get('name');
$item->description = Input::get('description');
$item->price = Input::get('price');
$item->brand = Input::get('brand');
$item->category = Input::get('Category');
$item->condition = Input::get('Condition');
$item->color = Input::get('Color');
$item->save();
}
Here is a picture of category table , condition and color table has the same logic.
http://imgur.com/9NCMYui
You are creating a relationship between User and Item while not using it.
You can set the populate the relationship manually by filling in the id yourself, but then you don't use the power of the Eloquent ORM.
What I would suggest is getting the current user.
And saving it like this.
$item->user()->save($user);
I suggest for the name of the class Item and not Items.
I find it having much more logic and so do most of the programmers.
The table can still be called items.

Ordered Results Set within a relationship using Laravel

I have a table structure that has this structure:
User (has many) Subjects (has many) Modules (has many) Topics (has many) Notes
I have foreign keys in each table like so:
Subject (user_id), Modules(subject_id), Topics(module_id), Notes(topic_id)
I want to have a way to access all the notes created by a user ordered by the date created. Is this possible using the query builder?
Note.php
class Note extends Model implements SluggableInterface
{
use SluggableTrait;
protected $sluggable = [
'build_from' => ['question', 'id'],
'save_to' => 'slug'
];
protected $fillable = ['question', 'answer', 'topic_id'];
public function topic()
{
return $this->belongsTo('App\Topic');
}
}
Topic.php
class Topic extends Model implements SluggableInterface
{
use SluggableTrait;
protected $sluggable = [
'build_from' => ['title', 'id'],
'save_to' => 'slug'
];
protected $fillable = ['title', 'module_id'];
public function notes()
{
return $this->hasMany('App\Note');
}
public function module()
{
return $this->belongsTo('App\Module');
}
}
There are a few ways to do this. If you wish to use your relationships, you will need to nest a few loops to make your way through the entire "tree" of relationships.
$user = User::with('subjects.modules.topics.notes')->find($user_id);
$notes = new Illuminate\Database\Eloquent\Collection;
foreach($user->subjects as $subject) {
foreach($subject->modules as $module) {
foreach($module->topics as $topic) {
foreach($topic->notes as $note) {
$notes->add($note);
}
}
}
}
$notes = $notes->sortBy('created_at');
As for making it easier through database design, that's a tough question without knowing what the rest of your app is doing. If this is the only place where you have any notes, then I would say probably it's the ideal solution. If other places need notes too, then it might be a problem.
Another approach would have to been to use the query builder which wouldn't require you to loop through any result sets but would require you write the sql. I wouldn't say it's simpler or easier though.
$notes = \DB::table('users')
->select('notes.*')
->join('subjects', 'users.id', '=', 'subjects.user_id')
->join('modules', 'subjects.id', '=', 'modules.subject_id')
->join('topics', 'modules.id', '=', 'topics.module_id')
->join('notes', 'topics.id', '=', 'notes.topic_id')
->where('users.id', $user_id)
->get();
I am not 100% sure because of naming conventions:
$user = User::with(['subjects.modules.topics.notes' => function($query)
{
$query->orderBy('created_at')
}])->whereId($user_id)->first();
dd($user);
Give me feedback in comments what you get.

Categories