How to eager loading with laravel on a different naming convention - laravel

I have two tables. 'weeks' and 'dates'
The weeks table holds an 'startDate' and an 'endDate' Both columns a foreignKeys to the dates columns. The dates table holds an primary key id and the date.
weeks
| IDweeks | startDate | endDate |
| 1 | 2 | 6 |
dates
| IDdates | date |
| 1 | 12-03-2018 |
| 2 | 13-03-2018 |
.....
When I query the weeks, I always get the keys for startDate and endDate. I would like to get the values from the dates tables instead.
I´ve already tried to eager load the values like this:
weeks Modal
class weeks extends Model
{
//....
public function startDate()
{
return $this->belongsTo('App\date', 'startDate', 'date');
}
public function endDate()
{
return $this->belongsTo('App\date', 'endDate', 'date');
}
//....
dates Modal
class date extends Model
{
protected $primaryKey = 'IDdates';
calling the 'with()' method
public function showWeeks() {
$weeks = weeks::with('startDate')->get();
return view('weeks')->with('weeks', $weeks);
}
using in the view
#foreach ($weeks as $week )
{{ $week->startDate->date }} // produces an error like: Trying to get property 'date' of non-object
{{ $week->startDate }} // works but returns only the keys instead of the value of dates table.
#endforeach
How can I load the results of the dates table when calling the weeks?
EDIT: edited a typo in the title

Related

belongsToMany in v7 returns an empty array

My client has an old site built on 4.x that I'm trying to get to work with 7.4. I have most of it working, but am stuck on a belongsToMany relationship
I have a Manufacturer class that has a many-to-many relationship with Subcategories, through a table named membercategory. However, the subcategories property always returns an empty array. What am I missing?
membercategory
+------+------------------+-----------------+
| ID | FKManufacturerID | FKSubCategoryID |
+------+------------------+-----------------+
| 3203 | 24 | 301 |
| 3202 | 24 | 292 |
| 3201 | 24 | 295 |
+------+------------------+-----------------+
and my Manufacturer class
class Manufacturer extends Model {
public function subcategories() {
# have tried swapping the two FK parameters, same result
return $this->belongsToMany('App\Subcategory','membercategory','FKSubCategoryID','FKManufacturerID');
}
}
I'm testing it in my controller using this
dd($manufacturers[0]->subcategories);
where $manufacturers[0] returns the object for Manufacturer ID=24
According to the documentation, your code should look like this:
class Manufacturer extends Model {
public function subcategories() {
return $this->belongsToMany('App\Subcategory','membercategory','FKManufacturerID','FKSubCategoryID');
}
}
Looking at the belongsToMany signature:
public function belongsToMany(
$related,
$table = null,
$foreignPivotKey = null,
$relatedPivotKey = null,
$parentKey = null,
$relatedKey = null,
$relation = null) {}
You will see that you need to have the related column in the 4th param and the foreign one in the 3rd.
EDIT
Make sure the types of columns in the model tables and the pivot table match.
Furthermore, according to the belongsToMany signature, you should add the parentKey and relatedKey params if they are not the default: id ( ID != id )
Here is a list of eloquent model conventions in Laravel 7.x and you can see:
Eloquent will also assume that each table has a primary key column named id. You may define a protected $primaryKey property to override this convention:
That means that provided both your model tables have the primary key columns named "ID" ( as you showed you do in the chat ) your code should look like this:
class Manufacturer extends Model {
public function subcategories() {
return $this->belongsToMany(
'App\Subcategory',
'membercategory',
'FKManufacturerID',
'FKSubCategoryID'
'ID',
'ID'
);
}
}
Just replace the positions of third and fourth columns like this:
return $this->belongsToMany('App\Subcategory', 'membercategory', 'FKManufacturerID', 'FKSubCategoryID');

How to query a table based on criteria of another table in Laravel?

In my laravel project I have an inventory and a medicine table which the formats are as the following:
Inventory Table
id | medicine_id | expiry_date
-------|-----------------|-------------
1 | 1 | 13-11-2021
2 | 2 | 01-01-2020
3 | 2 | 23-05-2024
Medicine Table
id | name | category
-------|-----------------|-------------
1 | Hemophine | Syringe
2 | andrenalin | Tablet
3 | aspirin | Capsule
The models are set as below:
Inventory Model
class Inventory extends Model
{
public $incrementing = false;
public function medicine(){
return $this->belongsTo('App\Medicine', 'medicine_id');
}
}
Medicine Model
class Medicine extends Model
{
public $incrementing = false;
public function inventory(){
return $this->hasMany('App\Inventory', 'medicine_id');
}
}
For retrieving all the inventories with a specific category such as Syringe, I tried eager loading, but couldn't figure out the flaws. Here is what I did to get all the inventories with a Syringe category, but it didn't work.
public function index()
{
$medicines = Inventory::where('medicine_id'->category, "Syringe")->get();
foreach($medicines as $medicine){
echo $medicine->medicine->name ." ".$medicine->expiry_date;
echo "<br>";
}
}
Now, Is there anyway to get all the inventory items based on their categories they are in? in this case in "Syringe" category?
Your syntax is a bit wrong, in order to load the medicine for each inventory you need to use with and the where function is where('column', value)
So change it to this:
$medicines = Inventory::with([
'medicine' => function($query) {
$query->where('category', "Syringe");
}
])->get();
or even better the other way around:
$medicines = Medicine::with('inventory')->where('category', 'Syringe')->get();

How to combine models and order by model two data in Laravel 5.4

I would like to be able to output leaders in a section by their position in a group. I'm thinking of combining these tables through a pivot table ordered by position from the groups table.
These are the three class I have relationships established
class Leader extends Model
{
public function groups()
{
return $this->belongsToMany('App\Group');
}
}
class Group extends Model
{
public function leaders()
{
return $this->belongsToMany('App\Leader');
}
}
class GroupLeader extends Model
{
// Maybe some function here?
}
I would like to be able to get the groups in the controller and pass them individually kinda like this.
$group1 = Leader::where('group', '=', 'group1_name')->orderBy('position', 'asc');
$group2 = Leader::where('group', '=', 'group2_name')->orderBy('position', 'asc');
return view('page.leadership')->with([
'group1' => $group1,
'group2' => $group2,
]);
Then I would pass the variables to include files which would loop through them in order.
Here is my table structure
leaders
--------
| id
| first_name
| last_name
| deceased
----------
groups
----------
| id
| group
| title
| position
-----------
group_leader
-------------
| id
| group_id
| leader_id
------------
Try it
$groups = Leader::whereIn('group', ['group1_name', 'group2_name'])
->orderBy('position', 'asc')
->groupBy('group', 'id')
->get(['group', 'id']);

Restructuring database and multiple views for model

I have a system where a user can input data into various forms and generate a custom document. When I set everything up, because each form has unique data, I create a Model/Controller for each type of document e.g. BriefDocument, InvoiceDocument etc.
I soon discovered that this became very messy, way too many Models and Controllers. It also took quite a long time to create a new document type. As such, I have rearranged my database.
I now have a Document model and a DocumentData model. A Document can have many Document Data. I envision something like this
Document
+----+---------------+-----------------+
| id | name | description |
+----+---------------+-----------------+
| 1 | BriefDocument | Something |
+----+---------------+-----------------+
DocumentData
+----+--------------+-----------------+--------------+
| id | key | value | documentId |
+----+--------------+-----------------+--------------+
| 1 | whatData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 2 | whoData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 3 | whyData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 4 | howData | inputted data | 1 |
+----+--------------+-----------------+--------------+
Doing this should allow me to create any type of Document using just these two models. My first problem is this, I have set up the routes as follows
Route::model('projects.document', 'Document');
Route::resource('projects.document', 'DocumentController', ['except' => ['index', 'show']]);
On a page I have a dropdown where the user can select the type of document they create. The dropdown has things like this
<li>{!! link_to_route('projects.document.create', 'Brief Document', array($project->id, 'Brief Document')) !!}</li>
So this will call the create function within my DocumentController
public function create(Project $project, $name)
{
$briefDocument = Document::where('projectId', '=', $project->id)
->where('name', '=', $name)
->first();
}
What I am trying to do in this function is first determine whether the same Document has already been created for this Project, because a Project can only have many documents, but no repeat documents.
If I do this however, I get
Missing argument 2 for App\Http\Controllers\DocumentController::create()
But am I not passing it arguement 2 within the link_to_route? From what I can see, this is passing my Project instance, as well as the string Briefing Document.
Why would I be getting this error?
Thanks
UPDATE
If I explicitly set the route it works e.g.
Route::model('projects.document', 'Document');
Route::get('projects/{projects}/document/{name}', array('as' => 'projects.document.create', 'uses' => 'DocumentController#create'));
You're getting this error, because you do not pass $name variable to the create() action.
Maybe the problem is in create() itself. This method is a part of RESTful controller and looks like it was designed to accept only Request object, so try this:
<li>{!! link_to_route('projects.document.create', 'Brief Document', ['project_id' => $project->id, 'name' => Brief Document')) !!}</li>
And create() action:
public function create(Request $request)
{
$id = $request->get('project_id');
$name = $request->get('name');
$briefDocument = Document::where('projectId', '=', $project->id)
->where('name', '=', $name)
->first();
}

Laravel - Eloquent - Polymorphic relationships with namespaces

I have 2 tables related by a polimorphic relationship:
The Store table:
id | name | ...
15 | my_store | ...
And the Tag table, that is connected to the Store table through the related_id key and the type.
id | related_id | tag | created | type
1 | 15 | test | 00:00:00 | store
2 | 15 | dummy | 00:00:00 | product
So, in that example, the Store "my_store" only has the tag "test" ("dummy" is a tag for a product, not a Store, besides it has the same related_id).
I have the Store model defined in my code as follows:
class Store extends Model {
protected $table = 'store';
public function tags()
{
return $this->morphMany('App\Tag', 'related', 'type');
}
}
And the tag model:
class Tag extends Model {
protected $table = 'tags';
public function related()
{
return $this->morphTo();
}
}
But when I try to run
$store->tags;
I saw that the query that Laravel is trying to run is:
SQL: select * from `mwp_tags` where `mwp_tags`.`related_id` = 46
and `mwp_tags`.`related_id` is not null
and `mwp_tags`.`type` = App\Store)
The query is looking for App\Store instead of store
I cannot change the value in DB and I wouldn't like to use the
protected $morphClass = 'store';
inside the Store model as I don't know if a would have to create another morphMany relationship, probably with another type name.
Somebody knows how to skip this issue? Thanks!
You could try something like this:
public function tags()
{
$default_morph_class = $this->morphClass ?: null;
$this->morphClass = 'store';
$morph_many_query = $this->morphMany('App\Tag', 'related', 'type');
$this->morphClass = $default_morph_class;
return $morph_many_query;
}
The idea being you change the morphClass on the fly and set it back. That allows you to use a different morphClass for a different relationship.

Resources