Laravel 5 updateOrCreate (or Delete) - laravel

I have a setup where, I have a user_roles table.
Then the administrator, will be able to update these, by adding new role, updating the name of an old role, and lastly delete.
------------------
| id | user_role |
| 1 | admin |
| 2 | role 1 |
| 3 | role 3 |
------------------
I tried to use this block of code to update, add, delete the roles
public function update(Request $request, $id){
$roles = Model::all();
foreach($roles as $role){
$role->delete();
}
foreach($request->role as $role){
$role = new Model;
$role->user_role = $role;
$role->save();
}
}
But in the users table, I have a user_role column that references to the id of the user_roles table, so whenever I use the above code, all rows will be deleted, then a new id will be created for the new rows inserted. So, when I go back to the list of users, their user_role column will return null, because each user has a non-existing user_role id.
Using updateOrCreate kind of solves my problem, when it comes to updating old row/s or creating new row/s but the problem is, deleting rows. It can't delete rows.
I need to delete the rows that are existing in the database, and missing in the request.
What would be the best way to do this ?

I have fixed this case using the id approach proposed by maslauskast # https://laracasts.com/discuss/channels/laravel/updateorcreate-rows-from-a-csv-or-delete-if-not-on-the-csv?page=0
In your case a solution* will be
public function update(Request $request, $id){
$usersRoleToDelete = Model::all()->pluck('id', 'id');
foreach($request->role as $role) {
$createdOrUpdated = Model::createOrUpdate(['user_role' => $role]);
if (!empty($usersRoleToDelete[$createdOrUpdated->id])) {
unset($usersRoleToDelete[$createdOrUpdated->id]);
}
}
if (count($usersRoleToDelete)) {
Model::whereRaw(sprintf('id IN (%s)', implode(',', $usersRoleToDelete)))->delete();
/* Alternatively you could use
* Model::whereIn('id', $usersRoleToDelete)->delete();
* if the amount of ids is smaller than the maximum PDO arguments allowed
*/
}
}
Please note that I have not tested this.

this is my working updateOrCreate method based on Adrian answer in Laravel 5.3
public function update($id, Request $request)
{
$et=Model::find($id);
//update some parent table field's (if you want)
$et['type']=$request['type'];
$et['sum'] =preg_replace('/[^0-9]/s', '', $request['sum']); //for remove thousand separtor
$et->save();
$et_det=$et->et_dets()
->pluck('id','id'); // one-to-many relation
for ($i=0;$i<count($request['det_id']);$i++)
{//some matching condition
$createdOrUpdated = Model_dets::updateOrCreate(
[
'parent_id'=>$id,
'total'=>$request['total'][$i]
],
[
'columnA' => $request['columnA'][$i],
'ColumnB' => $request['ColumnB'][$i])
]);
if (!empty($et_det[$createdOrUpdated->id])) {
unset($et_det[$createdOrUpdated->id]);
}
}
if (count($et_det)) {
Model_det::whereIn('id', $et_det)->delete();
}
return Redirect::to('index')->with('alert-success','Update successfully');
}

Related

Laravel relationship filter by company_id

I am doing a laravel api with custom permissions feature.
This is my structure of tables:
User
id | email | password
Company
id | companyName
Permissions
id | name
User_has_permissions
user_id | company_id | permission_id
I am get the user and permissions with code below in model:
public function permissions() {
return $this->belongsToMany(Permission::class, 'user_has_permission', 'user_id', 'permission_id');
}
And in controller:
public function show($company_id, $user_id) {
//now I need return only permissions related with $company_id
return User::with(['permissions'])->find($User_id);
}
Now, I am need get the user and your permissions, but, only related by company_id.
Anyone have any idea how can I get this result?
Any idea is welcome.
Thanks a lot.
You can query with includes, by doing key value syntax as the parameter. In BelongsToMany, it inner joins with the pivot table, which would make it possible to add a condition on the comapny_id.
return User::with(['permissions' => function ($query) use ($company) {
$query->where('user_has_permission.company_id', $company->id);
}])->find($id);

how to get foreign id's from two different tables and store in an another table in laravel

I have 3 tables called user, user_profile and notes
user.php contains
id name email
1 sam sam#dd.com
2 jen jj#sss.org
user_profile.php,
id user_id fname lname
1 1 ss aa
2 2 ww ed
notes.php
id user_id user_profile_id note file
1 1 1 demo aa.pdf
2 2 2 test aa.jpg
NotesController
public function store_notes()
{
$data = request()->validate([
"note" => ['required'],
"file" => ['required','file'],
]);
// dd($data);
auth()->user()->userprofile()->notes()->create($data);
return redirect('users');
}
I use this way to insert all details which I want to insert in notes table but I get the following error
Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::notes()
this is my user model
public function notes()
{
return $this->hasMany(Note::class);
}
my user_profile model
public function notes()
{
return $this->hasMany('App\Note','user_profile_id');
}
and my notes model
public function user()
{
return $this->belongsTo(User::class);
}
public function userprofile()
{
return $this->hasMany('App\UserProfile');
}
actually my point is that, I have to create notes and files in notes table also insert user_id and user_profile_id in notes table. I know how to use two tables with relations but dont know when it comes to three.. [NOTE: I already use a relation between user and userprofile during the development of this sample project it works fine]
If anyone knows the answer please help me to figure it out the issue... Advance greetings..

Laravel DB relations

I'm trying to connect users table with user_info. I've found some posts about it and it works, but I've troubles with user_info->id autoincrement.
If I set it to:
$table->increments('id');
I'm getting error that no default value is set, it works only if I add
$table->integer('id')->nullable($value = true);
Here is what I got for now:
User model
public function userinfo()
{
return $this->hasOne('App\Userinfo');
}
Userinfo model
public function user()
{
return $this->belongsTo('App\User');
}
Migration/table structure
public function up()
{
Schema::create('user_info', function (Blueprint $table) {
//There is a problem, if I don't add user_id it says that user_id doesnt exists, so I created user_id and decided to set id to autoincrement but it doesnt works so I made it like that
$table->integer('id')->nullable($value = true);
$table->foreign('id')->references('id')->on('users');
$table->integer('user_id');
$table->string('avatar',255)->default('notset.jpg')->nullable($value = true);
$table->string('looking_for',255)->nullable($value = true);
$table->string('steam_nick',40)->nullable($value = true);
$table->integer('age')->length(3)->nullable($value = true);
$table->integer('isFriendly')->length(2)->nullable($value = true);
$table->integer('isToxic')->length(2)->nullable($value = true);
$table->integer('isLeader')->length(2)->nullable($value = true);
$table->integer('isFunny')->length(2)->nullable($value = true);
$table->integer('isSkilled')->length(2)->nullable($value = true);
$table->text('description')->nullable($value = true);
$table->timestamps();
});
}
Finally UserinfoController
public function update(Request $request, $id)
{
$user = User::findOrFail($id); //Get role specified by id
$this->validate($request, [
'steam_nick'=>'max:120',
'looking_for'=>'required',
'avatar'=>'',
'description'=>'max:450',
'age'=>'min:2'
]);
$input = $request->only(['steam_nick', 'looking_for', 'description','avatar','age']); //Retreive the name, email and password fields
$userinfo = new Userinfo();
if ($userinfo->user_id == null ) {
$userinfo->steam_nick = $request->steam_nick;
$userinfo->looking_for = $request->looking_for;
$userinfo->description = $request->description;
$userinfo->avatar = $request->avatar;
$userinfo->age = $request->age;
$user->Userinfo()->save($userinfo);
} else {
$user->Userinfo()->update($input);
}
}
Phpmyadmin
img
All I need is to set id in user_info same as id in users. I don't need user_id, but couldn't make it works other way, but I'm sure it's wrong.
Okay, let's break it down piece by piece.
First, what I like to do is specifically declare what my table column is as the second argument on any hasOne and belongsTo in a model. It's not strictly necessary since Laravel does some voodoo magic to guess what the table name is - but I recommend it because it makes the relationship very clear. So, I would do this on the user model:
public function userinfo()
{
return $this->hasOne('App\Userinfo', 'user_id'); // it references user_id on your user_info table.
}
Next, let's look at your user_info migration. You were having problems with your primary key id because you were trying to set it as integer when it needs to be increments. We'll tweak the first three lines:
$table->increments('id')->unsigned();
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users'); // foreign references the user_id field in this table, since that's what's making the connection between users and users_info, we point back to the user's id
At this point, if you are able, I recommend php artisan migrate:fresh --seed. It might help with any weird database structures you have prior. This is optional, though. You can try it if it doesn't work straight away.
Now in the controller, I noticed that you were previously referencing $user->Userinfo()->update($input);, but you named the relationship userinfo() in your user model. This is probably one of the things that was giving you an issue. They must match. Try setting up your controller like so:
public function update(Request $request, $id)
{
$user = User::findOrFail($id); //Get role specified by id
$this->validate($request, [
'steam_nick'=>'max:120',
'looking_for'=>'required',
'avatar'=>'',
'description'=>'max:450',
'age'=>'min:2'
]);
$input = $request->only(['steam_nick', 'looking_for', 'description','avatar','age']); //Retreive the name, email and password fields
// Does this user have an info record? If not, create it, else update it.
if (is_null($user->userinfo)) {
// Since you already collected the data in the $input variable, we simply array_merge it with the user's id
Userinfo::create(array_merge([
'user_id' => $user->id,
], $input));
} else {
$user->userinfo()->update($input);
}
return redirect()->back();
}
So, basically what we are doing is checking to see if the user has a related record in the user_info table. If not, create it with the data. If so, simply update it. Since in our migration we declare that user_id cannot be null, we have to grab the user's id off the $user variable, and you've already grabbed all of the necessary data for the user_info table and put it in the $input variable, we simply array_merge() those two arrays when creating the user's info record.
Otherwise, if the related record already exists, we simply update the user_info record using our relationship ->userinfo().
Try that and let me know how it works.

How to update field when delete a row in laravel

Let I have a table named customer where customer table has a field named deleted_by.
I implement softDelete in customer model. Now I want to update deleted_by when row delete. So that I can trace who delete this row.
I do search on google about it But I don't found anything.
I use laravel 4.2.8 & Eloquent
You may update the field using something like this:
$customer = Customer::find(1); // Assume 1 is the customer id
if($customer->delete()) { // If softdeleted
DB::table('customer')->where('id', $customer->id)
->update(array('deleted_by' => 'SomeNameOrUserID'));
}
Also, you may do it in one query:
// Assumed you have passed the id to the method in $id
$ts = Carbon\Carbon::now()->toDateTimeString();
$data = array('deleted_at' => $ts, 'deleted_by' => Auth::user()->id);
DB::table('customer')->where('id', $id)->update($data);
Both is done within one query, softDelete and recorded deleted_by as well.
Something like this is the way to go:
// override soft deleting trait method on the model, base model
// or new trait - whatever suits you
protected function runSoftDelete()
{
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$deleted_by = (Auth::id()) ?: null;
$query->update(array(
$this->getDeletedAtColumn() => $this->fromDateTime($time),
'deleted_by' => $deleted_by
));
}
Then all you need is:
$someModel->delete();
and it's done.
I would rather use a Model Event for this.
<?php
class Customer extends \Eloquent {
...
public static function boot() {
parent::boot();
// We set the deleted_by attribute before deleted event so we doesn't get an error if Customer was deleted by force (without soft delete).
static::deleting(function($model){
$model->deleted_by = Auth::user()->id;
$model->save();
});
}
...
}
Then you just delete it like you would normally do.
Customer::find(1)->delete();
I know this is an old question, but what you could do (in the customer model) is the following....
public function delete()
{
$this->deleted_by = auth()->user()->getKey();
$this->save();
return parent::delete();
}
That would still allow the soft delete while setting another value just before it deletes.

laravel 4 model events updating a record on softdelete

[Help] I need when deleting a record it will also create a deleted_by value.
[company table]
| name | created_by | updated_by | deleted_by | created_at | updated_at | deleted_at |
public static function boot()
{
static::creating(function($company)
{
$company->created_by = Auth::user()->id;
});
}
This will fill created by with the user id when we creating record.
But when I use this when delete record ( using soft delete )
public static function boot()
{
parent::boot();
static::deleting(function($company)
{
$company->deleted_by = Auth::user()->id;
});
}
this method is doesn't work, deleted_by column is not update.
How to fill deleted_by with user id when we delete a record ?
Thanks before
At the moment, Laravel's delete() method does not take other attribute changes into consideration when it creates the relevant UPDATE query. Here's a snippet from Eloquent\Model::performDeleteOnModel():
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
if ($this->softDelete)
{
$this->{static::DELETED_AT} = $time = $this->freshTimestamp();
$query->update(array(static::DELETED_AT => $this->fromDateTime($time)));
}
else
{
$query->delete();
}
Because of the newQuery(), no changes made to the object are taken into consideration when building the actual DB query.
You could extend the Model class and add in your own functionality to accept any changed attributes, or you can simply toss $company->save() in your static::deleting() closure. It will perform two queries, but will take you mere seconds to implement, compared to the first option. Your choice!

Resources