How can I use soft deleted with relation - php

I use eloquent with soft delete .I'm getting error because of my query still select data that already use softdelete here is my model
User Model
class User extends Authenticatable
{
use Notifiable, HasRoles, SoftDeletes;
protected $guard_name = 'web';
protected $fillable = [
'username', 'password'
];
protected $dates = ['deleted_at'];
}
for example I've 100 user and I deleted 1 user with softdelete . then I try to
$a = User::all();
dd($a);
I get 99 user . It works! but after I use it relation It doest work here what I do
This is my Parent table and Model
table
|id|user_id|parent_id|
Note : user_id and parent_id are FK in user.id table
class Parent extends Model
{
protected $table = 'parent';
public function user()
{
return $this->belongsTo('App\User');
}
}
$getParent = Parent::with('user')->get();
when I dd($getParent); why I still get null data from user_id that I already use soft deleted ?
UPDATE model User : after I put whereNull I still getting user that I alredy soft deleted
public function user()
{
return $this->belongsTo('App\User')->whereNull('users.deleted_at');
}

https://laravel.com/docs/5.7/eloquent#querying-soft-deleted-models
...
public function customerAddress()
{
return $this->hasOne(Addresses::class, "id", "id_address")->withTrashed();
}
...

Ok, here's what I think is going on...
With soft delete the ondelete event doesn't work (meaning that related models is not deleted). I'm not sure if that changed in later versions of Laravel, but I don't think so. Also deleting User would still not affect the parent model, since you haven't defined the relationship between User and Parent (in the User model), only between Parent and User.
Try defining the relationship in User and then override the boot() function, that sits in the Model class. (This is untested code, but something like this should do the job)
class User extends Authenticatable
{
use Notifiable, HasRoles, SoftDeletes;
protected $guard_name = 'web';
protected $fillable = [
'username', 'password'
];
protected $dates = ['deleted_at'];
// Override Model boot function
protected static function boot()
{
parent::boot();
static::deleting(function ($users) {
foreach ($users->parents()->get() as $parent) {
$parent->delete();
}
});
}
// Define relationship with parent model
public function parents()
{
$this->hasMany('App\Parent');
}
}

You can put a constraint on the Eager Load:
public function groups()
{
return $this
->belongsToMany('Group')
->whereNull('group_user.deleted_at') // Table `group_user` has column `deleted_at`
->withTimestamps(); // Table `group_user` has columns: `created_at`, `updated_at`
}
Instead of HARD deleting the relationship using:
User::find(1)->groups()->detach();
You should use something like this to SOFT delete instead:
DB::table('group_user')
->where('user_id', $user_id)
->where('group_id', $group_id)
->update(array('deleted_at' => DB::raw('NOW()')));

Related

Laravel hasOne() Function Using $this when not in object context

I have 2 models named AdminContent, AdminCategory. I have content_category_id in my admin_contents table. I have category_id and category_name in my admin_categories table. I linked category_id with content_category_id foreign.
I am using the hasOne() function in my Admin Content model. But I get the error Using $this when not in object context!
My main goal is to get content_category_id value from admin_categories table name column
Migrations
// Admin Categories Migration
Schema::create( 'admin_categories', function(Blueprint $table) {
$table->bigIncrements('ctgry_id')->unique();
$table->string('category_name', 50)->unique();
$table->timestamps();
});
// Admin Contents Migration
Schema::create('admin_contents', function (Blueprint $table) {
$table->bigIncrements('cntnt_id')->unique();
$table->string('content_title');
$table->text('content_content');
$table->string('content_slug');
$table->bigInteger('content_category_id');
$table->foreign('content_category_id')->references('ctgry_id')->on('admin_categories');
$table->string('content_status');
$table->string('create_user');
$table->string('content_tags');
$table->string('content_excerpt');
$table->dateTime('posted_at');
$table->timestamps();
});
Models
// AdminContent Model
protected $table = "admin_contents";
protected $fillable = [
'content_title', 'content_content',
'content_category_id', 'content_status', 'create_user','content_tags',
'content_excerpt',
'created_at', 'updated_at'
];
protected $guards = [
'cntnt_id',
];
public function setCategoryName()
{
return $this->hasOne(AdminCategory::class);
}
When I want to access with $this->hasOne(AdminCategory::class) I get this error!
First: relationships in Laravel are based in standardize models, using 'id' as column name for ids. If you are using another name for firstKey, you should add it to relationship definition, as stated in documentation. I mean, your relationship should not work because Eloquent doesn't know which are your tables first keys.
Second: when you define a relationship you should call id from your model. So how are you accessing to $this->hasOne(AdminCategory::class)?
It should be something like AdminContent::with('setCategoryName')
Maybe showing some code from your controller we can give you a more accurate reply.
What I want is this,
I get the blog content with query and print it. But I am printing the content_category_id value as the id value in category table. What I need to do is get the content_category_id and the id value in the category table, the category name linked to that id. Thanks in advance for your help.
Admin Content Model
namespace App\Models\Admin;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class AdminContent extends Model
{
use HasFactory;
protected $table = "admin_contents";
protected $primaryKey = 'cntnt_id';
protected $fillable = [
'content_title', 'content_content',
'content_category_id', 'content_status', 'create_user','content_tags',
'content_excerpt',
'created_at', 'updated_at'
];
protected $guards = [
'cntnt_id',
];
public function _all()
{
return self::all();
}
public static function setCategoryName()
{
return $this->hasOne(AdminCategory::class, 'content_category_id', 'ctgry_id');
}
}
Admin Category Model
namespace App\Models\Admin;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AdminCategory extends Model
{
use HasFactory;
protected $table = 'admin_categories';
protected $primaryKey = 'ctgry_id';
protected $fillable = [
'category_name', 'updated_at'
];
protected $quards = [
'ctgry_id', 'created_at'
];
}
Post Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Admin\AdminContent;
class PostController extends Controller
{
public function index()
{
return view('frontend.blog');
}
public function getCategoryName()
{
return AdminContent::find(1)->setCategoryName;
}
}
MySQL Tables
https://www.hizliresim.com/2z0337a

Eloquent Many to Many attach() is passing a null model ID

I am developing an application using Laravel and Eloquent ORM, it uses a database filled with event information.
I have successfully implemented attach() in the relevant controllers for both my user and role models.
My Event model can have many Links. A Link can have Many events.
My problem is that the attach() is not supplying the ID of the object it is being called on, instead it supplies null and I receive the following error message:
SQLSTATE[23000]: Integrity constraint violation:
1048 Column 'link_id'
cannot be null (SQL: insert into 'event_link' ('created_at', 'event_id',
'link_id', 'updated_at') values (2018-06-09 11:27:15, 2, , 2018-06-09 11:27:15))
I've triple checked my models and database structure.
I can't even imagine how this error could occur since the id lacking in the SQL query is the id of the object that the attach() method is actually being called on. If I use sync($eventID, false) instead of attach(), the result is the same.
Event table:
Link table:
Event_Link table:
The following is the problematic method in the controller responsible for storing the record and creating an entry in the event_link weak entity.
The $link object is created successfully if the attach() line is commented out, a JSON representation of a link is returned which confirms this (but it lacks the 'id' field).
public function store(StoreLink $request) {
$link = Link::create([
'title' => $request->title,
'url' => $request->url,
]);
if ($request['eventId']) {
// $request->eventId is passed successfully, $link id is not passed.
$link->events()->attach($request->eventId);
}
return response()->json($link, 201);
}
Link Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Link extends Model
{
protected $table = 'links';
public $incrementing = false;
public $timestamps = true;
protected $primaryKey = "id";
protected $fillable = ['title', 'url'];
public function events()
{
return $this->belongsToMany('App\Event')->withTimestamps();
}
}
Event Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
protected $table = 'events';
public $incrementing = false;
public $timestamps = true;
protected $primaryKey = "id";
protected $fillable = ['description', 'date', 'image', 'category_id'];
public function category()
{
return $this->belongsTo('App\Event', 'category_id');
}
public function links()
{
return $this->belongsToMany('App\Link', 'event_link')->withTimestamps();
}
public function history()
{
return $this->belongsToMany('App\User', 'user_history');
}
public function favourites()
{
return $this->belongsToMany('App\User', 'user_favourites');
}
}
The problem is public $incrementing = false;: Remove the line from both your models.
Your id columns are defined as AUTO_INCREMENT, so $incrementing has to be true.

Laravel 5.2 three-way pivot with custom pivot model

I have the following problem:
I have three tables:
contacts (people)
departments
contact_types (e.g. IT-Contact)
All of them are many-to-many types; One person can be a responsible for 0-n departments as 0-n Contact_types (even for the same department as multiple types). And so on.
In addition i have to have a history all over the project, so each of the tables stores "valid_start" and "valid_end" timestamps as well.
Therefore i now have this relation table:
contact_contact_type_department
id
contact_id
contact_type_id
department_id
valid_start
valid_end
What i ended up doing is creating a Model for the intermediate table:
class DepartmentResponsible extends Model {
protected $table = 'contact_contact_type_department';
protected $fillable = [...];
protected $dates = [
'valid_start',
'valid_end',
];
protected static function boot(){
parent::boot();
static::addGlobalScope(new ValidScope());
}
public function contact() {
return $this->belongsTo('cap\Contact');
}
public function department() {
return $this->belongsTo('cap\Department');
}
public function type() {
return $this->belongsTo('cap\ContactType');
}
}
Contact Model:
class Contact extends CustomModel{
protected $dates = [...];
protected $fillable = [...];
protected static function boot(){
parent::boot();
static::addGlobalScope(new ValidScope());
}
public function departmentResponsibles() {
return $this->hasMany('cap\DepartmentResponsible');
}
}
ContactType Model:
class ContactType extends CustomModel {
protected $dates = [...];
protected $fillable = [...];
protected static function boot() {
parent::boot();
static::addGlobalScope(new ValidScope());
}
public function responsible() {
return $this->hasMany('cap\DepartmentResponsible');
}
}
Department Model:
class Department extends CustomModel {
protected $fillable = [...];
protected $dates = [...];
protected static function boot(){
parent::boot();
static::addGlobalScope(new ValidScope());
}
public function responsibles(){
return $this->hasMany('cap\DepartmentResponsible');
}
//other methods down here, which have no immpact on this issue
}
I can now do things like
Department::first()->responsibles
Regarding the issue with the timestamps on the pivot table i assume i will have to make it a custom pivot table again (already had to do that once, in another case, where i had a "regular" 2-way pivot table)
So my 2 Questions now are:
1. Is this even the right way to do it? I mean the whole thing with the intermediate model and so on. I tried other ways as well, but I couldn't get anything like department->attach(contact) to work since i always need the third id as well...
2. How can i get something like Department::first()->contacts to work? (In a way, where i can access the intermediate "responsibles (=contact_contact_type_department)" table and filter based on the validity dates;eg. with a scope or with wherepivot functions)
well i finally went with the approach that i have an intermediate model called responsible. So for example if i want to print all the contacts and their contact_types for a department then i can do something like this:
$department = Department::first();
<ul>
foreach($department->responsible as $responsible){
<li>{{$responsible->contact->name}} as {{$responsible->type->name}}</li>
}
</ul>

Simple way to check if user is a friend in Laravel 4

I'm trying to easily check if a given user_id is a friend of the current user so I can simply do a check within a blade #if statement. My friendship functionality is two-way, and accepting a friendship is not required.
I have seem to have some setup going, but am not confident that I'm doing it properly.
Friendship Table
Schema::create('friendshipLinks', function ($table) {
$table->increments('id');
$table->integer('userId_1'); // foreign key
$table->integer('userId_2'); // foreign key
$table->timestamps();
$table->foreign('userId_1')->references('id')->on('users')->onDelete('cascade');
$table->foreign('userId_2')->references('id')->on('users')->onDelete('cascade');
});
User Model (Trimmed)
class User extends Eloquent implements UserInterface, RemindableInterface {
use EloquentTrait, UserTrait, RemindableTrait;
protected $table = 'users';
// RELATIONSHIPS
public function posts() {
return $this->hasMany('Post');
}
// FRIENDSHIP
function friends() {
return $this->belongsToMany('User', 'friendshipLinks', 'userId_1', 'userId_2');
}
function friendsWith() {
return $this->belongsToMany('User', 'friendshipLinks', 'userId_2', 'userId_1');
}
}
Friendship Model
class Friendship extends Eloquent {
protected $table = 'friendshipLinks';
protected $fillable = ['userId_1', 'userId_2'];
}
At the moment I can get an array of all the users friends with (Two-way)
$friends = User::find($id)->friends;
$friendsWith = User::find(Auth::user()->id)->friendsWith;
$result = $friends->merge($friendsWith);
How can I easily implement something that will allow me to call a function that return a boolean like:
$isFriend = User::find($id)->isFriend($friend_id);
Here is the solution method in user model's class:
public function isFriend($friendId) {
return (boolean) $this->friends()->where('users.id', $friendId)->count();
}

Obtaining a list of non-linked models, in many_to_many relations, using Laravel Eloquent

I have a User-Roles model, using Laravel 4 where a user can have many roles, using Eloquent. I can access all roles linked to a user easily using this code :
class User extends Model {
protected $table = 'user';
protected $fillable = array('name');
public function rolesLinked() {
return $this->hasMany('App\UserRoleLink', 'user_id');
}
}
I've been trying to obtain the roles that are not linked to a user, to display on the specific user's page in a select box. Using this function, included in the User class.
public function rolesNotLinked() {
$user = this
$roles = Roles::whereDoesntHave('App\UserRoleLink',function($query) use ($user){
$query->where('user_id',$user->id);
});
}
The problem is, calling this function gives me the following error.
Call to undefined method Illuminate\Database\Query\Builder::App\UserRoleLink()
I've tried using has with < 1 to see if the function was problematic, but after reading this and the online source code, the function call pretty much does what I've tried.
Is something wrong in my function call, or have I messed up configurations somewhere?
For reference, here are my other Model classes:
class UserRoleLink extends Model{
protected $table = 'user_role_link';
protected $fillable = array('role_id','user_id);
public function role() {
return $this->hasOne('App\Role', 'role_id');
}
}
class Role extends Model{
protected $table = 'role';
protected $fillable = array('name');
}
EDIT: I've found out that I messed up by fillables when I copy-pasted. It didn't fix the issue, but I guess that's one step closer.
To use whereDoesntHave method, you must add the relation in your Role Model.
class Role extends Model{
protected $table = 'role';
protected $fillable = array('name');
public function UserRoles() {
return $this->hasMany('App\UserRoleLink', 'id');
}
}
Also, the whereDoesntHave method first parameter is not thte model but the function of the relation:
public function rolesNotLinked() {
$user = this
$roles = Roles::whereDoesntHave('UserRoles',function($query) use ($user){
$query->where('user_id',$user->id);
});
}

Categories