How to delete data using Eloquent query? - php

I can not delete a row using a simple eloquent query. Even when I am using eloquent can not get the data from DB. I am getting null. But, in DB query method at least I am getting data but can not delete then. Following is my code:
DB::transaction(function () use ($lead, $comment, $request) {
$lead->save();
$lead->comments()->save($comment);
if ($request->deleteAppointment) {
$calendarEvent = DB::table('calendar_events')->where('id', $request->appointmentId)->first(); // I am getting data here.
$calendarEvent = CalendarEvent::find($request->appointmentId); // But, here I am getting null, don't know why!
if ($calendarEvent != null) {
$calendarEvent->delete();
}
}
My goal is to get the data using Eloquent and then Delete from database.
update:
My Database Table
CalendarEvent.php model
class CalendarEvent extends Model
{
use SoftDeletes;
/**
* #var array
*/
protected $casts = [
'event_begin' => 'datetime',
'event_end' => 'datetime',
'options' => 'array',
];
/**
* #var array
*/
protected $guarded = [
'id',
];
/**
* #return mixed
*/
public function users()
{
return $this->morphedByMany(User::class, 'eventable');
}
/**
* #return mixed
*/
public function attendees()
{
return $this->morphedByMany(User::class, 'eventable')->withPivotValue('role', 'atendee');
}
/**
* #return mixed
*/
public function companies()
{
return $this->morphedByMany(Company::class, 'eventable')->withPivotValue('role', 'company');
}
/**
* #return mixed
*/
public function invitees()
{
return $this->morphedByMany(User::class, 'eventable')->withPivotValue('role', 'invitee');
}
/**
* #return mixed
*/
public function leads()
{
return $this->morphedByMany(Lead::class, 'eventable')->withPivotValue('role', 'lead');
}
}

Why not just:
CalendarEvent::where('id', $request->appointmentId)->delete();
Also, check the deleted_at column. If that is not null, then the select will return null, unless you add the ->withTrashed() method.
When using Eloquent objects, the SoftDelete trait is used, when using DB:: directly, then the SoftDelete trait is not used.

Related

Array to string conversion in Orchid Software attachments in Laravel

I am trying to attach documents to a model when saving. I am getting array to string conversion erro. Because, it puts the documents Ids in to an array.
Here is my model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Orchid\Screen\AsSource;
use App\Models\Seller;
use Orchid\Attachment\Models\Attachment;
use Orchid\Attachment\Attachable;
use Orchid\Filters\Filterable;
use Orchid\Metrics\Chartable;
use App\Orchid\Presenters\PropertyPresenter;
use Laravel\Scout\Searchable;
class Property extends Model
{
use HasFactory;
use AsSource, Attachable,Filterable;
use Chartable;
/**
* #var array
*/
protected $fillable = [
'property_name',
'property_type',
'property_city',
'property_address',
'property_area',
'seller_id',
'property_cost',
'property_price',
'property_rent_price',
'status',
'contracts',
'images'
];
/**
* Get the parent seller of the property.
*/
public function seller()
{
return $this->belongsTo(Seller::class);
}
/**
* Name of columns to which http sorting can be applied
*
* #var array
*/
protected $allowedSorts = [
'property_name',
'property_type',
'property_city',
'status',
'created_at',
'updated_at'
];
/**
* #param Builder $query
*
* #return Builder
*/
public function scopeActive(Builder $query)
{
return $query->where('status', 'Available');
}
/**
* #param Builder $query
*
* #return Builder
*/
public function scopeStatus(Builder $query)
{
return $query->where('status', '!=', 'Sold');
}
// Many-to-Many (no foreign id on table, should be uploaded with groups() function)
public function documents()
{
return $this->hasMany(Attachment::class)->where('group','contracts');
}
/**
* Get the presenter for the model.
*
* #return PropertyPresenter
*/
public function presenter()
{
return new PropertyPresenter($this);
}
/**
* Get the indexable data array for the model.
*
* #return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
// Customize array...
return $array;
}
}
Here are the form elements
Upload::make('property.contracts')
->title('Documents')
->maxFileSize(2)
->targetId()
->targetRelativeUrl()
->groups('documents')
->acceptedFiles('image/*,application/pdf,.psd'),
And here is the save/update function
/**
* #param Property $property
* #param Request $request
*
* #return \Illuminate\Http\RedirectResponse
*/
public function createOrUpdate(Property $property, Request $request)
{
$property->fill($request->get('property'))->save();
$property->attachment()->syncWithoutDetaching(
$request->input('property.contracts', [])
);
Alert::info('You have successfully created an property.');
return redirect()->route('platform.property.list');
}
Finally here is the migration file
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('properties', function (Blueprint $table) {
$table->id();
$table->string('property_name');
$table->string('property_type');
$table->string('property_city');
$table->text('property_address');
$table->double('property_area',15,2);
$table->unsignedBigInteger('seller_id');
$table->double('property_cost', 20.3);
$table->double('property_price');
$table->double('property_rent_price')->nullable();
$table->string('contracts')->nullable();
$table->string('images')->nullable();
$table->string('status')->default('Available');
$table->timestamps();
$table->foreign('seller_id')->references('id')->on('sellers');
});
}
It gives the array to string conversion error and here is the request body:
{ "property_name": "Villa02", "property_type": "residential", "property_city": "Garoowe", "property_address": "Test", "property_area": "12000", "seller_id": "1", "property_cost": "43000", "property_price": "50000", "property_rent_price": "300", "status": "Available", "contracts": [ "67" ], "images": "/storage/2022/04/15/e3cbed3acbfec1d40c54aa57aa651a05c80d6586.png" }
Thanks in advance.
Just unset the array before filling the model
public function createOrUpdate(Property $property, Request $request)
{
$propertyInputs = $request->get('property');
$contacts = $propertyInputs['contracts']??[];
unset($propertyInputs['contracts']);
$property->fill($propertyInputs)->save();
$property->attachment()->syncWithoutDetaching($contacts);
Alert::info('You have successfully created an property.');
return redirect()->route('platform.property.list');
}

Laravel pass value to model

Right now I try this query with eloquent:
'MentorId' => $employee->intern(true)->mentor(true)->MentorId,
And in my employee and intern model I've got this:
Intern
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(internModel::class, 'InternId')->withTrashed();
}
return $this->belongsTo(internModel::class,'InternId');
}
Mentor
/**
* #return mixed
*/
public function mentor($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(mentorModel::class, 'MentorId')->withTrashed();
}
return $this->belongsTo(mentorModel::class,'MentorId');
}
But it crashes:
BadMethodCallException in Builder.php line 2148:
Call to undefined method Illuminate\Database\Query\Builder::mentor()
How could I fix this?
--EDIT--
Employee
<?php
namespace App\src\employee;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\src\department\Department as departmentModel;
use App\src\employee\Employee as employeeModel;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\src\intern\Intern as internModel;
use App\src\mentor\Mentor as mentorModel;
use App\src\employee\Role as roleModel;
class Employee extends Authenticatable
{
use SoftDeletes;
use EmployeeServiceTrait;
/**
* table name
*/
protected $table = 'employee';
/**
* Mass assignment fields
*/
protected $fillable = ['RoleId', 'DepartmentId', 'InternId', 'FirstName', 'LastName', 'Bio','api_token', 'email', 'LinkedIn', 'password', 'Address', 'Zip', 'City', 'ProfilePicture', 'BirthDate', 'StartDate', 'EndDate', 'Suspended','LinkedIn'];
/**
* Primarykey
*/
protected $primaryKey = 'EmployeeId';
/**
* Deleted_at
*/
protected $dates = ['deleted_at'];
/**
* #return mixed
*/
public function role()
{
return $this->belongsTo(roleModel::class,'RoleId');
}
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(internModel::class, 'InternId')->withTrashed();
}
return $this->belongsTo(internModel::class,'InternId');
}
/**
* #return mixed
*/
public function department()
{
return $this->belongsTo(departmentModel::class,'DepartmentId');
}
/**
* #return mixed
*/
public function mentor()
{
return $this->belongsTo(mentorModel::class,'MentorId');
}
/**
* #return mixed
*/
public function employees()
{
return $this->hasManyThrough(employeeModel::class,departmentModel::class,'CompanyId','DepartmentId');
}
/**
* #param $role
* #return bool
*/
public function hasRole($role)
{
if(strtolower($this->role->RoleName) == strtolower($role))
{
return true;
}
return false;
}
}
The problem you have is that any Eloquent relationship object is actually an instance of Relation. This means when you create relationships you actually return a collection (instance of Builder); Hense your error:
BadMethodCallException in Builder.php line 2148:
Call to undefined method Illuminate\Database\Query\Builder::mentor()
The simple solution, without any modification to your code would be something like:
'MentorId' => $employee->intern(true)->first()->mentor(true)->first()->MentorId;
However, you could use overloading like the following:
'MentorId' => $employee->intern->mentor->MentorId;
Although this will NOT include your withTrashed. You can however tweak your relationship to something like:
public function intern($withTrashed = false)
{
$relation = $this->belongsTo(internModel::class, 'InternId');
if($withTrashed == true)
{
return $relation->withTrashed()->first();
}
return $relation->first();
}
But I wouldn't advise this because later on if you try using things like WhereHas you will get errors. That said, another way would be to do something along the following lines:
public function intern()
{
return $this->belongsTo(internModel::class, 'InternId');
}
Then get trashed like:
'MentorId' => $employee->intern()->withTrashed()->first()->mentor()->withTrashed()->first()->MentorId;
Try as below as per laravel guide. Keep in mind that parent model must have hasOne/hasMany method and child model must have belongsTo method.
Intern
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->hasOne('App\Intern', 'InternId')->withTrashed();
}
return $this->hasOne('App\Intern','InternId');
}
Employee
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo('App\Intern', 'InternId')->withTrashed();
}
return $this->belongsTo('App\Intern','InternId');
}
Note: Same for all other models.

method does not exist on this mock object - Laravel , Mockery

i'm trying to test a simple class. I'm following this tutorial( http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456 ).
I have this error, while running tests:
Method Mockery_0_App_Interfaces_MealTypeRepositoryInterface::getValidator() does not exist on this mock object
Im using repository structure. So, my controller calls repository and that returns Eloquent's response.
I'm relatively new in php and laravel. And I've started learning to test a few days ago, so I'm sorry for that messy code.
My test case:
class MealTypeControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('App\Interfaces\MealTypeRepositoryInterface');
$this->app->instance('App\Interfaces\MealTypeRepositoryInterface' , $this->mock);
}
public function tearDown()
{
Mockery::close();
}
public function testIndex()
{
$this->mock
->shouldReceive('all')
->once()
->andReturn(['mealTypes' => (object)['id' => 1 , 'name' => 'jidlo']]);
$this->call('GET' , 'mealType');
$this->assertViewHas('mealTypes');
}
public function testStoreFails()
{
$input = ['name' => 'x'];
$this->mock
->shouldReceive('getValidator')
->once()
->andReturn(Mockery::mock(['fails' => true]));
$this->mock
->shouldReceive('create')
->once()
->with($input);
$this->call('POST' , 'mealType' , $input ); // this line throws the error
$this->assertRedirectedToRoute('mealType.create');//->withErrors();
$this->assertSessionHasErrors('name');
}
}
My EloquentMealTypeRepository:
Nothing really interesting.
class EloquentMealTypeRepository implements MealTypeRepositoryInterface
{
public function all()
{
return MealType::all();
}
public function find($id)
{
return MealType::find($id);
}
public function create($input)
{
return MealType::create($input);
}
public function getValidator($input)
{
return MealType::getValidator($input);
}
}
My eloquent implementation:
Nothing really interresting,too.
class MealType extends Model
{
private $validator;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'meal_types';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [];
public function meals()
{
return $this->hasMany('Meal');
}
public static function getValidator($fields)
{
return Validator::make($fields, ['name' => 'required|min:3'] );
}
}
My MealTypeRepositoryInterface:
interface MealTypeRepositoryInterface
{
public function all();
public function find($id);
public function create($input);
public function getValidator($input);
}
And finally, My controller:
class MealTypeController extends Controller {
protected $mealType;
public function __construct(MealType $mealType)
{
$this->mealType = $mealType;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$mealTypes = $this->mealType->all();
return View::make('mealTypes.index')->with('mealTypes' ,$mealTypes);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$mealType = new MealTypeEloquent;
$action = 'MealTypeController#store';
$method = 'POST';
return View::make('mealTypes.create_edit', compact('mealType' , 'action' , 'method') );
}
/**
* Validator does not work properly in tests.
* Store a newly created resource in storage.
*
* #return Response
*/
public function store(Request $request)
{
$input = ['name' => $request->input('name')];
$mealType = new $this->mealType;
$v = $mealType->getValidator($input);
if( $v->passes() )
{
$this->mealType->create($input);
return Redirect::to('mealType');
}
else
{
$this->errors = $v;
return Redirect::to('mealType/create')->withErrors($v);
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
return View::make('mealTypes.show' , ['mealType' => $this->mealType->find($id)]);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
$mealType = $this->mealType->find($id);
$action = 'MealTypeController#update';
$method = 'PATCH';
return View::make('mealTypes.create_edit')->with(compact('mealType' , 'action' , 'method'));
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
$mealType = $this->mealType->find($id);
$mealType->name = \Input::get('name');
$mealType->save();
return redirect('mealType');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
$this->mealType->find($id)->delete();
return redirect('mealType');
}
}
That should be everything. It's worth to say that the application works, just tests are screwed up.
Does anybody know, why is that happening? I cant see a difference between methods of TestCase - testIndex and testStoreFails, why method "all" is found and "getValidator" is not.
I will be thankful for any tips of advices.
Perhaps an aside, but directly relevant to anyone finding this question by its title:
If:
You are getting the error BadMethodCallException: Method Mockery_0_MyClass::myMethod() does not exist on this mock object, and
none of your mocks are picking up any of your subject's methods, and
your classes are being autoloaded, (e.g. using composer)
then before making your mock object, you need to force the loading of that subject, by using this line of code:
spl_autoload_call('MyNamespace\MyClass');
Then you can mock it:
$mock = \Mockery::mock('MyNamespace\MyClass');
In my PHPUnit tests, I often put that first line into the setUpBeforeClass() static function, so it only gets called once and is isolated from tests being added/deleted. So the Test class looks like this:
class MyClassTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
spl_autoload_call('Jodes\MyClass');
}
public function testIt(){
$mock = \Mockery::mock('Jodes\MyClass');
}
}
I have forgotten about this three times now, each time spending an hour or two wondering what on earth the problem was!
I have found a source of this bug in controller.
calling wrong
$v = $mealType->getValidator($input);
instead of right
$v = $this->mealType->getValidator($input);

laravel/eloquent mutators/accessors in a pivot table

Well, I think the title explains most of it. Lets get right into it!
Blank Model:
class Blank extends Eloquent
{
protected $table = 'blanks';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated jobs.
*
* #return mixed
*/
public function jobs()
{
return $this->belongsToMany('Job')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Job Model:
class Job extends Eloquent
{
protected $table = 'jobs';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated blank.
*
* #return mixed
*/
public function blanks()
{
return $this->belongsToMany('Blank')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Attaching Code:
$job->blanks()->attach($blank->id,[
'status' => Input::get('status'),
'inventory' => Input::get('inventory'),
//'sizes' => $sizes,
'mill' => Input::get('mill'),
'po' => Input::get('po'),
'location' => Input::get('location'),
'ordered_at' => Carbon::parse(Input::get('ordered_at'))->format('Y-m-d H:i:s'),
'expected_at' => Carbon::parse(Input::get('expected_at'))->format('Y-m-d H:i:s'),
'note' => Input::get('note'),
]);
The mutator is not being called at all.. Any ideas?
Seems like that not possible to do this through ::attach() method.
But maybe you would like to use 'Defining A Custom Pivot Model'
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
return new YourCustomPivot($parent, $attributes, $table, $exists);
}
So, you can define your own pivot class with mutators:
class BlankJobPivot extends Eloquent
{
// ...
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($value);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->attributes['sizes'] = json_encode($value);
return $value; // return for multiple assignment statement: $arr = $pivot->sizes = array(12, 23, 34);
}
}
And than you can use getters:
$blank->jobs[$i]->pivot->sizes; // - ::getSizesAttribute() will called ( I hope :) )
And maybe you will find a way to save / attach through the setSizesAttribute mutator.
Good luck.

laravel 4 pivot table save not working

I am having trouble saving(creating new row) with extra data to a pivot table.
I am having to use a legacy db schema (that is still working on a live site). I am currently redoing the site in Laravel.
<?php namespace Carepilot\Repositories\Organizations;
use Carepilot\Repositories\EloquentRepositoryAbstract;
/*
* This class is the Eloquent Implementation of the Organization Repository
*/
class OrganizationRepositoryEloquent extends EloquentRepositoryAbstract implements OrganizationRepositoryInterface {
/*
* Define Eloquent Organization Type Relation.
*
*/
public function orgtypes()
{
return $this->belongsToMany('Carepilot\Repositories\OrganizationTypes\OrganizationTypesRepositoryEloquent', 'organizations_orgtypes', 'organization_id', 'orgtype_id')
->withPivot('objectstate_id');
}
}
<?php namespace Carepilot\Repositories\OrganizationTypes;
use Carepilot\Repositories\EloquentRepositoryAbstract;
/*
* This class is the Eloquent Implementation of the Organization Repository
*/
class OrganizationTypesRepositoryEloquent extends EloquentRepositoryAbstract implements OrganizationTypesRepositoryInterface {
protected $table = 'orgtypes';
/*
* Define Eloquent Organization Type Relation.
*
*/
public function organizations()
{
return $this->belongsToMany('Carepilot\Repositories\Organizations\OrganizationRepositoryEloquent', 'organizations_orgtypes', 'organization_id', 'orgtype_id')
->withPivot('objectstate_id');
}
}
Here in the Orgaizations controller I try to save a new organization but get an error in the pivot table.
<?php
use \Carepilot\Repositories\Organizations\OrganizationRepositoryInterface;
use \Carepilot\Repositories\Procedures\ProcedureRepositoryInterface;
use \Carepilot\Helpers\StatesHelper;
class OrganizationsController extends BaseController {
/**
* Organization Repository
*
* #var organization_repo
*/
protected $organization_repo;
protected $procedures;
protected $states;
public function __construct(OrganizationRepositoryInterface $organization_repo,
ProcedureRepositoryInterface $procedures,
StatesHelper $states)
{
$this->organization_repo = $organization_repo;
$this->procedures = $procedures;
$this->states = $states;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
return View::make('organizations.index');
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$supportedStates = ['' => 'Choose'] + $this->states->supportedStates();
$procedures = $this->procedures->getDropDown();
return View::make('organizations.create', compact('supportedStates', 'procedures'));
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$input = Input::all();
// validation here
$new_organization = $this->organization_repo->create(array_only($input, ['organization_name']));
$input['objectstate_id'] = 27;
$input['orgtype_id'] = 1;
$new_organization->orgtypes->pivot->create(array_only($input, ['objectstate_id', 'orgtype_id']));
$new_organization->addresses()->create(array_only($input, ['street1', 'zip', 'city', 'state_code']));
$input['objectstate_id'] = 4;
$new_organization->users()->create(array_only($input, ['first_name', 'last_name', 'email', 'password', 'objectstate_id']));
return "completed";
}
This returns "Undefined property: Illuminate\Database\Eloquent\Collection::$pivot” because the pivot has not been created yet. What am I missing?
I found that the 'attach' method does what I want with something like
$new_organization->orgtypes()->attach(1, ['objectstate_id' => '27']);

Categories