How to attach a relationship directly on an object? - php

I don't know if I formulated the question correctly, but whatever.
So when I use the "store" method on my controller, I send two fields, "name" and "fr", both in the same request.
In my controller, I want to be able to create my Model (Room) and attach its relationship to it (RoomTranslation). When I try the following code, it tells me I didn't provide the room_id. Is there an automatic way to achieve this ?
public function store(RoomRequest $request)
{
$request = $request->validated();
$room = new Room;
$room->create($request);
$room->translations()->create($request);
return success('');
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class RoomTranslation extends Model
{
protected $fillable = ['fr', 'room_id'];
public function room() {
return $this->belongsTo('App\Room');
}
}
<?php
namespace App;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
use App\RoomTranslation;
class Room extends Model
{
protected $fillable = ['name'];
public function categories() {
return $this->hasMany('App\Category');
}
public function translations() {
return $this->hasOne('App\RoomTranslation');
}
}
Thank you for your help !
P.S. : If there is a cleaner way to write this part of my code, I will be happy to hear how I can improve it.
Thank you !

You can do this:
Room::create($request->only(['name']))->translations()->create($request->only(['fr']));
just look for typo or input names to be correct.
Also in Room model class translations relation if you have multiple languages for every Room should be hasMany, And if you don't have many translations per Room you could just add a column for translation language.

Related

How can I use laravel Auditor in controller

I used laravel Auditor in a model and it works very well as following:
use Illuminate\Database\Eloquent\Model;
use OwenIt\Auditing\Contracts\Auditable;
class Contracts extends Model implements Auditable
{
use \OwenIt\Auditing\Auditable;
protected $fillable=['condatereceived'];
public function user()
{
return $this->belongsTo(User::class);
}
}
But I want to used it in the controller as :
public function updatecomplated(Request $request, $id,Contracts $contract ,Auditor $auditor)
{
Contracts::where('id', $id)
->update(['complated' => 50, 'conuploadby' => Auth::id(),'constatus' =>'Need To Active' ]);
if ($audit = $auditor->execute($contract)) {
$auditor->prune($contract);
}
return redirect()->back();
}
The code in controller give me error:
Call to undefined method OwenIt\Auditing\Facades\Auditor::execute()
any ideas to use auditor in the controller, please.
try this package its easy with good documentation
simply add this to your table
$table->auditable();
and this to your model
namespace App;
use Yajra\Auditable\AuditableTrait;
class User extends Model
{
use AuditableTrait;
}
thats it now simply get your auditor by calling
$user->creator // for who create
and
$user->updater //for who update data
for more information click here for check trait
Hope this helps

How to get all data from two related tables in Laravel [one to many]

I am pretty new in Laravel and need write a simple backend API.
I am doing smething wrong and I dont know what, because I get some of data from Suppliers table and empty array payments:[ ].
I am trying to get all data from two related tables - PAYMENTS and SUPPLIERS.
It`s a one to many relation SUPPLIERS_ID in PAYMENTS table is connected with ID in SUPPLIERS. Here I give You a graphic representation:
Here`s my code:
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->hasOne('App\Suppliers');
}
}
PaymentsController.php
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class PaymentsController extends Controller
{
public function index()
{
$payments = Suppliers::with('payments')->get();
return response($payments, Response::HTTP_OK);
}
}
And i get the following answear:
[{"id":1,"name":"Ekonaft","adress":"33-100 Tarnow ","email":"ekonaft#gmail.com","payments":[]},
{"id":2,"name":"Orlen","adress":"Ares testowy","email":"email#email.pl","payments":[]}]
What I`m doing wrong that I get te empty array payments:[ ] on the end of each object?
Try the inverse relationship on payments
belongsTo = has a foreign key to another table
Quoting an example
Should i use belongsTo or hasOne in Laravel?
This is how you can access suppliers from Payments
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo('App\Suppliers');
}
}
This is payments from suppliers
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments','suppliers_ID','id');
}
}
Also, make sure the id's are visible on the output (if id's are hidden, laravel can't work with the relationship). You can also specify the keys on the relationship if you want to use hasOne
Edit: add the keys names within the relation, your fk naming is in capslock
Change you relations like bel
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany(App\Payments::class, 'suppliers_ID', 'id');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo(App\Suppliers::class, 'suppliers_ID', 'id');
}
}
then try again..... :)
You are getting empty array of payments:[] due to miss-matching table relationship key name.
Please, make few changes in both relational function.
public function payments()
{
//return $this->hasMany('App\Model', 'foreign_key', 'local_key');
return $this->hasMany('App\Payments', 'suppliers_id');
}
public function suppliers()
{
//return $this->belongsTo('App\Model', 'foreign_key', 'other_key');
return $this->belongsTo('App\Suppliers', 'suppliers_id');
}
You can learn more about eloquent relationship directly from Laravel documentation for better understanding. https://laravel.com/docs/5.7/eloquent-relationships#one-to-many
Let me know if you still getting same error.

Laravel 5.5 MassAssignmentException

I'm following the Laravel From Scratch tutorial series, I'm currently at the part that you are creating a comment system for your articles system. But I'm having a problem, I don't really know what the error is saying at this point.
The error:
Illuminate\Database\Eloquent\MassAssignmentException
body
The comment model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
The post model:
<?php
namespace App;
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
}
The route I made:
Route::post('/posts/{post}/comments', 'CommentsController#store');
The comments controller:
<?php
namespace App\Http\Controllers;
use App\Post;
class CommentsController extends Controller
{
public function store(Post $post)
{
$post->addComment(request('body'));
return back();
}
}
Thanks in advance!
Explanation of this error
This is a security feature of Laravel. It is designed to protect you against form manipulation when using mass assignments.
For example on a sign-up form: When you have an is_admin column in your database, a user simply could manipulate your form to set is_admin to true on your server, and therefore in your database. This security feature prevents that by using a whitelist to define safe fields.
How to fix that
You need to set a $fillable property on your model. It's value must be an array containing all fields that are safe to mass assignable (like username, email address, ...).
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
# This property!
protected $fillable = ['body'];
// ...
}
See "Mass assignment" in the docs:
https://laravel.com/docs/5.5/eloquent#mass-assignment
Mass assignment is when you send an array to the model creation, basically setting a bunch of fields on the model in a single go, rather than one by one, something like what you did here:
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
You need to add the field you are populating to the fillable array in Comments.php model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['body'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
As the documentation states:
You may also use the create method to save a new model in a single
line. The inserted model instance will be returned to you from the
method. However, before doing so, you will need to specify either a
fillable or guarded attribute on the model, as all Eloquent models
protect against mass-assignment by default.
Hope this helps you.

How to go deeper with Eloquent hasMany in Laravel 5.2?

I'm trying to get a sort of results collection out from the db, still taking advantage of Eloquent.
I have a table called as_inspections, a table called as_green_areas and a table called as_assets
Each Inspection has a single green area, and each green area has many assets.
When I fetch the inspections I do something like this:
Inspection model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Inspection extends Model
{
protected $table = 'as_inspections';
public function greenAreas()
{
return $this->hasOne('App\GreenArea', 'id');
}
}
GreenArea model
namespace App;
use Illuminate\Database\Eloquent\Model;
class GreenArea extends Model
{
protected $table = 'as_green_areas';
}
Routes
Route::get('inspections', ['middleware' => 'cors', function()
{
$isp = new \App\Inspection();
return $isp
->with('greenAreas')
->get();
}]);
Now I'd like to do something like this:
Route::get('inspections', ['middleware' => 'cors', function()
{
$isp = new \App\Inspection();
return $isp
->with('greenAreas')
->with('assets') // where each green area has its own set of assets
->get();
}]);
As written in the comment, I'd like to get all the assets for that green area, and then all the green areas for that inspection.
How can I do this?
Thanks!
Firs of all your model class and relationship will be defined like this, make sure to replace the foreign keys in the relationship function with correct one in your table,
namespace App; //model class for inspection
use Illuminate\Database\Eloquent\Model;
class Inspection extends Model
{
protected $table = 'as_inspections';
public function greenArea()
{
return $this->belongsTo('App\GreenArea', 'greenareaid','id');
}
}
namespace App; //model for green area
use Illuminate\Database\Eloquent\Model;
class GreenArea extends Model
{
protected $table = 'as_green_areas';
public function inspection()
{
return $this->hasOne('App\Inspection', 'greenareaid','id');
}
public function assets()
{
return $this->hasMany('App\Asset', 'greenareaid','id');
}
}
namespace App; //model for asset
use Illuminate\Database\Eloquent\Model;
class Asset extends Model
{
protected $table = 'as_assets';
public function greenArea()
{
return $this->belongsTo('App\GreenArea', 'greenareaid','id');
}
}
then you can use eager loading of eloquent to easily bring the related models as in the example bellow.. you pass the primary key of the inspection model to find method, and then grab green area and related asset for it
Inspection:find(1)->with('greenArea.assets');
Inspection::find($id)->greenAreas()->assets()->all();
This will fetch all the assets of the greenAreas, inspected by Inspection $id.
I'm not sure which query you're looking for.

Using Model Events Listener in Laravel 5

I would like to make sure that I correctly used model events listeners in Laravel 5 and I didn't messed up nothing (listener vs handler?). My solution works fine, but I wonder if I developed according to concept and convention of Laravel 5.
Goal:
Always set $issue->status_id on some value when model is saving.
In app\Providers\EventServiceProvider.php
<?php namespace App\Providers;
...
class EventServiceProvider extends ServiceProvider {
...
public function boot(DispatcherContract $events)
{
parent::boot($events);
Issue::saving('App\Handlers\Events\SetIssueStatus');
}
}
In app\Handlers\Events\SetIssueStatus.php
<?php namespace App\Handlers\Events;
...
class SetIssueStatus {
...
public function handle(Issue $issue)
{
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$issue->issue_status()->associate($issueStatus);
}
}
Thank you for your time.
As you said you have a working version and it's a valid one, now that's up to you to figure out if it's ok for you.
Just to clarify I'm not saying that these are better solutions, they are just a valid different way.
Since what you are doing is specific to the Issue model or at least it doesn't seem to be a generic event, you could set it up on your model directly
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use IssueStatus;
class Issue extends Model {
protected static function boot()
{
parent::boot();
static::saving(function($issue){
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$issue->issue_status()->associate($issueStatus);
});
}
}
but if your event is indeed a generic one and you want to use it across multiple Models, you could achieve the same thing. You just need to extract the code from the model and use traits (like you do with soft deletes)
First we create our trait(in this case we created on the root of our App) and extract the code, I wrote before, from the model:
<?php namespace App
use IssueStatus;
trait IssueStatusSetter
{
protected static function boot()
{
parent::boot();
static::saving(function($model){
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$model->issue_status()->associate($issueStatus);
});
}
}
Now on the models where you want to use it, you just import the trait and declare it's use:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use IssueStatusSetter;
class Issue extends Model {
use IssueStatusSetter;
}
Now this last option I showed you it's a generic option you have that you could apply to every Model by just declaring it's use on the top of your model.

Categories