Why deleting row in related row boot() is not triggered? - laravel-5

In my Laravel 5.7 app I have 2 tables Tag, TagDetail(One to One relation) and the second table has image uploaded to storage and image field.
I want using boot method for automatic deletion of related rows and image. As result deleting Tag row related TagDetail is deleted, but image of TagDetail
is not deleted.
I have 2 models and new Tag())->d( is just debugging function
app/Tag.php :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use DB;
use App\MyAppModel;
use App\TagDetail;
use App\Http\Traits\funcsTrait;
use Illuminate\Validation\Rule;
use App\Rules\TagUniqueness;
class Tag extends MyAppModel
{
use funcsTrait;
protected $table = 'tags';
protected $primaryKey = 'id';
public $timestamps = false;
private $votes_tag_type= 'votesTagType';
public function getTableName() : string
{
return $this->table;
}
public function getPrimaryKey() : string
{
return $this->primaryKey;
}
public function tagDetail()
{
return $this->hasOne('App\TagDetail', 'tag_id', 'id');
}
protected static function boot() {
parent::boot();
static::deleting(function($tag) {
with (new Tag())->d( '<pre>Tag BOOT $tag::' . $tag->id);
$relatedTagDetail= $tag->tagDetail();
if ( !empty($relatedTagDetail) ) {
$relatedTagDetail->delete(); // I see this is triggered and relatedTagDetail is deleted
}
});
}
and app/TagDetail.php :
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use DB;
use App\MyAppModel;
use App\library\ImagePreviewSize;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use App\Http\Traits\funcsTrait;
class TagDetail extends MyAppModel
{
use Notifiable;
use funcsTrait;
protected $table = 'tag_details';
protected $primaryKey = 'id';
public $timestamps = false;
protected $fillable = [
'tag_id',
'image',
'description',
];
public function getTableName() : string
{
return $this->table;
}
public function getPrimaryKey() : string
{
return $this->primaryKey;
}
public function Tag()
{
return $this->belongsTo('App\Tag', 'tag_id');
}
protected static function boot() {
parent::boot();
static::deleting(function($tagDetail) { // THIS METHOD IS NOT TRIGGERED AT ALL!
with (new TagDetail())->d( '<pre>TagDetail BOOT $tagDetail::' . $tagDetail->id);
$tag_detail_image_path= TagDetail::getTagDetailImagePath($tagDetail->id, $tagDetail->image, true);
with (new TagDetail())->d( '<pre>TagDetail BOOT $tag_detail_image_path::' . $tag_detail_image_path);
TagDetail::deleteFileByPath($tag_detail_image_path, true);
});
}
Is something wrong in my models declarations ?
MODIFIED BLOCK # 2:
In my included file public/js/defaultBS41Backend/admin/tag.js I have method:
backendTag.prototype.deleteTag = function (id, name) {
confirmMsg('Do you want to delete "' + name + '" tag with all related data ?', function () {
var href = this_backend_home_url + "/admin/tag/destroy";
$.ajax({
type: "DELETE",
dataType: "json",
url: href,
data: {"id": id, "_token": this_csrf_token},
success: function (response) {
$("#btn_run_search").click()
},
error: function (error) {
alertMsg(error.responseJSON.message, 'Tag deleting error!', 'OK', 'fa fa-exclamation-triangle')
}
});
}
);
} // backendTag.prototype.deleteTag = function ( id, name ) {
and in control :
public function destroy(Request $request)
{
$id = $request->get('id');
$tag = MyTag::find($id);
if ($tag == null) {
return response()->json(['error_code' => 11, 'message' => 'Tag # "' . $id . '" not found!', 'tag' => null],
HTTP_RESPONSE_INTERNAL_SERVER_ERROR); //500
}
DB::beginTransaction();
try {
$tag->delete();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
return response()->json(['error_code' => 1, 'message' => $e->getMessage(), 'tag' => null], HTTP_RESPONSE_INTERNAL_SERVER_ERROR);
}
return response()->json(['error_code' => 0, 'message' => ''], HTTP_RESPONSE_OK_RESOURCE_DELETED); // 204
} // public function delete(Request $request)
and in routes/web.php :
Route::group(['middleware' => ['auth', 'isVerified'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
Route::delete('/tag/destroy', 'Admin\TagsController#destroy');
...

The issue is $tag->tagDetail(): You are using the query builder and deleting the model directly in the database. But the deleting event can only be triggered when you retrieve the model first.
Replace $relatedTagDetail = $tag->tagDetail(); with $relatedTagDetail= $tag->tagDetail;.

Related

laravel call to undefined method app\models\User:id()

I have been trying to create a point system, so after much effort i am getting this error which i could not figure out how to solve it because this is my first time working so deep
I have checked code but couldn't pinpoint the error
call to undefined app\models\User:id()
point model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Point extends Model
{
use HasFactory;
const TABLE = 'points';
protected $table = self::TABLE;
protected $fillable = [
'id', 'amount', 'message', 'current_points'
];
public function pointable(): MorphTo
{
return $this->morphTo();
}
public function getCurrentPoints(Model $pointable)
{
$currentPoints = Point::where('pointable_id', $pointable->id())
->where('pointable_type', $pointable->getMorphClass())
->orderBy('created_at', 'desc')
->pluck('current_points')->first();
if($currentPoints){
$currentPoints = 0;
}
return $currentPoints;
}
public function addAwards(Model $pointable, $amount, $message)
{
$award = new Static();
$award->amount = $amount;
$award->current_points = $this->getCurrentPoints($pointable) + $amount;
$award->message = $message
$pointable->awards()->save($award);
return $award;
}
}
pointable model
<?php
namespace App\Models;
interface pointable
{
public function awards();
public function countAwards();
public function addPoints($amount, $message);
}
hasPoints Traits
<?php
namespace App\Traits;
use App\Models\Point;
trait HasPoints
{
public function awards($amount = null)
{
return $this->morphMany(Point::class, 'pointable')
->orderBy('created_at', 'desc')
->take($amount);
}
public function countAwards()
{
return $this->awards()->count();
}
public function currentPoints()
{
return (new Point())->getCurrentPoints($this);
}
public function addPoints($amount, $message)
{
return (new Point())->addAwards($this, $amount, $message);
}
}
AwardPointLItener
?php
namespace App\Listeners;
use App\Events\ReplyWasCreated;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class AwardPointForNewReply
{
public function handle(ReplyWasCreated $event)
{
$amount = config('points.rewards.new_reply');
$message = 'User Created A New Reply';
$author = $event->reply->user;
$author->addPoints($amount, $message);
}
}
ReplyEvent
<?php
namespace App\Events;
use App\Models\Reply as Replyers;
use Illuminate\Queue\SerializesModels;
class ReplyWasCreated
{
use SerializesModels;
public $reply;
public function __construct(Replyers $reply)
{
$this->reply = $reply;
}
}
livewire reply componet
use Livewire\Component;
use App\Models\Reply as Replys;
class Reply extends Component
{
public $thread;
public $username;
public $reply_text;
public $replyCommentId = NULL;
protected $rules = [
'reply_text' => 'required'
];
public function mount(Thread $thread)
{
$this->thread = $thread;
}
public function render()
{
$replys = Replys::whereNull('parent_id')
->with('replies')
->with('user')
->where('thread_id', $this->thread->id)->paginate()->withQueryString();
return view('livewire.thread.reply',[
'replys' => $replys,
]);
}
public function save_reply()
{
$this->validate();
$replyevent = Replys::create([
'thread_id' => $this->thread->id,
'user_id' => auth()->user()->id,
'reply_text' => $this->reply_text,
'parent_id' => $this->replyCommentId
]);
event(new ReplyWasCreated($replyevent));
// $this->username = '';
$this->reply_text = '';
$this->replyCommentId = NULL;
}
public function deleteReply($id)
{
$reply = Replys::FindOrFail($id);
$reply->delete();
}
public function replys($replyId)
{
$this->replyCommentId = $replyId;
}
}
To get the id of a model, you simply access its id property. There is no id() method.
$currentPoints = Point::where('pointable_id', $pointable->id)

Route [admin.departments.index] not defined

i am trying to return back to departments after add a new department but this what happens :
Route [admin.departments.index] not defined
this is my store function in the DepartmentController
class DepartmentController extends BaseController
{
public function store(Request $request)
{
$this->validate($request, [
'department_name' => 'required|max:191',
]);
$params = $request->except('_token');
$department = $this->departmentRepository->createDepartment($params);
if (!$department) {
return $this->responseRedirectBack('Error occurred while creating department.', 'error', true, true);
}
return $this->responseRedirect('admin.deparments.index', 'Department added successfully' ,'success',false, false);
}
}
this is the responseRedirect function in the base controller
class BaseController extends Controller
{
protected function responseRedirect($route, $message, $type = 'info',
$error = false, $withOldInputWhenError = false)
{
$this->setFlashMessage($message, $type);
$this->showFlashMessages();
if ($error && $withOldInputWhenError) {
return redirect()->back()->withInput();
}
return redirect()->route($route);
}
}
these are the routes
Route::group(['prefix' => 'departments'], function() {
Route::get('/', 'Admin\DepartmentController#index')->name('admin.departments.index');
Route::get('/create', 'Admin\DepartmentController#create')->name('admin.departments.create');
Route::post('/store', 'Admin\DepartmentController#store')->name('admin.departments.store');
Route::get('/{id}/edit', 'Admin\DepartmentController#edit')->name('admin.departments.edit');
Route::post('/update', 'Admin\DepartmentController#update')->name('admin.departments.update');
Route::get('/{id}/delete', 'Admin\DepartmentController#delete')->name('admin.departments.delete');
});
InvalidArgumentException
Route [admin.deparments.index] not defined.
The store function in your DepartmentController returns a typo: admin.deparments.index should be admin.departments.index.

Couldn't get relation model value in maatwebsite laravel

The work of this function is to generate report of specific condition. Thus i am generating report with two tables ( User and Booking ) With primary key is userid and bookingid. Both the table is be clubbed into relations. Now i want to generate excel with using maatwebsite package at this condition. From (booking table) and to (booking table) with ticketstatus (booking table) and also with usertype ( from usertable ). For example From 01.09.2018 to 23.09.2018 with ticket status as "booked " and usertype as "Normal or agent". But i am getting an error, i am using FromQuery method in maatwebsite to perform this function.
I am adding all the codes here, User Model :
<?php
namespace App;
use App\Booking;
use App\Wallet;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $primaryKey = 'userid';
protected $fillable = ['name', 'phone', 'email','password','usertype'];
protected $dates = [
'createdAt'
];
const CREATED_AT = 'createdAt';
const UPDATED_AT = 'updatedAt';
public function bookings()
{
return $this->hasMany('App\Booking', 'userid');
}
public function walletUsers()
{
return $this->hasOne('App\Wallet', 'userid');
}
public function supports()
{
return $this->hasMany('App\Help', 'userid');
}
public function getNameAttribute($value)
{
return ucfirst($value);
}
}
Booking Model :
<?php
namespace App;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
class Booking extends Model
{
protected $primaryKey = 'bookingid';
protected $dates = [
'createdAt','updatedAt'
];
const CREATED_AT = 'createdAt';
const UPDATED_AT = 'updatedAt';
public function users()
{
return $this->belongsTo('App\User', 'userid');
}
public function getDateOfIssueAttribute($value) {
return Carbon::parse($value)->format('d-M-Y , h:m a');
}
public function getDateOfCancellationAttribute($value) {
return Carbon::parse($value)->format('d-M-Y , h:m a');
}
public function getDojAttribute($value) {
return Carbon::parse($value)->format('d-M-Y , h:m a');
}
}
Now Controller :
public function report(Request $request){
$from = $request->from;
$to = $request->to;
$bookingtype = $request->bookingtype;
$usertype = $request->usertype;
return (new BookingsExport($from, $to, $bookingtype, $usertype))->download('invoices.xlsx');
}
Route :
Route::post('/admin/reports/collect',[
'uses' => 'ReportController#report',
'as' => 'reports.generate'
]);
Maatwebsite Class:
<?php
namespace App\Exports;
use App\Booking;
use App\User;
use Carbon\Carbon;
use App\Http\Controllers\ReportController;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithMapping;
class BookingsExport implements FromQuery, WithStrictNullComparison, WithHeadings, ShouldAutoSize, WithColumnFormatting, WithMapping {
use Exportable;
public function __construct($from, $to, $bookingtype, $usertype)
{
$this->from = $from;
$this->to = $to;
$this->bookingtype = $bookingtype;
$this->usertype = $usertype;
}
public function headings(): array
{
return [
'Booking Id',
'Block Key',
'Bus Type',
'DOJ',
'status',
'Created At',
'Updated At',
'Usertype',
'Name'
];
}
public function map($booking): array
{
return [
$booking->bookingid,
$booking->blockkey,
$booking->busType,
$booking->doj,
$booking->status,
$booking->createdAt,
$booking->updatedAt,
$booking->users->usertype,
$booking->users->name
];
}
public function columnFormats(): array
{
return [
'D' => 'dd-mm-yyy',
'E' => NumberFormat::FORMAT_DATE_DDMMYYYY
];
}
public function query()
{
$from = $this->from;
$to = $this->to;
$bookingtype = $this->bookingtype;
$usertype = $this->usertype;
if(isset($from) && isset($to) && is_null($bookingtype) && is_null($usertype))
{
return Booking::query()->whereBetween('createdAt',[$from, $to]);
}
if(isset($from) && isset($to) && isset($bookingtype) && is_null($usertype))
{
return Booking::query()->whereBetween('createdAt',[$from, $to])->where('status','=', $bookingtype);
}
if(isset($from) && isset($to) && isset($bookingtype) && isset($usertype))
{
return Booking::query()->with('users')->whereHas("users", function($subQuery){
$subQuery->where("usertype", "=", $usertype);})->whereBetween('createdAt',[$from, $to])->where('status','=', $bookingtype);
}
}
}
The error i am getting is "Undefined variable: usertype" from the last query of Maatwebsite class file. But i am seeding all the values from controller to this, i even dd($usertype) but i am getting the value as agent, but it shows error while using in it query ! Kindly guide

BelongsTo relationship returns null when using relation name "user"

When creating a simple one-to-one relationship in Laravel 5.5, $person->user is returning a null value whenever I use the method/relation name user. If I change the name to foo, User, or login the code seems to work fine. This is the second project I've had this same issue on. Can anyone see what I'm doing wrong?
In Person model:
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function foo() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function getUser() {
if ($this->user_id) {
return User::find($this->user_id);
} else {
return null;
}
}
In PersonTest:
$user = factory(User::class)->create();
$person = factory(Person::class)->create(['user_id' => $user->id]);
// This works
$this->assertTrue( $person->getUser()->is($user) );
// This works
$this->assertTrue( !is_null($person->foo) );
if ( $person->foo ) {
$this->assertTrue( $person->foo->is($user) );
}
// This fails
$this->assertTrue( !is_null($person->user) );
if ( $person->user ) {
$this->assertTrue( $person->user->is($user) );
}
By request, here is all of the code relating to Person,
Entire App\Models\Person.php:
use App\Models\User;
use App\Models\Asset;
use App\Traits\HasGuid;
use App\Traits\HasNotes;
use App\Traits\HasModifiedBy;
use App\Traits\HasAttachments;
use App\Traits\HasRelationships;
use App\Transformers\PersonTransformer;
use App\Models\Abstracts\HasTypeModelAbstract;
use App\Models\Interfaces\HasTypeModelInterface;
class Person extends HasTypeModelAbstract implements HasTypeModelInterface {
use HasModifiedBy,
HasNotes,
HasAttachments,
HasRelationships;
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
Traits:
trait HasNotes {
protected static function bootHasNotes() {
static::deleting(function ($instance) {
$instance->notes->each(function ($note) {
$note->delete();
});
});
}
public function notes() {
return $this->morphMany(Note::class, 'notable');
}
}
trait HasModifiedBy {
protected static function bootHasModifiedBy() {
static::saving(function ($instance) {
$instance->modified_by_user_id = Auth::id();
});
}
public function modifiedBy() {
return $this->belongsTo(User::class, 'modified_by_user_id');
}
}
trait HasAttachments {
protected static function bootHasAttachments() {
static::deleting(function ($instance) {
$instance->attachments->each(function ($attachment) {
$attachment->delete();
});
});
}
public function attachments() {
return $this->morphMany(Attachment::class, 'attachable');
}
}
trait HasRelationships {
protected static function bootHasRelationships()
{
static::deleting(function ($instance) {
Relation::forObject( $instance )->delete();
});
}
public function related() { ...[long polymorphic relationship here]... }
/App/Models/Abstracts/HasTypeModelAbstract
use Illuminate\Database\Eloquent\Model;
// This thing just appends some custom attributes dynamically in the JSON and array forms. And no, 'user' is not a custom attribute key.
abstract class HasTypeModelAbstract extends Model {
public function newFromBuilder($attributes = array(), $connection = NULL) {
$instance = parent::newFromBuilder($attributes);
$instance->appendCustomAttributes();
return $instance;
}
protected function appendCustomAttributes() {
$this->append( $this->getCustomAttributesFromType() );
}
public function getCustomAttributesFromType() {
if ($this->type) {
return $this->type->custom_attributes ?
array_keys((array) $this->type->custom_attributes) : [];
} else {
return [];
}
}
protected function setCustomAttributesFromType($attributes = array()) {
if ($this->type) {
$custom_attribute_keys = $this->getCustomAttributesFromType();
$custom_attributes = (array) $this->custom_attributes ?: [];
foreach ($custom_attribute_keys as $key) {
$attributes[$key] = array_get($custom_attributes, $key);
}
}
return $attributes;
}
protected function addMutatedAttributesToArray(array $attributes, array $mutatedAttributes) {
$this->appendCustomAttributes($this, $attributes);
$attributes = $this->setCustomAttributesFromType($attributes);
return parent::addMutatedAttributesToArray($attributes, $mutatedAttributes);
}
protected function mutateAttribute($key, $value)
{
$keys = $this->getCustomAttributesFromType();
if ( in_array($key, $keys) ) {
return $this->getCustomAttributeValue( $key, $value );
}
return parent::mutateAttribute($key, $value);
}
protected function getCustomAttributeValue($key, $value) {
$custom_attributes = (array) $this->custom_attributes ?: [];
return array_get($custom_attributes, $key, $value);
}
I have to be honest - quickly looking at the code I don't see anything wrong but it doesn't mean everything is for sure ok.
If I were you, I would try to limit Person model just to:
class Person extends \Illuminate\Database\Eloquent\Model {
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
}
and now I would verify if everything is fine. If it's fine, now you could investigate this further, add one trait and verify, add second trait and verify, finally extend from same class.
There must be bug somewhere but looking at this code it's hard do find anything
user is reserved name in eloquent.
try User instead of user
public function User() {
return $this->belongsTo(User::class, 'user_id', 'id');
}

InvalidArgumentException route notdefined

I have error like (1/1) InvalidArgumentException
Route [home] not defined. whenever i used the store function but i'm pretty sure that i use the redirect method right what could be the possible error, all i wanted was to redirect to home once the store method is done.
web.php
<?php
Route::get('/', function () {
return view('main');
});
Route::get('/create', 'BuildingController#createBuilding');
Route::post('/store', 'BuildingController#store');
Route::post('home', 'BuildingController#getAllBuilding');
Building.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Building extends Model
{
public $timestamps = false;
protected $fillable = [
'id',
'building_name',
'building_information',
'building_image'
];
}
BuildingController.php
<?php
namespace App\Http\Controllers;
use App\Building;
use Image;
use Illuminate\Http\Request;
use App\Repositories\Building\BuildingRepository;
class BuildingController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
private $building;
public function __construct(BuildingRepository $building)
{
$this->building = $building;
}
public function createBuilding()
{
return view('building.create');
}
public function store(Request $request)
{
$this->validate($request, array(
'building_name'=>'required',
'building_information'=>'required',
'building_image' => 'required'
));
$image = $request->file('building_image');
$filename = time() . '.' . $image->getClientOriginalExtension();
$location = public_path('images/' .$filename);
Image::make($image)->resize(800,400)->save($location);
$buildings = array('building_name' => $request->building_name,
'building_information' => $request->building_information,
'building_image' => $filename);
$this->building->create($buildings);
return redirect()->route('home');
}
public function getAllBuilding()
{
$buildings = $this->building->getAll();
return view('building.home')->with('buildings', $buildings);
}
public function getSpecificRecord()
{
$buildings = $this->building->getById(1);
return view('building.show')->with('buildings', $buildings);
}
}
EloquentBuilding.php
<?php
namespace App\Repositories\Building;
use \App\Building;
class EloquentBuilding implements BuildingRepository
{
private $model;
public function __construct(Building $model)
{
$this->model = $model;
}
public function getById($id)
{
return $this->model->findOrFail($id);
}
public function getAll()
{
return $this->model->all();
}
public function create(array $attributes)
{
return $this->model->create($attributes);
}
public function update($id, array $attributes)
{
}
public function delete($id)
{
}
}
BuildingRepository.php
<?php
namespace App\Repositories\Building;
interface BuildingRepository
{
public function getById($id);
public function getAll();
public function create(array $attributes);
public function update($id, array $attributes);
public function delete($id);
}
Since you're using route(), you need to name the route. Also, make it get:
Route::get('home', 'BuildingController#getAllBuilding')->name('home');
Or:
Route::get('home', ['as' => 'home', 'uses' => 'BuildingController#getAllBuilding']);
You are trying to use route with post, replace it with get and also add/specify name attribute to call route using name.
Route::get('home', 'BuildingController#getAllBuilding')->name('home');
OR
Route::get('home', ['as' => 'home', 'uses' => 'BuildingController#getAllBuilding']);
Above both are comes with same output...

Resources