I wan't to store updates in pivot tables inside a separate table called audits_pivot.
To do that I need to sort of hook into the attached event on the model (State), which as I found out doesn't really exist. What I can do is to listen on the custom pivot class (LicenceState) for static::saving to be called, since that is the equivalent to 'attached'. Unfortunately does the callback of static::saving not contain any information about what the pivot was attached to.
There are libraries like this one from fico7489, but that doesn't work together with Laravel Nova, which I'm using.
How can I access things like the name and Id of the Model that the pivot row was attached to?
<?php
namespace App;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Database\Eloquent\Relations\Pivot as EloquentPivot;
use OwenIt\Auditing\Auditable as AuditableTrait;
use OwenIt\Auditing\Contracts\Auditable;
abstract class Pivot extends EloquentPivot implements Auditable
{
use AuditableTrait;
public static function boot()
{
parent::boot();
static::saving(function ($model) {
// How can I access here things like the name and Id of the Model that the pivot row was attached to?
// What I'm looking for is basically this:
// savePivotAudit('attached', 12, 'App\Licence', 'App\State', 51, '2020-01-14 13:55:58');
});
}
private function savePivotAudit($eventName, $id, $relation, $pivotId, $date)
{
return app('db')->table('audits_pivot')->insert([
'event' => $eventName,
'auditable_id' => $id,
'auditable_type' => $this->getMorphClass(),
'relation_id' => $pivotId,
'relation_type' => $relation,
'parent_updated_at' => $date,
]);
}
}
class License extends EloquentModel {}
class State extends EloquentModel
{
use AuditableTrait;
public function licenses()
{
return $this->belongsToMany(License::class)
->using(LicenseState::class);
}
}
class LicenseState extends Pivot {}
The Accountant package does what you want.
It supports many to many relations (i.e. pivot tables), by using Eventually, which adds events for attach(), detach(), updateExistingPivot(), sync() and toggle().
There's not even a need for using custom intermediate models.
The documentation covers all aspects of installation, configuration and usage.
Related
I want to create API store function and display course and curriculum detail like this ERD, but I don't know how to make it
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Curriculum extends Model
{
/**
* Get the course that owns the comment.
*/
public function course()
{
return $this->belongsTo(Course::class,'course_id', 'id'));
}
}
Once the relationship has been defined, we can Store
use App\Models\Curriculum;
use App\Models\Course;
$course = Course::whereId($id)->first(); //it will give you a collection of Course model
Curriculum::create([
'name' => 'testing'
'course_id' => $course->id
]);
Once the relationship has been defined, we can retrieve a Curriculum's parent course by accessing the course "dynamic relationship property":
use App\Models\Curriculum;
$curriculum = Curriculum::find(1);
return $curriculum->course->title_course;
I have two tables, work_order and project. On the project records, there is a work_order_id field. There is no project_id on the work_order records. Do I need to add one?
Or is there a way to define these relationships using hasOne/belongsTo?
I've tried:
class WorkOrder extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('id', Project::class, 'work_order_id');
}
}
class Project extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('work_order_id', WorkOrder::class, 'id');
}
}
I can retrieve the WorkOrder from the project like so: $project->workOrder, but I cannot retrieve a Project from a WorkOrder using $workOrder->project. I want a bidirectional relationship.
How do I do this?
Try adding the alias parameter, since the implicit retrieval might try to use the class name and it wouldn't support namespaces in your models.
I found it quite bogus in phalcon 1/2/3 to work with hasOne. I've been using belongsTo since then until I re-wrote the pre-post-save part of the phalcon relationship manager for my personal needs. Keep in mind that belongsTo will be saved before the main model you are working with, other types of relationships will be created/updated after the main record is saved. I choose to use "belongsTo" or "hasOne" depending on the order that I want the records and their relationships to be saved.
class WorkOrder extends \Phalcon\Mvc\Model {
public function initialize() {
$this->belongsTo('project_id', Project::class, 'id', ['alias' => 'Project']);
}
}
class Project extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('id', WorkOrder::class, 'project_id', ['alias' => 'WorkOrder']);
$this->hasMany('id', WorkOrder::class, 'project_id', ['alias' => 'WorkOrderList']);
}
}
Implicit retrieval should start with a ucfirst camelized string of your class name, or using a get.
$workOrder = WorkOrder::findFirst();
$project = $workOrder->Project;
$project = $workOrder->getProject(['deleted <> 1']);
$workOrderList = $project->WorkOrderList;
$workOrder = $project->WorkOrder;
$workOrder = $project->getWorkOrder(['deleted <> 1', 'order' => 'projectId desc']);
I'm learning Eloquent Model Relationships in Laravel. In my demo project I have two tables Sets and Cards, they have One to many relationship. One Set has many Cards and a Card belongs to a Set.
I want the output to hold both Sets and Cards together in nested JSON array, Cards under Sets. I have set the relationships in both models.
My expected result
[
{
"set_id":1,
"name":"English",
"description":"English Language",
"created_at":"2020-03-31T15:41:55.000000Z",
"updated_at":"2020-03-31T15:41:55.000000Z"},
"cards:
{
"card_id":1,
"name":"Greetings",
"description":"Greetings related questions",
"set_id":1,
"created_at":"2020-03-31T15:45:03.000000Z",
"updated_at":"2020-03-31T15:45:03.000000Z"
}
}
]
Set.php
<?php
namespace App;
use App\Card;
use Illuminate\Database\Eloquent\Model;
class Set extends Model
{
protected $table = "sets";
public function cards() {
return $this->hasMany('App\Card');
}
}
Card.php
<?php
namespace App;
use App\Set;
use Illuminate\Database\Eloquent\Model;
class Card extends Model
{
protected $table = "cards";
public function sets() {
return $this->belongsTo('App\Set');
}
}
In my Controller I have tried to get my result by this line return Set::all()->cards;, but it says Property [cards] does not exist on this collection instance. My migration files have foreign key set in Cards table, so I think the relationship between tables is made correctly or maybe I'm wrong.
I have read the detailed Laravel Doc for Eloquent Relationships, but did not find any query that returns related models together in a nested JSON, the way I'm expecting.
I have three relational table attached below.
https://drive.google.com/file/d/1q1kdURIwFXxHb2MgdRyBkE1e3DMug7r-/view?usp=sharing
I have also three separate models where defined relation among all of my table's.I can read the City Model's information from Country model using hasManyThrough() relation But cannot read the Country information from City model. I have tried to retrieve City model's using ``hasManyThrough``` but didn't get result (attached as commented country method ). Please read my model and it's relational method here..
Is there someone to help me for getting City model's information using Eloquent method hasManyThrough / hasManyThrough or using inverse of hasManyThrough / hasManyThrough ?
01.
<?php
namespace App\Hrm;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Country extends Model
{
//use SoftDeletes;
protected $fillable = ['name','description','status'];
public function districts(){
return $this->hasMany(District::class);
}
public function cities(){
return $this->hasManyThrough(City::class,District::class);
}
}
02.
<?php
namespace App\Hrm;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class District extends Model
{
//use SoftDeletes;
protected $fillable = ['country_id','name','description','status'];
public function country(){
return $this->belongsTo(Country::class);
}
public function cities(){
return $this->hasMany(City::class);
}
}
3.
namespace App\Hrm;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class City extends Model
{
//use SoftDeletes;
protected $fillable = ['district_id','name','description','status'];
public function district(){
return $this->belongsTo(District::class);
}
// public function country(){
// return $this->hasOneThrough(Country::class, District::class);
// }
Doesn't look like there is a native way to define the inverse of a "hasManyThrough" relationship yet in Laravel. There have been a few issues opened on github to request it, but they were closed.
You could use the staudenmeir/belongs-to-through package if you don't mind installing a third-party package for this functionality. Then you should be able to define a belongsToThrough relationship like this:
class City extends Model
{
use \Znck\Eloquent\Traits\BelongsToThrough;
public function country() {
return $this->belongsToThrough(Country::class, District::class);
}
}
Why can't use parent method?
$city = City::find(1);
$country = $city->district->country();
i just had a similar situation i was able to accomplish a belongsToThrough with hasOneThrough
public function country()
{
return $this->hasOneThrough(
Country::class, // model we are trying to get
District::class, // model we have an _id to
'id', // WHERE `district`.`id` = `city`.`district_id`
'id', // `countries`.`id`
'district_id', // local column relation to our through class
'country_id' // `district`.`country_id`
);
}
what this should generate is
SELECT * FROM `countries`
INNER JOIN `districts`
ON `districts`.`country_id` = `countries`.`id`
WHERE `districts`.`id` = ?
-- ? == city.district_id
Database structure:
City:
id: increments
district_id: integer
...
Country:
id: increments
...
District:
id: increments
country_id: integer
...
we can then do $city->country
note: i have not fully tested this but with the testing that i have done it 'works'
Edit: i originally thought that i needed to leave the localKey
parameter null otherwise the relation wont work. it turns out i didnt
fully understand what that column was doing and that was wrong. That
key is the local column that relates to our through column (unless i
still have more to learn/figure out), when left the value as null, it
would use the local id column which a. is the wrong value, b. can also
be out of range (which is how i discovered it was using the wrong
value)
in my testing i only had two rows, both with the same relations. what
i didnt realize though was that on the "through table" both row 1 and
2 and the same related (relation where are trying to reach) so i didnt
notice the issue right away. hopefully now its all working
I am trying to return data from my database and I want it to include data from the related table. It is a one-to-many relationship. However I all I get is an error
Property [User] does not exist on this collection instance.
In my User model I have
//App\User.php
class User extends Authenticatable{
use Notifiable;
public function systems(){
return $this->hasMany(\App\Models\General\systems::class,'added_by','id');
}
The other model, called systems I have
//App\Models\General\systems.php
class systems extends Model
{
public function User(){
return $this->belongsTo(\App\User::class,'added_by','id');
}
In my controller I have
$this->systemsObject = new \App\Model\General\systems();
$systems = $this->systemsObject->get()->User;
according to the Laravel Documentation this should work but it isn't. I tried reversing the foreign key/local key parameters. I made the ->User uppercase, lowercase.
I have no idea what I am doing wrong
You need to iterate over the collection, for example:
$systems = $this->systemsObject->get();
foreach ($systems as $system) {
echo $system->User->name;
}