This is the scenario.
Im filling in a form and this form has Name, Email , Country and Skills (which is a dropdown with a number of skills which is populated from a database table skills prefilled). When the person is filling the form he can select multiple skills he possess. This means the user has many skills.(One to many). After the user fills the form and click submit. I want the UserTable saved and also the UserSkills also save related to the user.
The problem is dont have the user saved yet so cant fetch theid to save the skill on. Both has to be saved the same time when save is pressed.
How best can I do this in Laravel
I assume the skill ids are formatted as an array. You have a pivot table named UserSkills. Create a belongsToMany with User class as this will be a many to many relationship (one user can have multiple skills and one skill can belong to multiple users). So in your App\User class
public function skills(){
return $this->belongsToMany('\App\UserSkills','table_name','user_id','skill_id');
}
Detailed info on pivot table creation
After that, when you create an user
$user = new User();
$user->username = $request->input('username');
// other inputs or use a `create` method
$user->save();
after that attach the skill ids to the newly created user.
$user->skills()->attach($request->input('skill_ids'));
You can assign a var to the newly created user like so:
$user = User::create([
'username' => 'user'
]);
You can then use that $user anywhere below
UserSkills::create([
'user_id' => $user->id,
]);
Related
I use laravel framework . I have two table. users and points . that has one to many relationship between them.in points table saved many records related to a one user that keep all of the ponits we assign to this user.I want to keep sum this points to one field as sumpoints filed in user table.how can i do it in laravel
Do something like this in your Points model:
public static function boot()
{
parent::boot();
self::created(function($model){
$user = Auth::user();
$user->sumfields = Points::where('user_id',$user->id)->sum('points');
$user->save();
});
}
The self::created function gets called after a new instance of that model has been created.
However if this was my project, I would probably do what Ivan Jelev suggested to you (doing the sum only when you need it).
I have a meetings table where I am storing meeting information and where I can select a meeting between 2 types of user visitor type user and host type user. I have a many to many relationships between users and meeting that's why I have a pivot table meeting_user. I need to send mail all of the selected users for one meeting.
I am trying to send email using this but it's storing the meeting_id into notifiable_id column of db. so how can I store users_id in the notifiable_id column of db.
$meetings->save();
$meetings->users()->attach($request->user_id);
$users = Meeting::with('users')->get();
\Mail::to($user->send(New NewMeeting($meetings('id')));
There are two scenarios in which you can send an email to users to the meeting:
When the user has been added to the meeting
When alerting all users (in bulk) of a meeting which they have been added to.
When emailing the user which has just been added
In the event where you would like to email the users once added, you can do the following:
...
$meeting = Meeting::find($meeting_id);
$user = User::find($request->user_id);
$meeting->users()->attach($user->id);
\Notification::send($user, new NewMeetingNotification($user));
This is to be added within code which only adds a user to a meeting, not multiple users.
When emailing all users within a meeting at once
In the event where you would like to email users, in bulk, once you've added all users, you can do the following.
...
$meeting = Meeting::with('users')->where('id', $meeting_id)->first();
$meeting->users()->each(function ($user, $key) {
\Notification::send($user, new NewMeetingNotification($user));
});
$meeting_id being the meeting in question.
Notify User (Optional)
If the user model has the notifiable trait, you can change the code to:
...
$meeting = Meeting::with('users')->where('id', $meeting_id)->first();
$meeting->users()->each(function ($user, $key) {
$user->notify(new NewMeetingNotification($user));
});
I hope this helps.
So I'm developing a system where a user can create a new account and upload a profile photo. I'm using two models: User for the account, Photo for the photos.
The users table has a foreign key on the field photoId that references to photos.id. The photos table has a userId field that has a foreign key referencing users.id. So there is a recursive relationship between User and Photo. Reason for this: when a Photo is created, we want to be able to see which User uploaded the Photo. A User has one Photo as his profile image.
So it's Photo hasOne User and User hasOne Photo. They are also configured this way in their Table classes.
Now, when a new User is saved, we want to also save a new Photo. Photo needs the id of the newly created User in order to save, but the User needs the id of the newly created Photo.
My question: what is the best method to save this? Should we allow User.photoId to be null, so that we can first save the User, then save the Photo, and then update the User with the correct Photo.id, or can CakePHP3 do some magic where it does all of this linking back and forth for you?
Data that comes from the form:
[
'username' => 'John Doe',
'mail' => 'john#example.org',
'password' => 'whatever',
'photo' => [
'name' => 'myImage.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/private/var/tmp/phpN3dVmL',
'error' => (int) 0,
'size' => (int) 40171
]
]
Make Things Simple !
Why you need hasOne relations for both table ?
It looks like you are making simple thing so complected.Let's talk about that:
You have two tables users and photos that's fine.
At the moment each user has one photo that's fine as well.
Just imagine one day user might have multiple photo, then ?
Then still no worries, everything would be good because you have photos table already.
So what kind of relations do you actually need here ?
Just like mentioned above, user has one photo, That's why relation should be:
user hasOne photo and obviously photo belongsTo user.
And you need nothing more than that.
Just for example
Fields on Users table
id
name
email
address
has_photo // eg:if has_photo = 1 user has uploaded photo,such field is not compulsary
password...etc
Fields on Photos table
id
user_id // foreign key of users table
name
size
Relations
// UsersTable.php
$this->hasOne('Photos', [
'foreignKey' => 'user_id'
]);
// PhotosTable.php
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
Don't be confuse on that photos need user_id..users table never need photo_id.Because users table already associated with photos table. And if A hasOne B then B obviously belongs to A.That's the simple logic.
Don't hesitate to see the documentation ( Associations
) to get more information on relations..This is really important things for database management.
or can CakePHP3 do some magic where it does all of this linking back and forth for you?
Yes! As long as your associations are setup correctly Cake will take care of the rest. So the best method is to pass your data array into newEntity or patchEntity and make sure that all passed fields are accessible in you entity.
Saving hasOne relationships
Entities and mass assignment
I'm a pretty new to Cakephp 3.0 and I'm quite stuck on data validation, or rather Application Rules.
I have a simple user registration form to create a new user in the table 'users'. In the user registration form, there is a field for "ticket_number" where the user has to enter a ticket number which must exist in the table tickets.ticket_number, and also tickets.registration_status must be false (that ticket had not had a user registered with it yet).
My tables look like this (simplified:)
users:
id | username | password
tickets:
id | ticket_number | user_id | registration_status
In my users model, I have defined (user can have many tickets):
$this->hasMany('Tickets', [
'foreignKey' => 'user_id'
]);
In my Tickets model, I have defined (a ticket belongs to a user):
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
In the users model, I added a rule to attempt to check whether the entered ticket_number exists in the tickets.ticket_number column:
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique(['username']));
$rules->add($rules->isUnique(['email']));
$rules->add($rules->existsIn
(['ticket_number'], 'Tickets.ticket_number'));
return $rules;
}
This gives me the error:
Error: Call to a member function primaryKey() on a non-object
I'm very stuck here. Can anyone advise on the right approach implementing this check? And then, how to also implement the check to see whether the associated registration_status is 0 (that ticket has not been registered yet).
Thanks in advance for any advice!
--D.
The existsIn rule will not solve your problem, as it will not take your additional condition into account (registration-status).
You will need to provide a custom rule to accomplish the problem you described.
Regarding your update: The rule will return true - so passing the rule, if your tables are not setup correctly or it cannot find the field you are referencing or your field is nullable, check the source here: http://api.cakephp.org/3.0/source-class-Cake.ORM.Rule.ExistsIn.html#74-91
OK, after considerable tinkering, I solved the first issue (On the user add form, the user must enter a ticket number which must exist in the table tickets.ticket_number.)
The only way I could get this to work using an existsIn rule in the UsersTable model, was to declare the ticket_number field as the primary key in the initialize method of the TicketsTable model:
$this->primaryKey('ticket_number');
Then the associations and existsIn rule in the UsersTable model worked. However, this isn't good as I don't want the primary key in tickets permanently set to ticket_number. It also doesn't solve my second problem (checking tickets.registration_status is false.)
So I took a different approach and instead used $this->loadModel('Tickets'); in the add method of my users controller. Then, I could easily perform the required checks:
//Look for this particular ticket
$ticketCount = $this->Tickets->find()->where(['Tickets.ticket_number' => $ticket_number])->count();
$this->set(compact('ticketCount'));
$this->set('_serialize', ['ticketCount']);
//If the ticket isn't found, then return with the Flash error
if (!$ticketCount > 0) {
$this->Flash->error(__('Sorry, but a Ticket with this number could not be found. Please, try again.'));
return;
} //otherwise move on...
I then similarly query the registration status of the ticket, and flash a different error back if it is already registered.
After the checks are passed, it goes on to the normal Add User checks and saving.
While this solution isn't as elegant as what I was hoping to do in the Users model with a custom association and rule, it works.
I'm also not convinced it can't be done in the model with a rule. But for now, this solution works.
Anyway thanks hmic for a response.
DBZ
I have 2 MySQL DB tables called roles (representing user access role) and modules (representing allowed modules per role). Each role can have many modules and each module can have many roles.
I want to add a crud representing roles table with a multiselect field allowing to select all related modules. What is the best way to do that. Thanks in advance.
There can be multiple solutions for this.
First one - use User CRUD with expander with Roles (should work):
$crud = $this->add('CRUD');
$crud->setModel('User');
if (! $crud->isEditing()) {
// add subCRUD
$sub_crud = $crud->addRef('UserRole', array(
'extra_fields' => array('role'),
'view_options' => array('entity_name' => 'Role'),
'label' => 'Roles'
));
}
Second one - use Grid with Roles + grid->addSelectable($fields) (not tested, but just to give you idea):
$grid = $this->add('Grid');
$grid->setModel('UserRole');
$grid->addSelectable('selected');
Third one - use two lists with roles (available roles and associated roles) and some buttons to "move" role from one list to another.
Something like this: (can't find link to appropriate Codepad page now) :(
There definitely can be even more ways to do this.