Eloquent save() throws internal server error - laravel

I'm building some API app using Slim3 and Eloquent as ORM for model, and having some strange issue.
When I save model, I get internal server error, and can't catch error at all.
My model have only two columns, id pk autoincrement and name (string 255)
this is my settup:
Model:
class Version extends Illuminate\Database\Eloquent\Model
{
protected $table = 'version';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name'];
protected $hidden = ['id'];
}
Action:
public function create(RequestInterface $request, ResponseInterface $response)
{
$params = $request->getParsedBody();
$class = $this->model; //fully namespaced class name
$model = new $class();
$model->fill($params);
return $model->save() ?
$this->success($response, "{$this->getModelName()} successfully saved.") :
$this->error($response, $model->errors());
}
I manager to localize issue to this part of code in Illuminate\Database\Eloquent\Builderline #1242
if (in_array($method, $this->passthru)) {
return call_user_func_array([$this->toBase(), $method], $parameters);
}
But I have no idea what is wrong
EDIT:
I'm using PHP/7.0.0-dev and Slim 3.1
Is Eloquent PHP 7 compatible?

Your Model is a Eloquent Model so to create you can use following code
$version = App\Version::create(['name' => 'Your version name']);
This will remove all the unnecessary functions, and keept yuor code clean.
In your case make sure the $request->getParsedBody();
returns the correct format for Eloquent to use it.

Related

Eloquent relationship update appropriate database fields in Laravel

I have BelongsTo model between 3 database (Admins, vendors, and vendor_business_table) table in Laravel. Trying to save the data which comes from HTML form in appropriate database field. My Admin Model looks like below:
class Admin extends Authenticatable
{
use HasFactory;
protected $guard = 'admin';
public function getVendorDetails(){
return $this->belongsTo(Vendor::class, 'vendor_id','vendor_id');
}
public function getVendorBusinessDetails(){
return $this->belongsTo(VendorBusinessDetails::class, 'vendor_id','vendor_id');
}
}
Once all the data is sent from the form I am trying to catch and save the fields. We have only id field is foreign key.
public function editVendorsDetails(Request $request,$id){
if($request->isMethod('post')){
$data = $request->all();
$myModel = Admin::with('getVendorDetails')->find($id);
$myModel->getVendorDetails->fill($data);
$myModel->getVendorDetails->save();
Once I save the form nothing is changed. Am I missing something here? Your help would be highly appreciated.
Would you please replace your code with this code in editVendorDetails()
if($request->isMethod('post')){
$data = $request->all();
$myModel = Admin::with('getVendorDetails')->find($id);
$myModel->getVendorDetails()->create($data);
}
// fill this array which field you want to store like name
protected $fillable = ['name'];
or
protected $guarded = [];
Have a look at is Mass Assignment Documantation.

Laravel relationship with additional where statement

I know I can define a relationship by
Class Users extends Model{
function profile(){
return $this->hasOne(Profile::Class);
}
}
is there a way like adding extra query to the relationship like other than foreign key and local key that is available to define, I want to only get those records of Profile model that field active contains a value of 1. Profile model has a field named active. Any help, ideas is greatly appreciated, thank you in advance.
you can simply try
return $this->hasOne(Profile::Class)->where('active', 1);
but better approach will be using Scope like this.
create a folder app/Scopes and add a new file ActiveUserOnly.php
place this code there
namespace App\Scopes;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
use \Illuminate\Database\Eloquent\Model;
class ActiveUsersOnly implements Scope {
/**
* #inheritdoc
*
* #param Builder $builder
* #param Model $model
*
* #return Builder|void
*/
public function apply( Builder $builder, Model $model ) {
return $builder->where( 'active', '=', true );
}
}
add this code to the top of Profile model.
use App\Scopes\ActiveProfilesOnly;
add this code in your Profile model.
protected static function boot() {
parent::boot();
static::addGlobalScope( new ActiveProfilesOnly() );
}
then this code will work in your User model.
Class Users extends Model{
function profile(){
return $this->hasOne(Profile::Class);
}
}

Laravel - Collection::delete method does not exist

I am trying to test the boot() static::deleting method, which should fire when a model is deleted through Eloquent.
The command in tinker App\User::find(6)->delete(); returns a 'method [...]Collection::delete does not exist'.
If I try to use App\User::where('id', 6)->delete(); then the static::deleting method does not get triggered since Eloquent is not loaded. If I load Eloquent with ->first() then I get the same error that states method does not exist.
Here is the entire user model
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
public function profile() {
return $this->hasOne(Profile::class);
}
public function posts() {
return $this->hasMany(Post::class);
}
public function tempUploads() {
return $this->hasMany(TempUploads::class);
}
protected static function boot() {
parent::boot();
static::created(function ($user) {
$user->profile()->create(['id' => $user->username, 'avatar' => '/storage/avatars/edit-profile.png']);
mkdir(public_path() . "/storage/images/" . $user->username , 0755);
// $data = [
// 'user_id' => $user->username
// ];
// Mail::to($user->email)->send(new WelcomeMail($data));
});
static::deleting(function ($user) {
$user->posts->delete();
if ($user->profile->avatar != '/storage/avatars/edit-profile.png') {
if ($user->profile->cover != NULL && $user->profile->cover != '') {
$oldAvatar = $_SERVER['DOCUMENT_ROOT'] . $user->profile->avatar;
$oldCover = $_SERVER['DOCUMENT_ROOT'] . $user->profile->cover;
if (is_file($oldAvatar) && is_file($oldCover)) {
unlink($oldAvatar);
unlink($oldCover);
} else {
die("Грешка при изтриване на стария файл. File does not exist in profile deleting method.");
}
}
}
$user->profile->delete();
});
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'username', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
I have spent hours now looking through google for possible solutions but nothing has yet.
How should I properly delete a User model while triggering the boot deleting method ?
In your deleting listener you are trying to delete something else, which is a Collection which is causing the error.
$user->posts is a relationship to Posts which is a plural which is a hasMany relationship (most likely) so it returns a Collection always. Collections do not have a delete method. You will have to iterate through the collection and call delete on each Post
// calling `delete()` on a Collection not a Model
// will throw the error you see
$user->posts->delete();
// iterate through the Collection
foreach ($user->posts as $post) {
$post->delete();
}
Side Note: you can not do any action in bulk with Models and queries and have the events be fired. All Model events are based on single instances of the Models. A direct query bypasses the Model.
You can optimise lagbox's answer by using only one query to delete all of the posts. In his example he's executing a delete query for every post attached to the user.
For a single delete query either use the query builder of the relationship directly:
$user->posts()->delete();
or use the pluck method of the collection and a separate query:
Post::where('id', $user->posts->pluck('id'))->delete();
You can use higher order messages as well:
$user->posts->each->delete();
$user->posts->map->delete()
I used this in my Controller File to delete the Database Entry:
public function destroy(Item $id) {
$id->destroy($id->id);
//return view('inv.delete', compact('id'));
return redirect('/inv');
}
$user->posts()->delete() will work
$user->posts->delete() will not work
Because $user->posts() is a query , not a collection

What is different between save(), create() function in laravel 5

I need to know what is the difference of save() and create() function in laravel 5.
Where we can use save() and create() ?
Model::create is a simple wrapper around $model = new MyModel(); $model->save()
See the implementation
/**
* Save a new model and return the instance.
*
* #param array $attributes
* #return static
*/
public static function create(array $attributes = [])
{
$model = new static($attributes);
$model->save();
return $model;
}
save()
save() method is used both for saving new model, and updating
existing one. here you are creating new model or find existing one,
setting its properties one by one and finally saves in database.
save() accepts a full Eloquent model instance
$comment = new App\Comment(['message' => 'A new comment.']);
$post = App\Post::find(1);
$post->comments()->save($comment);
create()
while in creating method you are passing an array, setting properties in
model and persists in the database in one shot.
create() accepts a plain
PHP array
$post = App\Post::find(1);
$comment = $post->comments()->create([
'message' => 'A new comment.',
]);
EDIT
As #PawelMysior pointed out, before using the create method, be sure to mark columns whose values are safe to set via mass-assignment (such as name, birth_date, and so on.), we need to update our Eloquent models by providing a new property called $fillable. This is simply an array containing the names of the attributes that are safe to set via mass assignment:
example:-
class Country extends Model {
protected $fillable = [
'name',
'area',
'language',
];
}

Trouble getting attribute of relation in Laravel

I'm having a trouble with a relation in Laravel 5. the thing is that I have a table User and that user belongs to a Group for that, in the User model I have this:
public function group(){
return $this->belongsTo('App\models\Group');
}
The model Group have this attributes: name,unity,level, init_date. I also put there a default function to return a group as String, this is the code:
public function __toString(){
return $this->name.' Unity '.$this->unity;
}
So, the thing that in a view a have many users and for each of them I want to display the unity, name,date. When I call $user->group it returns me correctly the name and the unity in a String (because the _toString function) that means that he is really querying the group perfectly, but then, when I want to access a simple attribute as unity,date,or name with $user->group->name Laravel gives me this error:
Trying to get property of non-object
I even tried $user->group()->name then I gets: Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$name
Edited:
The model User:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['email', 'password','estate','filial_id','perfil_id','rol','cat_teacher'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function __toString(){
return $this->email;
}
public function filial(){
return $this->belongsTo('App\models\Filial');
}
public function perfil(){
return $this->belongsTo('App\models\Perfil','perfil_id');
}
public function grupo(){
return $this->belongsTo('App\models\Group','group_id','id');
}
}
The model Group:
class Group extends Model {
protected $table = 'groups';
protected $fillable = ['name','unity','date'];
public function filiales() {
return $this->belongsTo('App\models\Filial');
}
public function teacher(){
return $this->belongsTo('App\models\User','teacher_id');
}
public function users() {
return $this->hasMany('App\models\User');
}
}
Then, in the controller I made a dd($users) and there not appear the relations, appears other relations but not this one. In the view I want to print some of the attributes in a table, for that I have:
<td>{{$user->group}}</td>
<td>{{$user->group->unity}}</td>
The first line works perfectly, and I don´t know why.
The reason you're unable to return your group's name is that ->group() returns an instance of the query builder, and not an eloquent collection/object. Since a user belongs to a single group, modify your code in one of these two ways:
public function group(){
return $this->belongsTo('App\models\Group')->first();
}
And then access the group using one of the following methods:
$user = User::with("group")->where("id", "=", 1)->first();
$group = $user->group;
echo $group->name;
// OR
$user = User::where("id", "=", 1)->first();
$group = $user->group();
echo $group->name;
Or, leave the group() function as it is and access ->group()->first() on your $user object:
$user = User::where("id", "=", 1)->first();
$group = $user->group()->first();
echo $group->name;
Any of the above methods should properly return your group object's name (or other attributes). Check the Eloquent Documentation for detailed explanations on how to access these objects.

Resources