I have simple comment rating logic now.
For example i have following controller :
public function rating_change(Request $request, Comment $comment)
{
if ($request['action'] == 'up') {
$comment->positive_rating = $comment->positive_rating + 1;
} else if ($request['action'] == 'down') {
$comment->negative_rating = $comment->negative_rating + 1;
}
$comment->save();
return ['positive' => $comment->positive_rating, 'negative' => $comment->negative_rating];
}
And the route for that method:
Route::put('/comments_rating/{comment}', function (Comment $comment, Request $request) {
$commentController = new CommentController();
return $commentController->rating_change($request, $comment);
});
Model:
class Comment extends Model
{
use HasFactory;
protected $fillable = [
'body',
'user_id',
'item_id'
];
protected $casts = [
'user_id' => 'integer',
'item_id' => 'integer',
];
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
public function post()
{
return $this->belongsTo(Items::class, 'id');
}
}
And resource:
return [
'id' => $this->id,
'user_id'=>$this->user_id,
'body'=>$this->body,
//https://github.com/jenssegers/date
'created_at' => Date::parse($this->created_at)->diffForHumans(),
'updated_at' => $this->updated_at->format('Y-m-d H:i'),
'author'=>[
'id'=>$this->author->id,
'name'=>$this->author->name,
],
'rating'=>[
'positive'=>$this->positive_rating,
'negative'=>$this->negative_rating
]
];
The current purpose to prevent change rating by the same user multiple times.(Server side block)
And return the following flag (changed or smth) to frontend.
How should i to do this?
Should i use the separate table and store all user actions to get flag of changed them in all my comments?
Should i use the https://laravel.com/docs/8.x/redis for that purpose or sql is enough?
Maybe there is some built in laravel solutions or libraries?
I use laravel sanctum to authorize.
Related
I made a Models controller and use it as resources for almost all my Model. Now, when I try to get the data of a model and the related models, Laravel replace upper case letter with an underscore and the lower case letter. I need to let it with the upper case.
So there is the model where I got the issue at App\Models\Rate:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Rate extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'rates';
protected $fillable = [
'institution_id',
'name',
];
protected $info = [
'relations' => [
'rateRistournes' => [
'model' => 'RateRistourne',
'type' => 'hasMany',
],
'rateRows' => [
'model' => 'RateRow',
'type' => 'hasMany',
],
'rateTables' => [
'model' => 'RateTable',
'type' => 'hasMany',
],
],
'rules' => [
],
'hashid' => false,
];
public function getRelations()
{
return $this->info['relations'];
}
public function getRules()
{
return $this->info['rules'];
}
public function useHashid()
{
return $this->info['hashid'];
}
public function institution()
{
return $this->belongsTo(Institution::class);
}
public function rateTables()
{
return $this->hasMany(RateTable::class);
}
public function rateRows()
{
return $this->hasMany(RateRow::class);
}
public function rateRistournes()
{
return $this->hasMany(RateRistourne::class);
}
}
And this is the function that contain the query into ModelsController:
public function show($name, $id)
{
$data = $this->retrieveModelAndRelations($name, $id);
if (is_null($data)) {
return $this->sendError('Model not found.');
}
return $this->sendResponse($data->toArray(), 'Model retrieved successfully.');
}
private function retrieveModelAndRelations($name, $id)
{
$modelName = 'App\Models\\'.$name;
$model = new $modelName;
if ($id === 'null') {
...
} else {
$data = $modelName::when(isset($model->getRelations()['customer']), function($query) {
return $query->with('customer');
})...
})->when(isset($model->getRelations()['rateTables']), function($query) {
return $query->with(array('rateTables' => function($q) {
$q->orderBy('cashStart', 'ASC');
}));
})->when(isset($model->getRelations()['rateRows']), function($query) {
return $query->with(array('rateRows' => function($q) {
$q->orderBy('rate', 'ASC');
}));
})->when(isset($model->getRelations()['rateRistournes']), function($query) {
return $query->with(array('rateRistournes' => function($q) {
$q->orderBy('ristourne', 'ASC');
}));
})->find($id);
}
return $data;
}
And there is the result into the console:
created_at:(...)
deleted_at:(...)
id:(...)
institution_id:(...)
name:(...)
rate_ristournes:Array(1)
rate_rows:Array(1)
rate_tables:Array(1)
The 3 last line should be:
rateRistournes:Array(1)
rateRows:Array(1)
rateTables:Array(1)
Is there a way to force laravel to keep the relation key as I wrote it?
Something under the hood change the name and I don't know how to bypass it.
Change $snakeAttributes:
class Rate extends Model
{
public static $snakeAttributes = false;
}
I have one DB which has 3 tables: user, statuses and friends.
My status table has a relationship column "parent id" which is NULL but stores the user_id of a user that replies to a status. Below is my Status.php code:
namespace Pictogram\Models;
use Illuminate\Database\Eloquent\Model;
class Status extends Model
{
protected $table = 'statuses';
protected $fillable = [
'body'
];
public function user()
{
return $this->belongsTo('Pictogram\Models\User', 'user_id');
}
public function scopeNotReply($query)
{
return $query->whereNull('parent_id');
}
public function replies()
{
return $this->hasMany('Pictogram\Models\Status', 'parent_id');
}
}
And blow is from my route file: This controls replies to status
Route::post('/status', [
'uses' => '\Pictogram\Http\Controllers\StatusController#postStatus',
'as' => 'status.post',
'middleware' => ['auth'],
]);
Route::post('/status/{statusId}/reply', [
'uses' => '\Pictogram\Http\Controllers\StatusController#postReply',
'as' => 'status.reply',
'middleware' => ['auth'],
]);
And my status controller .php
class StatusController extends Controller
{
public function postStatus(Request $request)
{
$this->validate($request, [
'status' => 'required',
]);
Auth::user()->statuses()->create([
'body' => $request->input('status'),
]);
return redirect()
->route('home')
->with('info', 'Status updated.');
}
public function postReply(Request $request, $statusId)
{
$this->validate($request, [
"reply-{$statusId}" => 'required',
], [
'required' => 'The reply body is required.'
]);
$status = Status::notReply()->find($statusId);
if (!$status) {
return redirect()->route('home');
}
if (!Auth::user()->isFriendsWith($status->user) && Auth::user()->id !== $status->user->id)
{
return redirect()->route('home');
}
$reply = Status::create([
'body' => $request->input("reply-{$statusId}"),
])->user()->associate(Auth::user());
$status->replies()->save($reply);
return redirect()->back();
}
}
And lastly this is the line 2673 of models .php below:
protected function getRelationshipFromMethod($method)
{
$relations = $this->$method();
if (! $relations instanceof Relation) {
throw new LogicException('Relationship method must return an object of type '
.'Illuminate\Database\Eloquent\Relations\Relation');
}
return $this->relations[$method] = $relations->getResults();
}
I am using Laravel 5.2. Now my issue is that the reply gets save to the table because the empty parent_id then takes the user_id of the user who replied but then it brings up an error page that has these errors below.
Error1/2
Error2/2
Make sure your relationship name is proper in Status model.
check your replies() realtion in Status model.
it return the Status Relationship i should be the realtion of replies i.e Reply
public function replies()
{
return $this->hasMany('Pictogram\Models\Reply', 'parent_id');
}
I need to update the items for specific order with Eloquent.
I have this models:
class Orders extends \Illuminate\Database\Eloquent\Model
{
public $timestamps = false;
protected $fillable = ['items_array'];
public function items()
{
return $this->hasMany(Items::class, 'order_id', 'order_id');
}
public function setItemsArrayAttribute($data)
{
$this->items()->whereIn('article_id', array_map(function($item){
return $item['article_id'];
}, $data['items']))->update($data);
}
}
class Items extends \Illuminate\Database\Eloquent\Model
{
protected $table = 'order_to_items';
public $timestamps = false;
protected $fillable = ['internal_code'];
public function order()
{
return $this->belongsTo(Orders::class, 'order_id', 'order_id');
}
}
I have the api response like that:
$response = [
'message'=>'some',
'order_id'=>'111-222-333',
'items'=>[
[
'article_id' => 'R-320108',
'internal_code' => 333
],
[
'article_id' => 'R-320116',
'internal_code' => 444
],
]
];
So I make this
$order = Orders::where('order_id', $response['order_id'])->with('items')->first();
and I was trying to make this:
$order->update([
'is_sent' => true,
'items_array' => $response['items']
]);
but that doesn't work. Is there any way to match the related model with API response and make update?
Thanks!
You can use save():
$order->is_sent = true;
$order->items_array = $response['items'];
$order->save();
Or update():
$order = Orders::where('order_id', $response['order_id'])
->update([
'is_sent' => true,
'items_array' => $response['items']
]);
I'm trying to seed a database using some model factories but I'm getting error call to member function create() on a non-object
Below are my model factories:
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->make()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->make()->id,
'remember_token' => str_random(10),
];
});
In my seeder I'm using the following to create 2 organizations and a associate a user and a department to each organization and then to make a user the manager of that department:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = $o->users()->save(factory(App\User::class)->make());
$department = $o->departments()->save(factory(App\Department::class)->make());
$department->managedDepartment()->create([
'organisation_id' => $o->id,
'manager_id' => $user->id,
]);
});
However I'm getting fatalerrorexception call to member function create() on a non-object
I thought $department is an object?
My department model is as follows:
class Department extends Model
{
protected $fillable = ['name','organisation_id'];
public function organisation()
{
return $this->belongsTo('App\Organisation');
}
/* a department is managed by a user */
public function managedDepartment()
{
$this->hasOne('App\ManagedDepartment');
}
}
And my managedDepartment model is as follows:
class ManagedDepartment extends Model
{
protected $table = 'managed_departments';
protected $fillable = ['organisation_id', 'department_id', 'manager_id',];
public function department()
{
$this->belongsTo('App\Department');
}
public function manager()
{
return $this->belongsTo('App\User');
}
}
Can anyone help?
Try to return your relation
public function department()
{
return $this->belongsTo('App\Department');
}
And here
/* a department is managed by a user */
public function managedDepartment()
{
return $this->hasOne('App\ManagedDepartment');
}
I think it will resolve your problem.
Firstly, do not make foreign keys fillable!
Secondly, where is your organisation function in ManagedDepartment? You should create one, otherwise the following will not work, because association is not possible.
Thirdly, I think you should change make() to create() in the following
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->create()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->create()->id,
'remember_token' => str_random(10),
];
});
Furthermore:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = factory(App\User::class)->create();
$o->users()->attach($user->id);
$department = factory(App\Department::class)->create();
$o->departments()->attach($department);
$managedDep = new ManagedDepartment();
$managedDep->associate($o);
$managedDep->associate($user);
$managedDep->associate($department);
$managedDep->save();
});
I'm making a multi select form element for updating schools and specialties pivot table school_specialty. The problem is that when I change only something in multi select not other inputs or textareas, I can't listen model events so I can't sync school_specialty table. But when I fill in any other input it's works perfect. Here's my multi select from blade:
{{Form::select('specialties[]', $specialties_data, $school->specialties, array('multiple' => 'true', 'id' => 'multi-select'))}}
This is my update method from school controller:
public function update($id)
{
$data = Input::only('name', 'type_id', 'description', 'info_specialties', 'contacts', 'specialties', 'financing_id', 'district_id', 'city_id');
$school = School::find($id);
$school->name = $data['name'];
$school->type_id = $data['type_id'];
$school->description = $data['description'];
$school->info_specialties = $data['info_specialties'];
$school->contacts = $data['contacts'];
$school->cover_photo = Input::file('cover_photo');
$school->set_specialties = $data['specialties'];
$school->financing_id = $data['financing_id'];
$school->set_district_id = $data['district_id'];
$school->city_id = $data['city_id'];
try {
$school->save();
} catch (ValidationException $errors) {
return Redirect::route('admin.schools.edit', array($id))
->withErrors($errors->getErrors())
->withInput();
}
return Redirect::route('admin.schools.edit', array($id))
->withErrors(array('mainSuccess' => 'School was created.'));
}
And here's my example school model:
<?php
class School extends Eloquent {
protected $table = 'schools';
protected $fillable = array('name', 'type_id', 'description', 'city');
protected $guarded = array('id');
protected $appends = array('specialties');
public $set_specialties;
public $set_district_id;
protected static function boot()
{
parent::boot();
static::updating(function($model)
{
$data = array(
'name' => $model->name,
'type_id' => $model->type_id,
'description' => $model->description,
'specialties' => $model->set_specialties,
'city_id' => $model->city_id
);
$rules = array(
'name' => 'required|min:3|max:50',
'type_id' => 'required|min:1|max:300000',
'description' => 'required|min:10',
'specialties' => 'required|array',
'city_id' => 'required|min:1|max:300000'
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
throw new ValidationException(null, null, null, $validator->messages());
} else {
return true;
}
});
static::updated(function($model)
{
if ( $model->set_specialties != null )
{
$model->specialty()->sync($model->set_specialties);
}
});
}
public function specialty()
{
return $this->belongsToMany('Specialty', 'school_specialty');
}
}
?>
When updating only school specialities the School model events aren't triggered because the School model stays the same.
I think the simplest and most elegant solution is to touch the school model instance. This will modify the updated_at field for the School object and thus trigger the model events.
To do this add the following lines before the try/catch block:
if ($school->set_specialties !== null) {
$school->touch();
}
Also, validation shouldn't be handled in the model observers. Check form request validation here: https://laravel.com/docs/5.6/validation#form-request-validation.