I have a one-to-one unidirectional relation.
class User extends Model
{
public $timestamps = false;
public function profile()
{
return $this->hasOne(Profile::class);
}
}
class Profile extends Model
{
public $timestamps = false;
}
I want to create a user with a single profile:
$user = User::firstOrCreate([
'name' => 'John',
'email' => 'john#email.com'
]);
$profile = new Profile([
'age' => 'age',
'sex' => 'sex'
]);
$user->profile()->save($profile);
Running this command multiple times creates one user with multiple profiles without a exception/warning that User model will have multiple relations.
How can I create a constraint or ensure that User will have only one profile?
Update:
Because my command can run multiple times, unique on profile_id will throw an exception which is not ideal in my case. I end up doing something like this:
$user = User::firstOrCreate([
'name' => 'John',
'email' => 'john#email.com'
]);
$user->profile()->firstOrCreate([
'age' => 'age',
'sex' => 'sex'
]);
You can:
Set user_id as unique()
Manually check if profile already exists $user->profile()->isEmpty()
Use updateOrCreate() or firstOrCreate() methods.
Related
I have a table called students that has first_name, last_name and full_name columns. I want the value of full_name to be set with first_name .' '. last_name before the values are saved to the database.
Is public function store(StoreRequest $request) the best place and what is the required code?
$this->crud->addField([
'name' => 'first_name',
'type' => 'text',
'label' => "First Name",
'tab' => 'Details'
]);
$this->crud->addField([
'name' => 'last_name',
'type' => 'text',
'label' => "Last Name",
'tab' => 'Details'
]);
$this->crud->addField([
'name' => 'full_name',
'type' => 'text',
]);
// add asterisk for fields that are required in StudentRequest
$this->crud->setRequiredFields(StoreRequest::class, 'create');
$this->crud->setRequiredFields(UpdateRequest::class, 'edit');
$this->crud->allowAccess('show');
}
public function store(StoreRequest $request)
{
// your additional operations before save here
$redirect_location = parent::storeCrud($request);
// your additional operations after save here
// use $this->data['entry'] or $this->crud->entry
return $redirect_location;
}
Thanks.
One of the proper ways to do this is to use laravel eloquent model events.
You can use the creating event of the Student model. The creating event occurs right before the model is saved to the database.
You can bind the creating event of the student model in the AppServiceProvider boot function
AppServiceProvider
use App\Models\Student;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Student::creating(function ($student) {
$student->full_name = $student->first_name.' '.$student->last_name;
});
}
}
I'm building an app using Laravel 5.7 and Vue.js2. I have two tables: departments and users. A user can be a chief of a department. I made the relationship between the models. I want it so that when I create a new department, the type of the chief will be changed on the user's table to 'chief.'
DepartmentController
public function store(Request $request)
{
$this->validate($request, [
'name' => 'string|required|max:191',
'bio' => 'string|required',
'user_id' => 'integer|required|unique:departements'
]);
return Department::create([
'name' => $request['name'],
'user_id' => $request['user_id'],
'bio' => $request['bio']
]);
}
Can you try this.
Controller
public function store(Request $request)
{
$this->validate($request,[
'name'=>'string|required|max:191',
'bio'=>'string|required',
'user_id'=>'integer|required|unique:departements'
]);
$new_department = Department::create([
'name'=>$request['name'],
'user_id'=>$request['user_id'],
'bio'=>$request['bio']
]);
$get_user = User::where('id', $request['user_id'])->first();
if($get_user)
{
$get_user->type = 'chief';
$get_user->save();
}
return ['message' => 'success'];
}
In this code, After saving the New Department I get the UserData in UserModel where id is the $request['user_id] then check it if exists.
If exists, I change the type to 'chief' and save.
If you have relationship between two models then you can update like this
$product = Department::with('relationship_function_name')->find($id);
$product->fields= $request->input_name;
$product->relationship_function_name->field_name = $request->input_name;
$product->update();
Hope this helps :)
what i need is to save some data besides creating the user, here is what I've been trying to do in my RegisterController.php :
protected function create(array $data)
{
if (isset($data['checkbox'])) {
$type = 1;
$available = 1;
} else {
$type = 0;
$available = 0;
}
$user = User::create([
'name' => $data['name'],
'username' => $data['username'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'type' => $type,
'available' => $available,
'company' => $data['company'],
'job' => $data['job'],
]);
$user->profilesInfoModel()->create([
'bio' => $data['bio'],
'site' => $data['site'],
'location' => $data['location'],
'education' => $data['education'],
]);
return $user->with('profilesInfoModel');
}
The User.php (Model) has a one to one relationship with profilesInfoModel (yes, i know i should change the name of the model to make it more comfortable).
But after trying to register a user... i get this error message: Method Illuminate\Database\Query\Builder::profilesInfoModel does not exist.
What is actually going on?
The relationship should be like this
User Model
public function profile()
{
return $this->hasOne(ProfileInfo::class, 'user_id');
}
Assuming you have ProfileInfo as Profile model and it has user_id as foreign key references users table id field
Now you can create profile from $user like this
$user->profile()->create([
'bio' => $data['bio'],
'site' => $data['site'],
'location' => $data['location'],
'education' => $data['education'],
]);
$user->load('profile'); //lazy eager load
return $user;
1.in App\Model\User
public function profilesInfoModel()
{
return $this->hasOne(App\Model\User);
}
2.to call
use App\Model\User
in RegisterController
I am working in laravel-lumen. I have two models. An Organization model and an Apikey model corresponding to an organizations and an apikeys table. The column organization_id in the apikeys table is a foreign key referring to the id field of the organizations table.
The model for organizations looks like
<?php
namespace App;
use App\Apikey
use Illuminate\Database\Eloquent\Model;
Class Organization Extends Model {
public $table = 'organizations';
public $fillable = [
'name',
'contact_name',
'contact_phone',
'contact_email',
'address1',
'state',
'city',
'zip',
'country'
];
public function apikeys()
{
return $this->hasMany('App\Apikey');
}
}
The apikeys model looks like this
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
Class Apikey Extends Model {
public $table = 'apikeys';
public $fillable = [
'key',
'secret',
'organization_id',
'permissions'
];
}
organization_id in apikeys is a foreign key in the organizations table that refers to the id field of organizations table.
Now I have a controller that generates the api key given an organization_id and the permissions and fills the apikeys table. It looks like this
<?php
use App\Http\Controllers\Controller;
use App\Apikey;
use Illuminate\Http\Request;
public function generateApiKeyGivenOrganizationId(Request $request)
{
$data = $request->all();
// code for generating api key.
$dd = [
'key' => 'generated encrypted key',
'secret' => 'secret',
'organization_id' => $data['organization_id'],
'permissions' => $data['permissions']
];
$xx = Apikey::create($dd);
return response()->json(['status' => 'ok', 'apikey_id' => $xx->id]);
}
}
I want to test this code. I created two model factories like this.
$factory->define(Organization::class, function ($faker) use ($factory) {
return [
'name' => $faker->name,
'contact_name' => $faker->name,
'contact_phone' => '324567',
'contact_email' => $faker->email,
'address1' => 'xxx',
'state' => 'Newyork',
'city' => 'Newyork',
'country' => 'USA'
];
});
$factory->define(Apikey::class, function ($faker) use ($factory) {
return [
'key' => 'xxx',
'secret' => 'xxxx',
'permissions' =>'111',
'organization_id' => 7
});
My testing function looks like this.
public function testApiKeyGeneration ()
{
factory(App\Organization::class)->create()->each(function($u) {
$data = [
'organization_id' => $u->id,
'permissions' => '111'
];
$this->post('/createapikeyfororg' , $data)
->seeJson(['status' => 'ok']);
});
}
The controller works perfectly. It is only in the testing I am having problems. The url '/createapikeyfororg' is the url that invokes the controller method generateApiKeyGivenOrganizationId(). Is this testing procedure correct? I am yet to try it out and I am asking this question on a Saturday because I am really in a hurry. I am a total novice at testing and I am in a hurry and any help would be appreciated.
I'm using Jeffrey Way's model validation (https://github.com/JeffreyWay/Laravel-Model-Validation) to validate both on save and update. With this method, let's say you fill a update some fields on an entry, then call the save() method, the validation will run on all the fields currently set on the entry. But if the validation requires a field, say the email address, to be unique, the validation will fail because it already exists:
User.php:
protected static $rules = [
'email' => 'required|email|unique:users',
'firstname' => 'required',
'lastname' => 'required'
];
Controller.php:
// Get user from id
$user = User::find($id);
// Update user
$user->update($data);
// Validation when model is saved, via Way\Database\Model
if ($user->save())
{
return Response::json([
'data' => $user->toArray()
], 200);
}
if ($user->hasErrors())
{
return Response::json([
'errors' => $user->getErrors()
]);
}
Will return errors because the email address failed the validation. So, with this method, how do you tell the validator to ignore the unique rule for the email?
I think I use similar behaviour with different approach. Using this model, I thing you shold override the validate method to get the rules from a custom method, in witch you could set your new rules for existing models.
Something like this could work:
protected function processRules($rules = array()) {
$result = [];
if (empty($rules)) {
$rules = static::$rules;
}
// Add unique except :id
$replace = ($this->exists()) ? ',' . $this->getKey() : '';
foreach ($rules as $key => $rule) {
$result[$key] = str_replace(',:' . $this->getKeyName(), $replace, $rule);
}
return $result;
}
And override your validate method to call the proccessRules method.
public function validate() {
$v = $this->validator->make($this->attributes, $this->processRules(static::$rules), static::$messages);
if ($v->passes()) {
return true;
}
$this->setErrors($v->messages());
return false;
}
So now, you can define your email rule as required|email|unique:users:id, and when its a new User the rule should be required|email|unique:users and when you update the User with id 1234 the rule will be required|email|unique:users:1234.
I hope it works fine for you.
I've had this problem! I decided the problem on their own.
protected static $rules = [
'email' => $user->email == Input::get('email') ? 'required|email' : 'required|email|unique:users',
'firstname' => 'required',
'lastname' => 'required'
];
You cannot do it using this package, because you need to pass id for the unique rule. You could do it this way:
protected static $rules = [
'email' => 'required|email|unique:users,email,{id}',
'firstname' => 'required',
'lastname' => 'required'
];
and extend this model to add your custom validation method to replace {id} with id attribute