Good day. I am building an API, in which I want to return some data. I have three tables
counsels
counsel_cases
analysis_sc
A section of the counsels table is shown below
A section of the counsel_cases is also shown below
Finally, a section of the analysic_sc is shown below.
I want that when a counsel is selected, through the counsel_id, I can fetch the cases belonging to the counsel from the counsel_cases, and then with that information, I want to be able to fetch the number of cases of such a counsel belonging to a legal head (area of practice) on the third table as shown in the design below.
How will that be possible. I have a relationship between counsel and counsel_cases though. Also, I have tried using a foreach loop as shown below, but I am unable to get the unique values of the legal_head.
public function getCounselPracticeAreas(Request $request)
{
$counsel_id = $request->route('counsel_id');
$cases = CounselCase::select('suit_number')->where('counsel_id', $counsel_id)->get();
$data = [];
foreach ($cases as $case) {
$values = AnalysisSc::select('legal_head')->where('suitno', $case->suit_number)->first();
array_push($data, $values);
}
return response()->json([
"message" => "successful",
"data" => $data
]);
}
However, this is the value I get
[![enter image description here][5]][5]
I want to get something like this:
$data : [
"legal_head" : [
"name" : "Criminal Law",
"count" : 2
]
]
Please, is this possible
I know this is quite long. And I hope I explained myself well. Thanks
you need to use SQL Joins to create a relationship between the tables and fetch the data
It looks like you're skipping using relationships in your models. Once you have your models set up, retrieving the data you need will be a lot easier with Laravel. You may want to separate your models/tables a little more and add relationships, like the following:
Models/tables:
Counsel (counsels)
id
name
LegalHead (legal_heads)
id
name
Case (cases)
id
suit_number
year
subject_matter
legal_head_id
case_counsels (This is not a model, just a relationship table)
id
case_id
counsel_id
appearing_for
role
Note: I wasn't sure how your data is structured. You can use this as start and adjust as necessary.
Relationships
The Many-Many relationship is suitable for the case counsels and you'll be able to add the role as a pivot(extra field) for the relationship.
https://laravel.com/docs/8.x/eloquent-relationships#many-to-many
Case
legal_head: belongsTo
counsels: belongsToMany with pivot for role
Counsel
cases: belongsToMany with pivot for role
Retrieving the Objects
When that is set up, you won't have to do as much query work. You can do this to get case data with counsels, legal_head and their role for each case:
$cases = Case::with('counsels','legal_head')->get();
And this to get the Legal Head names with the number of cases:
$legal_heads = LegalHead::withCount('cases')->get();
Related
i'm really new working with laravel 5.0, so I got this problem when I try to retrieve a result using a model. I have a users table, with a list of users who can be a manager or not, they can have assigned one or more companies, or none, a company table with companies which can have one or many managers, and a pivot table that I called companies_managers. I set up the relations in every model like this:
/***User model***/
public function companies()
{
return $this->belongsToMany('App\Company', 'companies_managers','id', 'manager_id');
}
and the same in Company model
public function managers()
{
return $this->belongsToMany('App\User', 'companies_managers', 'id', 'company_id');
}
I want to get the managers assigned to a company using a company id to get it, but it just gave me an huge object without the values I looking for (the names of the managers assigned to that company). This is the code that I tried:
$managers = Company::find($id)->managers();
I would appreciate any help you can give me
Using ->managers() (with the brackets) doesn't actually return the associated managers, but rather a Builder instance (the "huge object"), which you can then chain with additional parameters before finally retrieving them with ->get() (or another closure, like ->first(), ->paginate(), etc)
Using ->managers (without the brackets), will attempt to access the associated managers, and execute any additional logic to retrieve them.
So, you have 2 options:
$company = Company::with(["managers"])->findOrFail($id);
$managers = $company->managers;
Or
$company = Company::findOrFail($id);
$managers = $company->managers()->get();
Both of those will perform the necessary logic to pull the managers. ->with() and no brackets is slightly more efficient, doing it all in a single query, so bear that in mind.
You just need to split out your code;
// this will find the company based on the id, or if it cannot find
// it will fail so will abort the application
$company = Company::findOrFail($id);
// this uses the active company record and gets the managers based
// on the current company
$managers = $company->managers;
Thank you for your help guys, I solved the issue fixing the relations in the models to this:
return $this->belongsToMany('App\Company', 'companies_managers', 'manager_id', 'company_id');
and this
return $this->belongsToMany('App\User', 'companies_managers', 'company_id', 'manager_id');
The IDs that I had set were not the correct ones for belongsToMany function
And this
$managers = Company::find($id)->managers();
was a problem too, was a dumb mistake of my part. I solved the return of Builder instance using just return instead of dd(), in that way I got the values I looking for. Thanks everyone!
I'm developing a Laravel application where I have a posts table, a tags table and a post_tag table which acts as a pivot table.
Now I need to give all the tags from a post to another post. In other words I need to make:
$tags = $post->tags;
And change the post_id to each record in the pivot table. I have all the relationships already set.
EDIT: this is my code
class Post extends Model
{
public function tags()
{
return $this->belongsToMany(Tag::class)->withPivot('is_active')->withTimestamps();
}
}
class Tag extends Model { }
The main problem is that I have to keep the is_active value as it is. I just need to replace the post_id from the pivot table where post_id equals the one I want to override (I know I could make a raw query but I'm trying to avoid it)
EDIT 2:
I made it work this way but I still prefer an object oriented way
DB::table('post_tag')->where('post_id', $post_a->id)->update(['post_id' => $post_b->id]);
You can use the method updateExistingPivot of Eloquent, from the laravel documentation:
If you need to update an existing row in your pivot table, you may use updateExistingPivot method. This method accepts the pivot record foreign key and an array of attributes to update:
$user = App\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);
Try something like
$tags = $post->tags;
//convert tags to IDs only for upcoming steps
... //an array of IDs
$post->tags()->sync($tags); //remove the tags from this post
$post2->tags()->sync($tags); // add the tags to this post
This should get you to the right tracks.
Update
If it was only one, this would do
$post2->tags()->attach($tag, ['is_active' => true]);
$post2->tags()->->sync([1 => ['is_active' => true], 2 => ['is_active' => true]);
You can try to adapt the example above.
But I have no idea how to do it with an array of IDs.
I have 5 user titles, defined by booleans: CEO, executive, manager, employee & intern.
I'm building a user search API, and want to turn on/off eloquent queries, returning users with selected titles.
So if I were to search for managers and employees, the query should be
$users = User::where(function($query)
{
$query->orWhere('manager')->orWhere('employee');
})
->where([ADDITIONAL CONSTRAINTS... (like age)])->get();
The furthest I have came is:
$query = User::query();
//the respective titles are turned on by 1 and turned off by 0
if($CEO) {
$query = $query->orWhere('CEO');
}
if($executive) {
$query = $query->orWhere('executive');
}
//And so on for each title
In the end the additional where constraints get added like this:
$users = $query->where([Additional constraints])->get();
When searching for managers and employees, the final query would be:
$users = User::orWhere('manager')->orWhere('employee')
->where([ADDITIONAL CONSTRAINTS... (like age)])->get();
The result of this query is that the additional constraints are not always met, because there are orwhere queries before, which allow for unwanted instances to get selected.
I tried replacing the orWhere's with where's, but then users need to check positive for each selected title to get selected. So if I wanted to search for managers and employees, I might get none, because there isn't any user with both titles.
The goal:
I want to add all these conditional 'title-queries' together.
Put them all in one where(function($query) { $query->[all 'title-queries']; }).
Additional comments:
I know that I could also eliminate every other model instead of searching for wanted models. If I would search for managers and employees, I could set where('CEO', '!=', 1) for each unwanted title. I don't want this, because Users with two titles, like employee and interim would get excluded in some cases.
I know that I could write nested conditional queries for each scenario i.e. (manager & ceo, interim & ceo & executive and on ...), but that would take 25 queries and simply is not easily scalable (exponential more queries) if additional user titles are added.
It has to be an Eloquent solution.
Users can have multiple titles.
I have thought hard about this problem, thanks!
Maybe you can do something like this ? (with use function keyword)
<?php
$filters = ['manager', 'employee'];
$users = User::where(function($query) use($filters) {
foreach( $filters as $filter )
$query = $query->orWhere($filter);
})
->where([ADDITIONAL CONSTRAINTS... (like age)])->get();
So I have a many to many relationship between Users and Photos via the pivot table user_photo. I use belongsToMany('Photo') in my User model. However the trouble here is that I have a dozen columns in my Photo table most I don't need (especially during a json response). So an example would be:
//Grab user #987's photos:
User::with('photos')->find(987);
//json output:
{
id: 987,
name: "John Appleseed",
photos: {
id: 5435433,
date: ...,
name: 'feelsgoodman.jpg',
....// other columns that I don't need
}
}
Is it possible to modify this method such that Photos model will only return the accepted columns (say specified by an array ['name', 'date'])?
User.php
public function photos()
{
return $this->belongsToMany('Photo');
}
Note: I only want to select specific columns when doing a User->belongsToMany->Photo only. When doing something like Photo::all(), yes I would want all the columns as normal.
EDIT: I've tried Get specific columns using "with()" function in Laravel Eloquent but the columns are still being selected. Also https://github.com/laravel/laravel/issues/2306
You can use belongsToMany with select operation using laravel relationship.
public function photos()
{
return $this->belongsToMany('Photo')->select(array('name', 'date'));
}
Im assuming you have a column named user_id. Then you should be able to do the following:
public function photos()
{
return $this->belongsToMany('Photo')->select(['id', 'user_id', 'date', 'name']);
}
You have to select, the foreign key, else it will have no way of joining it.
Specifying the exact columns you want for the Photos relationship will likely end up biting you in the butt in the future, should your application's needs ever change. A better solution would be to only specify the data you want to return in that particular instance, i.e. the specific JSON response you're delivering.
Option 1: extend/overwrite the toArray() Eloquent function (which is called by toJson()) and change the information returned by it. This will affect every call to these methods, though, so it may end up giving you the same problems as doing select() in the original query.
Option 2: Create a specific method for your JSON response and call it instead of the general toJson(). That method could then do any data building / array modifications necessary to achieve the specific output you need.
Option 3: If you're working with an API or ajax calls in general that need a specific format, consider using a library such as League/Fractal, which is built for just such an occasion. (Phil is also working on a book on building APIs, and it doesn't suck.)
I started using Laravel yesterday, the ORM seems powerful. Does it have any way of updating rows in related models? This is what I tried:
Step 1: Generate a JSON object with the exact structure the database has. The JSON object has certain fields that are subarrays which represent relationships in the database.
Step 2: Send the JSON object via POST to Laravel for processing, here it gets tricky:
I can change the JSON object into an array first
$array = (array) $JSONobject;
Now I need to update, I would expect this to work:
Product::update($JSONobject->id,$array);
But because the array has subarrays, the update SQL that is executed cannot find the sub-array column in the table, it should instead look for the associated table. Can this be done? Or do I have to call the other models as well?
Thanks in advance!
This is something that Eloquent does not handle for you. The array that you supply to the update() method should contain columns only for, in your case, the Product model. You might try something like this to update relations. This is all off the top of my head and is by no means tested. Take it with a grain of salt.
$update = (array) $JSONobject;
$relations = [];
foreach ($update as $column => $value)
{
// If the value is an array then this is actually a relation. Add it to the
// relations array and remove it from the update array.
if (is_array($value))
{
$relations[$column] = $value;
unset($update[$column]);
}
}
// Get the product from the database so we can then update it and update any of the
// the products relations.
$product = Product::find($update['id']);
$product->update($update);
foreach ($relations as $relation => $update)
{
$product->{$relation}()->update($update);
}
The above code assumes that the key for your nested relation arrays is the name of the relation (method name used in your model). You could probably wrap this up in a method on your Product model. Then just call something like Product::updateRecursively($JSONobject); I'm terrible with names but you get the idea.
This probably won't work with more complex relations either. You'd have to take it a few steps further for things like many to many (or probably even one to many).