I have a table called messages and users. the users is the default users table generated by laravel auth. for some reason in my postMessage function in my controller when i try the return
return response()->json(['s' => $broadcastMessage, 'r' => $broadcastMessage->MessageOwner()]);
the relationship ship returns an empty object. i know that the MessageOwner relationship works because i use it in a different function and it works fine but i can't figure out why it wont work here? I made sure and it stores the user_id and it's the correct id.
Note that it does return the message.
here is migration up function
Schema::create('messages', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users');
$table->longText('message');
$table->timestamps();
});
here is my message model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
protected $table = 'messages';
protected $fillable = [
'user_id', 'message'
];
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function MessageOwner()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function job()
{
return $this->belongsToMany(Job::class);
}
}
and here is my controller function
public function postMessage(Request $request)
{
try {
$message = Message::create([
'user_id' => $request->input('user_id'),
'message' => $request->input('message')
]);
$job = Job::find($request->input('job_id'));
$job->messages()->attach($message);
$broadcastMessage = Message::find($message->id);
return response()->json(['s' => $broadcastMessage, 'r' => $broadcastMessage->MessageOwner()]);
event(new MessagePushed($broadcastMessage));
return response()->json([
'success' => true,
'message' => 'success',
]);
} catch (\Exception $exception) {
return response()->json([
'success' => false,
'error' => true,
'message' => $exception->getMessage()
], 500);
}
}
You are calling the relationship method, not the it's value.
Try without the ():
return response()->json(['s' => $broadcastMessage, 'r' => $broadcastMessage->MessageOwner]);
Also you should consider using lower_snake_case for all your relationship methods and name the foreign key by relationshio_name_id, so you don't need to manually define the foreign key name, Laravel will automatically guess it.
Related
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.
I'm new to Laravel so I struggle. I have a comment system that worked perfectly fine but now I want to also add a reply system to it. So the way I decided to do it, is by adding a parent_id column to the comments table and then check if a comment has a parent. But I don't know how exactly the store method, in this case, should work. Here's my database set up for comments:
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->text('body');
$table->timestamps();
});
}
And now a set up for the reply column:
public function up()
{
Schema::table('comments', function (Blueprint $table) {
$table->unsignedBigInteger('parent_id')->nullable();
$table->foreign('parent_id')->references('id')->on('comments');
});
}
Model:
class Comment extends Model{
use HasFactory;
protected $guarded = [];
public function post()
{
return $this->belongsTo(Post::class);
}
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
public function replies() {
return $this->hasMany('App\Comment', 'parent_id');
}
}
Controller:
public function store(Post $post){
request()->validate([
'body' => 'required'
]);
$post->comments()->create([
'user_id' => request()->user()->id,
'parent_id' => request()->get('id'),
'body' => request('body')
]);
return back();
}
I just don't know how exactly I can get parent_id in the store function so I would appreciate some suggetstions
it should be the comment id that got the reply
something like this
$post->comments()->create([
'user_id' => request()->user()->id,
'parent_id' => request()->get('comment_id'),
'body' => request('body')
]);
I hope it's helpful
use code :
public function store(Post $post) {
request()->validate([
'body' => 'required'
]);
$post->comments()->create([
'user_id' => request()->user()->id,
'parent_id' => request()->get('comment_id'),
'body' => request('body')
]);
return back();
}
I have User and Activity models. User hasMany relationship to Activity (and an Activity belongsTo only one User):
In User model:
public function activities() {
return $this->hasMany(Activity::class);
}
I want to seed the users with their corresponding activities. I tried this but did not work:
public function run()
{
factory(App\User::class, 5)->create()->each(function ($user) {
$user->activities()->saveMany(factory(App\Activity::class, 2)->make());
});
}
ActivityFactory:
$factory->define(App\Activity::class, function (Faker $faker) {
return [
'title' => $faker->text(50),
'description' => $faker->text(200)
];
});
What am I doing wrong?
Try this way:
database/factories/ActivityFactory.php
$factory->define(App\Activity::class, function (Faker\Generator $faker) {
return [
'user_id' => factory('App\User')->create()->id,
'title' => $faker->text(50),
'description' => $faker->text(200),
];
});
database/seeds/ActivitySeeder.php
public function run()
{
factory(App\Activity::class, 10)->create();
}
And then run for the activity seed.
php artisan make:seeder ActivitySeeder
I have a model Foo, which has many Bars:
class Foo extends Model
{
public function bars()
{
return $this->hasMany('App\Bar');
}
}
class Bar extends Model
{
public function foo()
{
return $this->belongsTo('App\Foo');
}
}
When saving a new Foo, the request payload comes with an array of Bar ids. I want to save these at the same time. This works:
public function store(StoreFoo $request)
{
$foo = Foo::create($request->validated());
foreach ($request->barIds as $barId) {
$foo->bars()->create(['bar_id' => $barId]);
}
}
My question is: is there a way to do this without a loop? I've tried sync and attach but these aren't applicable in this case.
The only way I can think of that you can achieve this without writing a loop yourself is by using the saveMany method on the HasMany relation. You can create instances of your Bar model and pass them all as an array to the saveMany method and that will save all of them and return an array of the created entities in response.
$foo->bars()->saveMany([new Bar(['id' => 1]), new Bar(['id' => 2])]);
That being said, Laravel uses a loop to save these models one by one under the hood so it doesn't really do much different to what you're doing now.
Similarly, there's also a createMany method that you can use in the same way as saveMany but instead of providing newly created models, you can provide arrays of attributes instead.
migration table sample
Schema::create('logs', function(Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->default(0)->index();
$table->string('type', 10)->index(); // add, update, delete
$table->string('table', 50)->index();
$table->unsignedBigInteger('row');
$table->dateTime('created_at');
});
Schema::create('log_fields', function(Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('log_id')->index();
$table->string('field', 50)->index();
$table->longText('old');
$table->longText('new');
});
model Log.php file
class Log extends Model
{
const UPDATED_AT = null;
protected $fillable = [
'user_id',
'type',
'table',
'row'
];
public function logFields()
{
return $this->hasMany(LogField::class);
}
}
model LogField.php file
class LogField extends Model
{
public $timestamps = false;
protected $fillable = [
'field',
'old',
'new'
];
public function log()
{
return $this->belongsTo(Log::class);
}
}
boot function for another model for save change in database.
hook created, updating and deleting for answer your question
public static function boot()
{
parent::boot();
static::created(function($resorce) {
$_log = new Log;
$_log->create([
'user_id' => session('uid', 0),
'type' => 'add',
'table' => $resorce->getTable(),
'row' => $resorce->fresh()->toArray()['id']
]);
return true;
});
static::updating(function($resorce) {
$_log = new Log;
$log = $_log->create([
'user_id' => session('uid', 0),
'type' => 'update',
'table' => $resorce->getTable(),
'row' => $resorce->fresh()->toArray()['id']
]);
foreach($resorce->getDirty() as $field => $new) {
$log->logFields()->create([
'field' => $field,
'old' => $resorce->fresh()->toArray()[$field],
'new' => $new
]);
}
return true;
});
static::deleting(function($resorce) {
$_log = new Log;
$log = $_log->create([
'user_id' => session('uid', 0),
'type' => 'delete',
'table' => $resorce->getTable(),
'row' => $resorce->id,
]);
foreach($resorce->fresh()->toArray() as $field => $value) {
$log->logFields()->create([
'field' => $field,
'old' => '',
'new' => $value
]);
}
return true;
});
}
Hope I have helped you to understand this.
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');
}