i am creating A notifcation for user that created a new post on my site and the user will be awarded point after creating a post, so when a user create a post and get a point send notification but im getting this error
👉 Property [id] does not exist on this collection instance.
please how can I resolve this issue kindly assist me
<?php
namespace App\Http\Livewire;
use App\Gamify\Points\PostCreated;
use App\Models\Category;
use App\Models\Post;
use App\Models\Tag;
use App\Models\User;
use App\Notifications\PointAdd;
use Illuminate\Support\Str;
use Livewire\Component;
use Illuminate\Http\Response;
use Livewire\WithFileUploads;
class PostCreate extends Component
{
use WithFileUploads;
public $post;
public $user;
public $body;
public $slug;
public $photo;
public $title;
public $category = 1;
public $points = 10;
public $energy = 1;
public function increment()
{
$this->points++;
}
protected $rules = [
'category' => 'required|integer|exists:categories,id',
'title' => 'required|min:4',
'body' => 'required|min:4',
];
public function createPost()
{
if (auth()->check()) {
$this->validate();
$random = str_pad(mt_rand(1,999999),6,'0',STR_PAD_LEFT);
$post = Post::create([
'user_id' => auth()->user()->id,
'title' => $this->title,
'category_id' => $this->category,
'body' => $this->body,
'post_number' => $random,
'slug' => Str::slug($this->title),
]);
$user = auth()->user();
$points = $user->givePoint(new PostCreated($post));
$user->notify(new PointAdd($points));
$image = $this->photo->storeAs('posts', str::random(30));
$post->image = $image;
$post->save();
session()->flash("message", "Featured image successfully uploaded");
preg_match_all('/(?<=#)(\w+)/mi', $this->body, $matchedTags, PREG_SET_ORDER, 0);
foreach ($matchedTags as $matchedTag) {
if (!$tag = Tag::where('name', $matchedTag[0])->first()) {
$tag = tag::create(['name' => $matchedTag[0]]);
}
$post->tags()->attach($tag->id);
$tag->addEnergy(1);
}
preg_match_all('/(?<=#)(\w+)/mi', $this->body, $matchedMentions, PREG_SET_ORDER, 0);
foreach ($matchedMentions as $matchedMention) {
optional(User::where('username', $matchedMention[0])->first(), function ($user) {
// $user->notify(new MentionsNotify($user));
});
}
// $users = auth()->user();
// $users->increment('points', 10);
session()->flash('success_message', 'Post was added successfully!');
$this->reset();
return redirect()->route('post.index');
}
abort(Response::HTTP_FORBIDDEN);
}
}
My notification components
<?php
namespace App\Notifications;
use App\Models\Post;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class PointAdd extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail', 'database'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
'user_name' => $this->user->name,
'user_avatar' => $this->user->avatar,
'user_points' => $this->user->reputation,
'post_id' => $this->user->post->id,
];
}
}
You are passing a $points object to notification which expects a User model. If your givePoint() method (which you didn't share) does not return a User model then that's the problem.
You can add in your notification, under use Queueable; the protected User $user; definition and check if notification throws an error.
Related
I'm trying to build a custom Artisan command with Laravel, this one can create a product by custom request and pass it to the controller to ensure that validators work fine. on the web, everything works fine, but when I run my custom command with an EMPTY field, the validators don't work and I get the integrity constraint violation error.
This is my custom command code:
<?php
namespace App\Console\Commands;
use App\Http\Controllers\Api\ProductController;
use App\Http\Requests\ProductRequest;
use App\Repositories\Interfaces\ProductRepositoryInterface;
use Illuminate\Console\Command;
class CreateProduct extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'product:create';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Create new product';
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$productName = $this->ask("Product name");
$productDescription = $this->ask("Product description");
$productPrice = $this->ask("Product price");
$productImageUrl = $this->ask("Product image url");
// $productRequest = new ProductRequest([
// "name" => $productName,
// "description" => $productDescription,
// "price" => $productPrice,
// "image" => $productImageUrl
// ]);
// $productRequest->setMethod('POST');
// $productRequest->replace(['foo' => 'bar']);
$productController = app()->make(ProductController::class);
$response = $productController->store(
new ProductRequest([
"name" => $productName,
"description" => $productDescription,
"price" => $productPrice,
"image" => $productImageUrl
])
);
$this->info($response);
return 0;
}
}
This my custom request code:
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class ProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
"name" => "required|string|min:3|max:255",
"description" => "required",
"price" => "required",
"image" => "required|string|max:2048",
'categories.*' => "exists:categories,id"
];
}
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'success' => false,
'message' => 'Validation errors',
'data' => $validator->errors()
]));
}
public function messages()
{
return [
"name.required" => "The name of product is mandatory",
"description.required" => "The description of product is mandatory",
"price.required" => "The price of product is mandatory",
"image.required" => "The image of product is mandatory",
];
}
}
Controller:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\ProductRequest;
use App\Repositories\Interfaces\ProductRepositoryInterface;
use Illuminate\Http\Request;
class ProductController extends Controller
{
private $productRepository;
public function __construct(ProductRepositoryInterface $productRepository)
{
$this->productRepository = $productRepository;
}
public function index()
{
$products = $this->productRepository->all();
return response()->json($products);
}
public function create()
{
//
}
public function store(ProductRequest $productRequest)
{
$product = $this->productRepository->create($productRequest->only(['name', 'description', 'price', 'image', 'categories']));
return response()->json($product);
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update(ProductRequest $request, $id)
{
$productUpdated = $this->productRepository->update($request->only(['name', 'description', 'price', 'image']), $id);
return response()->json($productUpdated);
}
public function destroy($id)
{
$deleted = $this->productRepository->delete($id);
return response()->json([$deleted]);
}
public function filterProductsByCategory($id) {
$products = $this->productRepository->filterProductsByCategory($id);
return response()->json($products);
}
}
You can merge data into the Request that is bound to the Container, which is what gets used to create the FormRequest from:
$request = app('request');
$request->replace(['your' => 'data', ...]); // or merge([...])
Then you can ask the Container for an instance of your FormRequest (which it does things to when resolving to fill it and validate it):
$productController->store(app(YourRequestClass::class));
Ideally you would not be calling a Controller like this, instead using the Container to call the method for you, so it will do dependency injection for you:
$response = app()->call('YourController#method');
Though you should really refactor this code out of the Controller and put it somewhere that your Controller and Command can both makes call to it.
I've been creating some tests to try my create delete edit functions on laravel from my database, this is my code:
ConstituencyController.php :
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreConstituencyRequest;
use App\Http\Resources\ConstituencyResource;
use App\Models\Constituency;
use Illuminate\Http\Request;
use phpDocumentor\Reflection\Types\Collection;
class ConstituencyController extends Controller
{
/**
* Display a listing of the constituencies.
*
*
*/
public function index()
{
$constituency = Constituency::all();
return ConstituencyResource::collection($constituency);
}
/**
* Show the form for creating a new resource.
*
*
*/
public function create()
{
//
}
/**
* Store a newly created constituency in storage.
*
* #param Request $request
*
*/
public function store(Request $request)
{
$name = $request->name;
$data = array("name"=>$name);
Constituency::insert($data);
}
/**
* Display the specified constituency.
*
* #param int $id
*
*/
public function show(int $id)
{
$constituency = Constituency::find($id);
return new ConstituencyResource($constituency);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
*
*/
public function edit(int $id)
{
//
}
/**
* Update the specified constituency in storage.
*
* #param Request $request
* #param int $id
*
*/
public function update(Request $request, int $id)
{
$constituency = Constituency::find($id);
$constituency->name = $request->name;
$constituency->update();
}
/**
* Remove the specified constituency from storage.
*
* #param int $id
*
*/
public function destroy(int $id)
{
Constituency::find($id)->delete();
}
}
Constituency.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Constituency extends Model
{
use HasFactory;
public function candidate()
{
return $this->hasMany(Candidate::class);
}
public function town()
{
return $this->hasMany(Town::class);
}
}
ConstituencyResource.php :
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ConstituencyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
ConstituencyFactory.php :
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Constituency>
*/
class ConstituencyFactory extends Factory
{
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->word(),
];
}
}
Now this is my test to update a constituency:
public function test_a_constituency_can_be_modified()
{
$constituency = Constituency::factory()->create();
$constituency_id = $constituency->id;
$response = $this->put('api/constituencies/'.$constituency_id);
$this->assertDatabaseHas('constituencies', [
'id' => $constituency->id,
'name' => $constituency->name,
'created_at' => $constituency->created_at,
'updated_at' => $constituency->updated_at,
]);
}
Now of course the test passes, but i'm not actually giving it some new parameters to change... I've been trying to give some parameters to the function to actually change some data but i can't figure out how to do that.... I don't think i'm gonna have to put the parameters in the URI but where then?
If you are using PHPUnit you likely want to make use of Data Providers:
Example from docs
/**
* #dataProvider additionProvider
*/
public function testAdd(int $a, int $b, int $expected): void
{
$this->assertSame($expected, $a + $b);
}
public function additionProvider(): array
{
return [
'adding zeros' => [0, 0, 0],
'zero plus one' => [0, 1, 1],
'one plus zero' => [1, 0, 1],
'one plus one' => [1, 1, 3]
];
}
The smart folks over at Tighten also have an excellent tutorial on data providers.
If you're using PEST then you'll want Data Sets.
Example from docs
dataset('emails', [
'enunomaduro#gmail.com',
'other#example.com'
]);
it('has emails', function ($email) {
expect($email)->not->toBeEmpty();
})->with('emails'); // <-- use the dataset
Using data providers and data sets allows you to reuse data, but also test against multiple inputs for your unit test. You could if you wanted just hard code a value after you're arrange statement (where you create the DB record) but that has limitations and providers are far more flexible.
Update - Example test
The following is an example of how you might go about things. Note this is not exhaustive and things like using $request->all() to update your model are not advisable but I have done so to keep things simple for illustritive purposes. This should give you an idea of where/how you could go about performing your testing. There are many ways/opinions on such things.
api.php
Route::put('/constituencies/{constituency}',
[ConstituencyController::class, 'update']
)->name('api.constituencies.update');
ConstituencyController.php
<?php
namespace App\Http\Controllers;
use App\Models\Constituency;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class ConstituencyController extends Controller
{
public function update(Request $request, Constituency $constituency)
{
$constituency->update($request->all());
return response()->json($constituency, Response::HTTP_OK);
}
}
ExampleTest.php
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\Constituency;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ExampleTest extends TestCase
{
/**
* A basic test example.
*
* #test
* #dataProvider constituencyNameProvider
* #return void
*/
public function it_can_update_constituency_name_successfully($constituencyName)
{
// Arrange
$constituency = Constituency::factory()->create();
$payload = ['name' => $constituencyName];
// Act
$response = $this->put(route('api.constituencies.update', $constituency->id), $payload);
// Assert
$response->assertStatus(Response::HTTP_OK)
->assertJson([
'id' => $constituency->id,
'name' => $constituencyName
])
->assertJsonStructure([
'id', 'name', 'created_at', 'updated_at'
]);
}
public function constituencyNameProvider(): array
{
return [
['Ostwald'],
['Springtown'],
['Baybarrow'],
['Blackhaven'],
['Lochspring'],
];
}
}
error
enter image description here
I am trying to send notifications of the event when some likes and comment on his post, notifications for comments and likes working
here is my notification class.
i have error in my CommentController if ($event->user_id != $comment->user_id)
class NewCommentEvent extends Notification
{
use Queueable;
protected $comment;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($comment)
{
$this->comment = $comment;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database'];
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
return [
'comment' => $this->comment,
'event' => Event::find($this->comment->event_id),
'user' => User::find($this->comment->user_id)
];
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
My controller function code for notifications on comments
public function store(CommentRequest $request)
{
$event = Event::findOrFail($request->event_id);
Comment::create([
'comment' => $request->comment,
'user_id' => Auth::id(),
'event_id' => $event->id
]);
if ($event->user_id != $comment->user_id) {
$user = User::find($event->user_id);
$user->notify(new NewCommentEvent($comment));
}
Toastr::success('Comment post with success','', ["positionClass" => "toast-top-center"]);
return redirect()->back();
}
my CommenRequest
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class CommentRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'comment' => 'required|max:2000',
];
}
}
In your controller: the variable $comment is not defined.
From Laravel docs:
The create method returns the saved model instance.
so the solution is:
$comment = Comment::create([
'comment' => $request->comment,
'user_id' => Auth::id(),
'event_id' => $event->id
]);
you have not defined your $comment, you just created a comment. This is throwing the error
$comment = Comment::create([
.
.
]);
This will fix your issue
The error message was clear. $comment is undefined. Replace your controller code with the follow:
public function store(CommentRequest $request)
{
$event = Event::findOrFail($request->event_id);
// defined comment here
$comment = Comment::create([
'comment' => $request->comment,
'user_id' => Auth::id(),
'event_id' => $event->id
]);
if ($event->user_id != $comment->user_id) {
$user = User::find($event->user_id);
$user->notify(new NewCommentEvent($comment));
}
Toastr::success('Comment post with success','', ["positionClass" => "toast-top-center"]);
return redirect()->back();
}
i've implemented notifications on my app.And they were working fine until yesterday out of the blue the stopped working.now when i click on the route that enables the notification it just keeps loading this is the store method on my controller where i check if the email notifications are enabled and if they are the user should recieve an email everytime a project is published
public function store(Request $request){
$this->validate(request(), [
'title' => 'required|max:255|unique:projects',
'body' => 'required|max:1000',
// 'tutorial' => 'required|max:1000',
'avatar' => 'required|mimes:jpeg,bmp,png',
'zip_file' => 'required|mimes:zip,rar',
]);
$user = User::all();
$profiles_storage = storage_path('app/avatars/');
$project = new Project;
$project -> user_id = auth()->id();
$project -> title = request('title');
$project -> body = request('body');
$project -> tutorial = request('tutorial');
$project -> views = '0';
$project -> downloads = '0';
$project -> alternative_text = config('app.name').' '.request('title').' '.'project';
$profile = request()->file('avatar');
// $profile->store('profiles');
$project->image = $profile->hashName();
$image = Image::make($profile->getRealPath());
$image->fit(640, 360, function ($constraint)
{ $constraint->upsize();})->save($profiles_storage.$profile->hashName());
request()-> file('zip_file')->store('zip_files');
$project -> zip_file = request()->file('zip_file')->hashName();
$project -> save();
$category = $request->input('categories');
$project->categories()->sync($category);
foreach ($user as $u) {
if ($u->email_notifications != 0) {
$u->notify(new ProjectPublished($project));
}
}
session()->flash('message',"{$project->title}".' created');
return redirect('/admin/projects');
}
and this is the ProjectPublished.php
<?php
namespace App\Notifications;
use App\User; use App\Project; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage;
class ProjectPublished extends Notification { use Queueable; protected $project;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Project $project)
{
$this->project = $project;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello there')
->subject('New Project:'.$this->project->title)
->line('As requested we are letting you know that a new project was published at Rek Studio')
->action('Check it out', url('projects/'.$this->project->title));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
can anyone help me out?
I am trying to send notifications to the owner of the post when some like and comment on his post, notifications for comments are working but when I do the same work for likes it is not working.
here is my notification class
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class show_notification extends Notification
{
use Queueable;
protected $comment;
protected $likes;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($comment,$likes)
{
$this->comment = $comment;
$this->likes = $likes;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database'];
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
return [
'comment' => $this->comment,
'likes' => $this->likes,
'user' => auth()->user()
//'repliedTime' => Carbon::now()
];
}
public function toArray($notifiable)
{
return [
//
];
}
}
My controller function code for notifications on comments
$id = $comment->post_id;
$getuser = Post::where('id', $id)->first();
$userid = $getuser->user_id;
if ($userid != $user_id ){
$user = User::where('id', $userid)->first();
$user->notify(new show_notification($comment));
}
My controller function code for notifications on likes
$id = $likes->post_id;
$getuser = Post::where('id', $id)->first();
$userid = $getuser->user_id;
if ($userid != $user_id ){
$user = User::where('id', $userid)->first();
$user->notify(new show_notification($likes));
}