Laravel - Getting first thread per forum all() result - ajax

I'm learning VueJS and trying to develop a forum system
I am trying to get the latest post from the threads relationship per forum in my forum model.
This is my Forum Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Forum extends Model
{
public $table = 'forums';
public $timestamps = false;
public function threads() {
return $this->hasMany('App\Thread')->orderBy('id', 'DESC');
}
public function getFirstThread() {
return $this->threads()->first();
}
}
So I thought maybe this would work but it didn't
Forum::with('getFirstThread')->get();
Any idea's how I can achieve this without having to loop through everything and getting first thread for every result?
TLDR: Trying to get the latest Thread per Forum without having to loop through all forums.

You can $append the method results by using getMethodNameAttribute()
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Forum extends Model
{
public $table = 'forums';
public $timestamps = false;
protected $appends = ['firstthread'];
public function threads() {
return $this->hasMany('App\Thread')->orderBy('id', 'DESC');
}
public function getFirstThreadAttribute() {
return $this->threads()->first();
}
}

You could define another mapping as hasOne in your model to get latest thread per forum, Call latest('id') on your mapping and pass id as a column to sort
public function latest_threads() {
return $this->hasOne('App\Thread')->latest('id');
}
Then you can easily eager load your relationship as
Forum::with('latest_threads')->get();

Related

laravel 6.0 belongsTo with ApplicationService

I'm new in laravel framework. I couldn't get work medicine with prices in controller.
My model;
use Illuminate\Database\Eloquent\Model;
class Medicine extends Model
{
protected $table = 'medicine';
protected $fillable = [];
protected $guarded = [];
public function withPrice()
{
return $this->hasMany('App\Models\MedicinePrice', 'medicine_id', 'id');
}
}
In my app service ;
public function getRecentEntries()
{
$medicines = Medicine::orderBy('id','DESC')->take(10)->get()->toArray();
dd($medicines);
return $this->formatMedicine($medicines);
}
Table of medicine : https://take.ms/EHrwd
Table of medicine_price : https://take.ms/BMTJW
Any helps ? Thank you so much.
You are never loading the relationship in your code. You can accomplish it with:
Medicine::with('withPrice')->get();
However, the with('withPrice') sounds a little weird doesn't it? I would recommend you to rename the method of your relation in your Medicine model to something prettier, like prices:
public function prices()
{
return $this->hasMany(MedicinePrice::class);
}
And then you can retrieve the medicine with the prices like this:
$medicines = Medicine::with('prices')->orderByDesc('id')->take(10)->get()->toArray();
You can read more about eager loading here: https://laravel.com/docs/6.x/eloquent-relationships#eager-loading

How can you use Eloquent to find related values two tables away and in a different database?

I am developing a system that extends an existing ERP system, and so is accessing two databases (both on the same MS SQL Server). I am trying to access items on the "Equipment" model (this is a table in the ERP database) through the "EquipmentInstance" model from the "EquipmentType" model (these two are in the new database). They are related as per this diagram:
The three models are as follows:
EquipmentType
namespace App;
use Illuminate\Database\Eloquent\Model;
class EquipmentType extends Model
{
protected $table = 'dbo.EquipmentType';
protected $connection = 'sqlsrv';
protected $primaryKey = 'EquipmentTypeID';
protected $fillable = [
'TypeName',
'ProductManager'
];
public function EquipmentInstance()
{
return $this->hasMany(EquipmentInstance::class,'EquipmentTypeID', 'EquipmentTypeID');
}
public function Equipment()
{
return $this->hasManyThrough(
Equipment::class,
EquipmentInstance::class,
'TypeID',
'PartNum',
'TypeID',
'PartNum'
);
}
}
EquipmentInstance
namespace App;
use Illuminate\Database\Eloquent\Model;
class EquipmentInstance extends Model
{
protected $table = 'dbo.EquipmentInstance';
protected $primaryKey = 'EquipmentID';
protected $keyType = 'string';
protected $connection = 'sqlsrv';
protected $fillable = [
'EquipmentID',
'EquipmentTypeID',
'PartNum'
];
public function Part()
{
return $this->belongsTo(Part::class,'PartNum','PartNum');
}
public function Equipment()
{
return $this->hasMany(Equipment::class,'PartNum', 'PartNum');
}
public function EquipmentType()
{
return $this->belongsTo(EquipmentType::class); /*,'EquipmentTypeID', 'EquipmentTypeID'*/
}
/* public function Attribute()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}
public function TechNote()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}*/
}
Equipment
namespace App;
use Illuminate\Database\Eloquent\Model;
class Equipment extends Model
{
protected $table = 'ERP.SerialNo';
public $timestamps = false;
protected $primaryKey = 'SerialNumber';
protected $keyType = 'string';
protected $connection = 'epicor';
public function Part()
{
return $this->belongsTo(Part::class,'PartNum','PartNum');
}
public function Customer()
{
return $this->belongsTo(Customer::class,'CustNum', 'CustNum');
}
public function Equipment()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}
public function EquipmentInstance()
{
return $this->belongsTo(EquipmentInstance::class,'PartNum', 'PartNum');
}
}
On the EquipmentType Controller I am trying to get all of the Equipment through the EquipmentInstance so for each EquipmentInstance I can display all of the Equipments.
EquipmentType Controller
public function show(EquipmentType $EquipmentType)
{
$EquipmentInstance = $EquipmentType->EquipmentInstance()
->get();
$Equipments = $EquipmentType->EquipmentInstance()->Equipment()
->get();
return view('EquipmentType.show', compact('EquipmentType', 'EquipmentInstance', 'Equipments'));
}
The error message I get is
"BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::Equipment()"
I believe the issue is that (my understanding is rocky) that Eloquent is trying to write one query to access both databases, which is failing. However I am not sure how to proceed.
Any help would be greatly received.
Richard
Update
I have implemented what gbalduzzi suggested in his answer, which almost worked, and I am sure the issue is with my blade implemtention. I have nested two forloops:
#foreach($EquipmentType->EquipmentInstance as $EquipmentInstance)
#foreach($Equipments as $Equipment)
<tr>
<td>{{$EquipmentInstance->PartNum}} - {{$EquipmentInstance->Part->PartDescription}}</td>
<td>{{$Equipment->SerialNumber}}</td>
<td>{{$Equipment->SNStatus}}</td>
<td>{{--{{$Equipment->Customer->LegalName}}--}}</td>
</tr>
#endforeach
#endforeach
Which is displaying the serial numbers (from the Equipment model) for the first EquipmentInstance only and repeating them for all EquipmentInstanced.
Update 2
I have proven that the issue is with first() in the suggested answer, as if I change this to last() the results change as you would expect (see update 1). So my question now is:
Is there an equivelant of first(), last() which is all() or every()?
The problem is not in your database configuration, but in the way you are calling the relationship. Instead of:
$Equipments = $EquipmentType->EquipmentInstance()->Equipment()
->get();
use:
$Equipments = $EquipmentType->EquipmentInstance->first()->Equipment()
->get();
Long answer
In Eloquent, you can use a relationship in 2 ways:
as a magic field (i.e. $EquipmentType->EquipmentInstance). In this case you get as a result an instance of the model EquipmentInstance (also, if you already queried it, it directly returns the value without executing a new query)
as an eloquent query (i.e. $EquipmentType->EquipmentInstance()). Using it as a function, you don't get the model but a RelationShip instance, that is basically an eloquent query and can be chained with other eloquent methods, such as where, orderBy, ecc
So, if you call $EquipmentType->EquipmentInstance()->Equipment() it throws an error because the eloquent query does NOT have the relationship Equipment().
On the other hand, $EquipmentType->EquipmentInstance->Equipment works because it calls Equipment on the actual model instance, that has the Equipment relationship properly defined.

Eloquent one to many relationship not working

I'm stuck for hours with one of those issues where a fresh set of eyes might help. I just can't understand what's missing.
I'm connecting a model called User_ativo and defining two one-to-many relations to models Instituicao and Tipo_Ativo.
My database is simple.
Table user_ativo has columns "tipo_ativo_id" and "instituicao_id". I have a test row where both are set to 1. Both my tables instituicoes and tipo_ativos have only "id" and a string field "nome" (name). Both have a record with id == 1.
User_ativo.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User_ativo extends Model
{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo');
}
public function instituicao(){
return $this->belongsTo('App\Instituicao');
}
}
Instituicao.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
Tipo_ativo.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
My controller method that fetches the date goes as follow:
public function index()
{
$ativos = User_ativo::with('tipo', 'instituicao')->get();
return view('ativos.index', compact('ativos'));
}
Now here's where it gets interesting, for some reason I can't figure out, when I echo the $ativos variable in my view I get this:
[{"id":1,"user_id":1,"instituicao_id":1,"tipo_ativo_id":1,"tipo":null,"instituicao":{"id":1,"nome":"Banco do Brasil"}}]
So, weirdly my relationship with the Instituicao model works, but the one with Tipo_ativo returns null.
I'm pretty confident someone will point out some dumb and obvious mistake in all of this, but I can't for the life of me understand why one works and the other doesn't since they're pretty much the same thing.
Your relationships names are not according to laravel convention.
Read below function and provide foreign_key and local_key/owner_key to your relationships then it will work
public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null){}
If we do not follow laravel convention while creating relationships then we have to tell it that these are the foreign and local keys that should be used.
Read more here
class User_ativo extends Model{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
public function instituicao(){
return $this->belongsTo('App\Instituicao','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
}
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo','instituicao_id'); //second parameter is foreign key of Instituicao model
}
}
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo','tipo_ativo_id'); //second parameter is foreign key of Tipo_ativo model.
}
}

Most Recent Updates in Laravel

I have a list of books in my database and each book have chapters. my models are
Books.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
protected $guarded = [];
public function chapters()
{
return $this->hasMany(Chapter::class);
}
}
Chapter.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Chapter extends Model
{
protected $guarded = [];
public function book()
{
return $this->belongsTo(Book::class);
}
}
How can make a page that will show the books in order manner from latest to old?
Also, the order is based on the chapter being updated or added in a book. If one of the old books is being updated by adding 1 more chapter, that book will show first on the most recent updated books.
Thank you!
I am using Laravel 5.6 and Vue JS
Option 1:
You should use joins in query:
$books = Books::select('books.*')
->leftJoin('chapters', 'chapters.book_id', '=', 'books.id')
->groupBy('books.id')
->orderByDesc('chapters.updated_at')
->get();
Option 2:
If you don't need paginate and want to show all books in one page, you can try to sort a collection by relation value.
Add latestChapter relation:
public function latestChapter()
{
return $this->hasOne(Chapter::class)->orderByDesc('updated_at');
}
Get and sort:
$books = Books::with('latestChapter')->get();
$books = $books->sortByDesc(function($item){
return $item->latestChapter ? $item->latestChapter->updated_at : '1970-01-01';
});

Laravel 4.1 eager loading 3 deep nested relationships will return undefined index on third relationship

I will be doubting thomas as much as possible. Sorry for long codes.
The problem is going to be presented using series, books, authors, authorPicture
Series Model
/**
* The Series Model
*/
namespace My\Project\Series\Eloquent;
use Illuminate\Database\Eloquent\Model;
class Series Extends Model
{
protected $table = "series";
protected static $bookModel = "My\Project\Books\Eloquent\Book";
public function books()
{
return $this->hasMany(static::$bookModel);
}
}
Book Model
/**
* The Book Model
*/
namespace My\Projects\Books\Eloquent;
use Illuminate\Database\Eloquent\Model;
class Book Extends Model
{
protected static $seriesModel = "My\Project\Series\Eloquent\Series";
protected static $authorModel = "My\Project\Authors\Eloquent\Author";
public function series()
{
return $this->belongsTo(static::seriesModel);
}
public function authors()
{
return $this->hasMany(static::$authorModel);
}
}
Author Model
/**
* The Author Model
*/
namespace My\Project\Authors\Eloquent;
use Illuminate\Database\Eloquent\Model;
class Author extends Model
{
protected static bookModel = "My\Project\Books\Eloquent\Book";
protected static authorPictureModel = "My\Project\AuthorPictures\Eloquent\AuthorPicture";
public function authorPicture()
{
return $this->hasOne(static::$authorPictureModel);
}
public function book()
{
return $this->belongsToMany(static::$bookModel);
}
}
Author Picture Model
/**
* The Author Picture Model
*/
namespace My\Project\AuthorPictures\Eloquent;
use Illuminate\Database\Eloquent\Model;
class AuthorPicture
{
protected static $authorModel = "My\Project\Authors\Eloquent\Author";
public function author()
{
return $this->belongsTo(static::$authorModel);
}
}
Series Service
/**
* Series Service
*/
namespace My\Project\Series;
use My\Project\Series\SeriesProviderInterface;
class SeriesService
{
protected $seriesProvider;
public function __construct(SeriesProviderInterface $seriesProvider)
{
$this->seriesProvider = $seriesProvider;
}
public function findSeriesById($id)
{
$series = $this->seriesProvider->findById($id); // Will return model
return $series->with('books.authors.authorPicture')->get()->toArray();
}
}
Here comes the problem. The print_r result of SeriesFacade::findSeriesById($id) will include books and authors but not authorPicture.
The wierd thing; if I cancel return and dump DB::getQueryLog(), I can see that, a query was fired to find authorPictures in (.,.,.).
I can already associate models on save too. But I get undefined index if I try to eager load these nested relationships.
I read all the questions and even opened an issue on github laravel/laravel, but still not sure if I am doing something wrong or something else. That is why I ask this question.
I had a similar problem, which I solved. First, I submitted a query as follows (all the relationships had been set up correctly)
$batch = Batch::with('batchItem.teamMember.employee.employeeType')->find($id);
Then I got one of the batch items
$batchItem = $batch->BatchItem[0];
But when I print_r($batchItem) the last relation employeeType did not show up. Even more disconcerting, when I attempted to get data from $batchItem, for instance
$batchItem->teamMember->employee->name
It would issue more queries, as if no data was eager loaded at all!
The solution was sublime. It appears Eloquent is extremely case sensitive...
$batchItem = $batch->batchItem[0];
solved all of the issues!
Not sure if this is your problem, but perhaps it might help.
The query was being executed and the data was not being presented because;
the authorPicture relation was not set under $visible array of authors. That was not a bug. That was a feature I couldn't mastermind.

Resources