Im at a bit of a loss. I have an api that will create a user upon a request. This is done no problem.
I also want to create another controller action or add to my current action the ability to create an address for the same user.
Is there an easy way to do this? Or should I stick to the
$user = new User(Input::all());
$user->save();
$address = new Address(Input::all());
$address->save();
You should set up relationships between your User and Address model - http://laravel.com/docs/eloquent#relationships and use associate/sync() to connect the dots.
This is a relationship problem. An address to a user will most likely be One-to-One (i.e., each Userhas a unique Address). A User might have an Address, but an Address must have a User. So in essence, the Address belongs to User.
Create two tables users and addresss, and add user_id to the address table as a column.
Then you define your relationships:
// In your User.php model
public function address()
{
return $this->hasOne('Address');
}
// In your Address.php model
public function user()
{
return $this->belongsTo('User');
}
Note when you use the correct notation, you can just define the model name, and not specify the pivot column. That is why I have defined the class addresss with an extra 's' to make it plural. I personally don't care about the spelling and rather Laravel take care of everything. Otherwise read the documentation on how to define the pivot column
Then you can use associate easily:
$user = new User();
// Fill $user however you want
$address = new Address();
// Fill $address however you want
$user->associate($address);
$user->save();
I was able to figure it out!
I wound up utilizing the Ardent package to help me validate my models before they hit the save method.
if my models didnt validate i will return all the errors to the user.
If they did validate my models would be created.
As for the association I am using the has many relation ship on the User and belongs to on the Address.
I used the following to save the address to the user
$address = $user->address()->save($address);
however I could only preform this after the initial user object was saved.
Thanks for all the responses guys they lead me in the right direction!
Related
I have a model User with fileds like - colorhair_id, nationality_id, etc. Of course I have a relationship to other model. Problem is that I want to return nationality from User i must do that:
User::find(1)->colorhair->name
In next time I need to use
User::find(1)->nationality->name
It works but it's not look professional and it's dirty. How can I change query or something else to return object with repleace field like nationality_id to nationality with name of that. Any idea?
You can use Laravel Mutators. Put below two functions into the User model
public function getHairColorNameAttribute(){
return $this->colorhair->name
}
public function getNationalityNameAttribute(){
return $this->nationality->name
}
Then when you simply access it.
User::find(1)->hair_color_name;
The next time
User::find(1)->nationality_name;
If you want to get these values by default use $append in the model. Put the following line to the top of the User model
protected $appends = ['hair_color_name','nationality_name'];
Note: In laravel 9 mutators little bit different from the above method.
Bonus Point :
if you access values in the same scopes don't use find() method in each statement.
$user = User::find(1);
then
$user->hair_color_name;
$user->nationality_name;
Quite new to Laravel and learning it now for work and just wonder, why do you have to use relationships, when you can simply use?
$n = Name::find(2)
$a = Address::where('name_id', '=', $n['id'])->get()
Instead of forming a relationship in the controller and:
$n = Name::find(2)
$n->address
Is it to less complicated somehow or is it just to reduce code or what?.
Any help appreciated and thanks in advance.
It is to write less code and to encapsulate things (write once and use everywhere)... those are the main principles in OOP... Your example is not so complicated. If a user has only one address you don't even need a separate model for adress, just put it in users table as an attribute...but imagine a relationship a Customer and Invoice... a Customer can have multiple Invoices and you want to show all invoices (with all the details) of a certain Invoice. It would require of you to write a lot of code to show all the details without making relationships between the models.
İf users have one adress, you dont need to new model. Just add 'address' column in your users table;
Here is your migration;
php artisan make:migration add_address_column_to_users_table
İf users have multiple adress, you can use one to many releationships.
Create address model and table,
php artisan make:model Address -m
Then in your Address model, add this function;
public function users()
{
return $this->belongsTo('App\User');
}
And in your User model;
public function address()
{
return $this->hasMany('App\Address');
}
Thats all. You can fnd more information in here
I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.
I have three tables: users, emails,attachments. User table is connected with emails by user_id. Emails table is connected with attachments by email_id.
My question is: How should I make it look eloquent in laravel to get all users their emails and their attachments? (I know how get all user and they emails but I don't know how to add attachments.)
Depending on your database relationship,you may declare a relationship method in your Email model, for example:
// One to One (If Email has only one attachment)
public function attachment()
{
return $this->hasOne(Attachment::class);
}
Otherwise:
// One to Many (If Email contains more than one attachment)
public function attachments()
{
return $this->hasMany(Attachment::class);
}
To retrieve the related attachment(s) from Email model when reading a user using id, you may try something like this:
$user = User::with('email.attachment')->find(1); // For One-to-One
$user = User::with('email.attachments')->find(1); // For One-to-Many
Hope you've already declared the relationship method in the User model for Email model using the method name email.
Note: make sure, you have used right namespace for models. It may work if you've done everything right and followed the Laravel convention, otherwise do some research. Also check the documentation.
I'm rather new to Laravel 4 and can't seem to find the right answer, maybe you can help:
A User in our application can have many Accounts and all data is related to an Account, not a User. The account the User is currently logged into is defined by a subdomain, i.e. accountname.mydomain.com.
We added a method account() to our User model:
/**
* Get the account the user is currently logged in to
*/
public function account()
{
$server = explode('.', Request::server('HTTP_HOST'));
$subdomain = $server[0];
return Account::where('subdomain', $subdomain)->first();
}
The problem is that there is always an extra query when we now use something like this in our view or controller:
Auth::user()->account()->accountname
When we want to get "Products" related to the account, we could use:
$products = Product::where('account_id', Auth::user()->account()->id)->get();
And yet again an extra query...
Somehow we need to extend the Auth::user() object, so that the account data is always in there... or perhaps we could create a new Auth::account() object, and get the data there..
What's the best solution for this?
Thanks in advance
Just set it to a session variable. This way, you can check that session variable before you make the database call to see if you already have it available.
Or instead of using ->get(), you can use ->remember($minutes) where $minutes is the amount of time you wish to keep the results of the query cached.
You should take a look at Eloquent relationships : http://laravel.com/docs/eloquent#relationships
It provides simple ways to get the account of a user and his products. You said that a user can have many accounts but you used a first() in your function I used a hasOne here.
Using Eloquent relationships you can write in your User model:
<?php
public function account()
{
// I assume here 'username' is the local key for your User model
return $this->hasOne('Account', 'subdomain', 'username');
}
public function products()
{
// You should really have a user_id in your User Model
// so that you will not have to use information from the
// user's account
return $this->hasMany('Product', 'account_id', 'user_id');
}
You should define the belongsTo in your Account model and Product model.
With Eager Loading you will not run a lot of SQL queries : http://laravel.com/docs/eloquent#eager-loading
You will be able to use something like
$users = User::with('account', 'products')->get();
To get all users with their account and products.
I think this is a good example for the purpose of Repositories.
You shouldn't query the (involved) models directly but wrap them up into a ProductRepository (or Repositories in general) that handles all the queries.
For instance:
<?php
class ProductRepository
{
protected $accountId;
public function __construct($accountId)
{
$this->accountId = $accountId;
}
public function all()
{
return Product::where('account_id', $this->accountId)->get();
}
}
//now bind it to the app container to make it globaly available
App::bind('ProductRepository', function() {
return new ProductRepository(Auth::user()->account()->id);
});
// and whenever you need it:
$productRepository = App::make('ProductRepository');
$userProducts = $productRepository->all();
You could group the relevant routes and apply a filter on them in order to bind it on each request so the account-id would be queried only once per repository instance and not on every single query.
Scopes could also be interesting in this scenario:
// app/models/Product.php
public function scopeCurrentAccount($query)
{
return $query->where('account_id', Auth::user()->account()->id);
}
Now you could simply call
$products = Product::currentAccount()->get();