I'm unsure of the best practice when inserting mass assignment relationships within Laravel 5.4 - I'm new to the framework. The below code is working correctly, however can you tell me is there a way to simply into one line (inserting relationships)?
I've tried to look at 'save()'and 'push()' but it's not working as expected. Would this have an impact if transactions would scale up?
I have a Listing model, with a hasOne relationship:
public function garage()
{
return $this->hasOne('App\Garage', 'post_id');
}
First of all I have some validation, then I use the following to store, which I want to simplify to one one line of code:
public function store(Request $request)
{
// Validation has passed, insert data into database
$listing = Listing::create($request->all());
$listing->Garage()->create($request->all());
}
Also if I wanted to return the data inserted, how would I do this as the following is only returning the Listing model and not the Garage relationship? Yes I know that I wouldn't do this in a real world application.
return \Response::json([
'message' => 'Post Created Succesfully',
'data' => $listing
]);
Any help is muchly appreciated
Method chaining
Your store method looks good. You could chain methods though, if you don't need the listing object itself:
public function store(Request $request)
{
// Validation has passed, insert data into database
$garage = Listing::create($request->all())
->garage()->create($request->all();
}
But if you need the listing object, it's fine as you did it before!
Returning relation models
If you want to return the garage relation model too, you can simply do that by accessing it like a normal class propery:
return \Response::json([
'message' => 'Post Created Succesfully',
'data' => [$listing, $listing->garage]
//Access collection of garage relation ship
]);
Related
I have this relational table on my db:
id, is referenced to: "attivitaSost" (and attivitaSpostata).
The relathionship is "optional" so the foreignkey is nullable.
But since the problem is the same, I will try to solve the first relationship first.
My model "cciActivities" have this 2 methods:
public function attOrig()
{
return $this->hasOne(CcieActivity::class,'id', 'attivitaSost');
}
public function attSpost(){
return $this->belongsTo(CcieActivity::class,'attivitaSost','id');
If I set the inverse:
public function attOrig()
{
return $this->hasOne(CcieActivity::class,'attivitaSost','id');
}
not works, and goes in a infinite loop thats goes in 500.
are well written? who needs to carry the foreign key? the children or the parent? there is a standard or I make work as was thinking:
save the new model,
pick up the id,
save it on the parent model,
The code:
$ccieActPadre= CcieActivity::where('id',$ccieActivityId)->first();
$ccieActivityNew = CcieActivity::create($data);
$ccieActPadre -> attivitaSost = $ccieActivityNew->id;
$ccieActPadre->save();
I am asking this, because when i try to apply methods filters like
$ccieActivities = CcieActivity::doesntHave('attOrig')
->get();
are returned not what i am expected.
When I am trying to render the resource activities, im using an api Resource like:
return [
'id' => $this->id,
'project' =>new ProjectResource($this->project) , //id, nomeEnte, name, email, ruolo
'catAttivita' => $this->catAttivita,
'nomeAttivita' => $this->nomeAttivita,
'descrizione' => $this->descrizione,
'dataInizioPrevista' => $this->dataInizioPrevista,
'dataFinePrevista'=> $this->dataFinePrevista,
'numNegoziAderentiPrevisti'=> $this->numNegoziAderentiPrevisti,
'numAziendeCoinvoltePreviste'=> $this->numAziendeCoinvoltePreviste,
'numInfluencerPartecipantiPrevisti'=> $this->numInfluencerPartecipantiPrevisti,
'numBuyerPrevistiB2B'=> $this->numBuyerPrevistiB2B,
'budgetTotalePrevisto'=> $this->budgetTotalePrevisto,
'modalitaRealizzazionePrevista'=> $this->modalitaRealizzazionePrevista,
'attivitaSpostata' => new CcieActivityResource($this->attOrigSpost),
'attivitaSostituitaaaaa' => new CcieActivityResource($this->attOrig),
];
this part
'attivitaSostituita' => new CcieActivityResource($this->attOrig),
never works! whatever method I apply!
So I need to understand which is the right convention to menage a 1:1 optional self relationship over a laravel model, thanks.
The second parameters for hasOne and belongsTo are not the same.
belongsTo is for the related model and hasOne is for the local model
$this->hasOne(Phone::class, 'foreign_key', 'local_key');
$this->belongsTo(User::class, 'foreign_key', 'owner_key');
In your case, the hasOne has the wrong parameters. change it to
public function attOrig()
{
return $this->hasOne(CcieActivity::class, 'attivitaSost', 'id');
}
EDIT:
Never eager load by default the parent in the child model and the child in the parent model even if they are seperate Classes. It will lead to an infinite loop.
I have a litte question for you.
I'm using Laravel and I'm not sure which is the best way (and place) to save different models at same time.
For example:
When a user creates a "RecordSheet", I need to automatically create other models related to the RecordSheet model. Obviously I will create the RecordSheet model in his own controller:
class RecordSheetController extends Controller
{
public function store(){
RecordSheet::create([
.......
'user_id' => Auth::user()->id
]);
}
}
Where should I put the creation of the other models? In the same RecordSheetController?
class RecordSheetController extends Controller
{
public function store(){
DB:beginTranaction()
try{
$record = RecordSheet::create([
.......
'user_id' => Auth::user()->id
]);
ModelB::create([
.......
'recordSheet' => $record->id,
'user_id' => Auth::user()->id
]);
}catch(Exception $e)
{
DB:rollback();
}
DB:committ();
}
}
I'm not sure about thate since I suppose that RecordSheetController should be responsible only of "RecordSheet" models and not other models.
Any suggestion would be appreciated! Thanks everyone!
you can use Laravel Observers for this scenario, create a RecordSheetObserver and place your ModelB code in the created method
Laravel provides some built-in conventions for placement of your action or CRUD (Create - Read - Update - Delete) code.
Typically, you can put the related model action in the same method. To start, you can utilise the artisan command:
php artisan make:controller RecordSheetController --resource
This will add the standard methods to your controller. These methods tie into any resource methods you have in your routing, which follow standards for GET/POST/PUT/etc.
Once you have your controller set up, it is usually easiest and most readable to do your related action within the same method, so you don't have to go back and forth with the user from page to controller and back again. So:
public function store(Request $request){
// Add transactions as you wish
$record = RecordSheet::create([
.......
' user_id' => Auth::user()->id
]);
ModelB::create([
.......
'recordSheet' => $record->id,
'user_id' => Auth::user()->id
]);
}
You can certainly make sub functions within this, but the key is to perform this at one time for efficiency. If there are many repeatable sub functions with less related actions, it may be helpful to move this to other parts of your app. But for simple, directly related creation, it tends to be more readable to keep them in the same class.
in my controller i create an Eloquent Model Instance passign throug a relation. The model is loaded on controller's __construct, that's why is present a $this->store and not a $store.
public function index()
{
if (is_null($this->store->gallery)) {
$this->store->gallery()->create([
'title' => 'gallery_title,
'description' => 'gallery_description',
]);
}
$gallery = $this->store->gallery;
dd($gallery);
return view('modules.galleries.index', compact('gallery'));
}
Simply if a store's gallery is not present yet, let's create it.
The first time i print out my dd() is ALWAYS null, if i reload the page the dd() show correctly my gallery model.
The things is weird for me, seems like the first time the creation is done but not ready... I can work around but why this code doesn't work the first time?
Help is very appreciate.
Relationship codes: on gallery ....
public function store()
{
return $this->belongsTo(Store::class);
}
on store...
public function gallery()
{
return $this->hasOne(Gallery::class);
}
When using the $this->store->gallery()->create() method, the original method is not hydrated with the new value, you can simply do a
$gallery = $this->store->refresh()->gallery;
OR
$gallery = $this->store->load('gallery')->gallery;
if you want to make your code cleanner you can do that in your Store Model:
public function addGallery($gallery){
$this->gallery()->create($gallery);
return $this->load('gallery')->gallery;
}
And that in your controller:
$gallery = $this->store->addGallery([
'title' => 'gallery_title',
'description' => 'gallery_description',
]);
and voila ! You have your gallery ready to be used :)
It's the lazy load part of Eloquent. basicly, when you tested for it with is_null($this->store->gallery) it sets it to that value.
when you tried to recover it again, it did not do the DB query, it just loaded the value already present (null).
after creation you need to force reload the relation:
$this->store->load('gallery');
or
unset($this->store->gallery);
or
$gallery = $this->store->gallery()->get();
I have setup Spark and I have created my custom view in Settings - Students (assume User object is actually a teacher). I have also created migration and model Student.
Now http://spark.app/settings/students returns the page successfully. At this point, I need to return data from backend. I investigated Spark\Http\Controllers\Settings\DashboardController#show - which is the method returning the 'settings' view, however this doesn't return any data to view using ->with('user', $user)
But, as mentioned in Docs, :user="user" :teams="teams" :current-team="currentTeam" already available out of the box.
Where and how does Spark returns these values to /settings? And How do I make my Student object available likewise?
Now, if I want to return my Student object to front-end, I have 2 choices.
1) edit Spark\Http\Controllers\Settings\DashboardController
2) I think Spark\InitialFrontendState is the place where Spark returns these objects user, teams, currentTeam. This approach is something I've seen for the first time to be honest and I didn't really understand how it works.
So how should I achieve in Spark, something as simple as :
return view('spark::settings')->with('student', $student); ?
Add a new route and set up your own Controller & own view
web.php
Route::get('/settings/students', 'SettingsStudentController#index');
SettingsStudentController.php
class SettingsStudentController extends Controller {
public function __construct() {
$this->middleware('auth');
}
public function index(Request $request) {
$user = Auth::user();
$student = STUDENTCLASS::whatever();
return view('yourstudentview', ['student' => $student , 'user' => $user]);
}
}
I have set 2 models (Post and Category) with it´s proper relationships configured
class Post extends Model
{
protected $fillable = [
'title',
'excerpt',
'body',
'featured',
'published',
'category_id',
];
public function category()
{
return $this->belongsTo('App\Category');
}
}
class Category extends Model
{
protected $fillable = [
'name',
];
public function posts()
{
return $this->hasMany('App\Post');
}
}
And my Post´s storing method is
public function store(Request $request)
{
$post = Post::create($request->all());
return redirect('admin/posts');
}
The thing is, it´s actually working ok, it sets the category_id on the table and I can fetch all the dynamic data by using $post->category->name, but when I var_dump($post->relation) I get a null return.
I if create a new Post model, set all the attributes, save it and then associate the Category model (as documented on the official channel), it will return everything as expected.
For now, all I need is to fetch it´s dynamic attributes, and it´s working fine now, but I know I must be doing something wrong to get the null response. My concern is that it may be working fine now, but when the project gets larger I´ll probably face a bigger problem and I´ll have a lot of work to fix this issue.
The relation isn't there because you haven't loaded it. All it knows is the foreign key. It would be wildly inefficient if it grabbed all that information for you because it wouldn't always need all that. Think of instances where a single model could have many relationships, that would be many database calls for no reason.
If you need the relation, you can use $post->category. Since the relation is not yet loaded, it will get it for you when you do this.
Or you can eager load it by using the following $post->load('category') although this doesn't really benefit you because you are working with a single Post at this point. If you had a collection of Post objects, then you'd start seeing the benefits of using $posts->load('category') otherwise you end up with the n + 1 problem.
Consequently, if you use $post->load('category') and then var_dump($post), you should see that the relation is no longer null.