Store notifications data with saveMany Contents - laravel

So what I am trying to do is store notifications to the database with Notifiable, but I have a saveMany contents and I don't know how to declare the data in the notifications. getting a null from what I've declared like the picture below
this is my saveMany store
$post = new Post;
$post->user_id = Auth::guard('webcontrol')->user()->id;
$post->lob = $request->lob;
$post->type = 'post';
$post->category_id = $request->category_id;
$post->is_published = $request->is_published;
$post->published_at = ($request->published_at) ? $request->published_at : Carbon::now();
$post->metas = '{}';
$post->save();
$post->contents()->saveMany([
new PostContent([
'lang' => 'id',
'slug' => str_slug($request->contents['id']['title'], '-'),
'title' => $request->contents['id']['title'],
'body' => $request->contents['id']['body'],
'image' => $request->contents['id']['image'],
'tag' => $request->contents['id']['tag'],
'metas' => serialize($request->contents['id']['metas']),
]),
new PostContent([
'lang' => 'en',
'slug' => str_slug($request->contents['en']['title'], '-'),
'title' => $request->contents['en']['title'],
'body' => $request->contents['en']['body'],
'image' => $request->contents['en']['image'],
'tag' => $request->contents['en']['tag'],
'metas' => serialize($request->contents['en']['metas']),
])
]);
Notification::send($user, new OneSignalNotification($post));
dd('done');
this is my Notification
class OneSignalNotification extends Notification
{
use Queueable;
public $post;
public function __construct($post)
{
$this->post = $post;
}
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
'body' => $this->post['body'], //this is where i confused how to declare the saveMany contents so its not returning null
];
}
}

So I'm not sure what you're trying to achieve but the issue is with the fact that you want to retrieve the body from the post, but the way I see it, the $post doesn't have a body property. The PostContent seems to have the body property, but the problem is that you saved many PostContent to the same $post, so therefore there are multiple body properties, one for each PostContent. So that's why I would recommend use the first() method to get the first PostContent from $post and then return it. If you want to return all the body property, you would have to get all of them and add them into an array or a string, or whatever you want. I hope this makes sense.
You should try using this:
$post = new Post;
$post->user_id = Auth::guard('webcontrol')->user()->id;
$post->lob = $request->lob;
$post->type = 'post';
$post->category_id = $request->category_id;
$post->is_published = $request->is_published;
$post->published_at = ($request->published_at) ? $request->published_at : Carbon::now();
$post->metas = '{}';
$post->save();
$post->contents()->saveMany([
new PostContent([
'lang' => 'id',
'slug' => str_slug($request->contents['id']['title'], '-'),
'title' => $request->contents['id']['title'],
'body' => $request->contents['id']['body'],
'image' => $request->contents['id']['image'],
'tag' => $request->contents['id']['tag'],
'metas' => serialize($request->contents['id']['metas']),
]),
new PostContent([
'lang' => 'en',
'slug' => str_slug($request->contents['en']['title'], '-'),
'title' => $request->contents['en']['title'],
'body' => $request->contents['en']['body'],
'image' => $request->contents['en']['image'],
'tag' => $request->contents['en']['tag'],
'metas' => serialize($request->contents['en']['metas']),
])
]);
Notification::send($user, new OneSignalNotification($post->fresh()));
dd('done');
And then inside the Notification, like I said, we take the first PostContent from the $post and get it's body property:
class OneSignalNotification extends Notification
{
use Queueable;
public $post;
public function __construct($post)
{
$this->post = $post;
}
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
'body' => $this->contents()->first()->body,
];
}
}

Related

Laravel Many to one in Resource

I use laravel 8 & have 3 table:
Products, ProductPrice & ProductsPublisher:
this is my Products model for this relationship:
public function lastPrice(){
return $this->hasMany(ProductPrice::class)->where('status','active')->orderBy('created_at','DESC')->distinct('publisher_id');
}
and this is my productsPrice model for publisher relationship:
public function getPublisher(){
return $this->belongsTo(ProductsPublisher::class,'publisher_id');
}
now, i want to use laravel resource for my api, i wrote products resource:
public function toArray($request)
{
return [
'id' => $this->id,
'price' => lastPrice::make($this->lastPrice),
'status' => $this->status,
'slug' => $this->slug,
'title' => $this->title,
'description' => $this->description,
'txt' => $this->txt,
'lang' => $this->lang,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
but in lastPrice resource, when i wrote like this:
return [
'id' => $this->id,
'main_price' => $this->main_price
];
it give me this error:
Property [id] does not exist on this collection instance.
when i use this code:
return parent::toArray($request);
get response but because i need to use another relationship in my lastPirce for publishers, i cant use that code and should return separately my data.
What i should to do?
thanks
Edit 1:
this is my Controller Code:
$products = Product::where('id',$id)->where('slug',$slug)->where('status','confirm')->first();
if(!$products){
return $this->sendError('Post does not exist.');
}else{
return $this->sendResponse(new \App\Http\Resources\Products\Products($products), 'Posts fetched.');
}
and this is sendResponse & sendError:
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'success' => false,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
thanks.
Edit 2:
i change my lastPrice Resource toArray function to this and my problem solved, but i think this isn't a clean way, any better idea?
$old_data = parent::toArray($request);
$co = 0;
$new_data = [];
foreach ($old_data as $index){
$publisher_data = Cache::remember('publisher'.$index['publisher_id'], env('CACHE_TIME_LONG') , function () use ($index) {
return ProductsPublisher::where('id' , $index['publisher_id'])->first();
});
$new_data[$co]['main_prices'] = $index['main_price'];
$new_data[$co]['off_prices'] = $index['off_price'];
$new_data[$co]['publisher'] = SinglePublisher::make($publisher_data);
$new_data[$co]['created_at'] = $index['created_at'];
$co++;
}
return $new_data;

Error column not found, but I did not declare the column?

I'm inserting a record to a polymorphic imageable table, however it says column thread_id not found. I have not declared this thread_id column and I don't know where it's pulling it from. Here is the code it's trying to run.
protected static function bootRecordImage()
{
if (auth()->guest()) return;
foreach (static::getMethodToRecord() as $event) {
static::$event(function ($model) use ($event) {
$body = request()->body;
preg_match_all('/<img .*?(?=src)src=\"([^\"]+)\"/si', $body, $matches);
$images = $matches[1];
if($event == 'created') {
foreach ($images as $image) {
$model->images()->create([
'user_id' => auth()->id(),
'imageable_id' => $model->id,
'imageable_type' => get_class($model),
'path' => $image
]);
}
}
if($event == 'deleting') {
foreach ($images as $image) {
$model->images()->delete([
'user_id' => auth()->id(),
'imageable_id' => $model->id,
'imageable_type' => get_class($model),
'path' => $image
]);
if (File::exists(public_path($image))) {
File::delete(public_path($image));
}
}
}
});
}
}
My store method:
public function store(Request $request, Channel $channel, Spam $spam)
{
if (!auth()->user()) {
return back()->withInput()->with('flash', 'Sorry! You must be logged in to perform this action.');
}
if (!auth()->user()->confirmed) {
return back()->withInput()->with('flash', 'Sorry! You must first confirm your email address.');
}
$this->validate($request, [
'title' => 'required',
'body' => 'required',
'channel_id' => 'required|exists:channels,id',
'g-recaptcha-response' => 'required'
// yes it's required, but it also needs to exist on the channels model, specifically on the id
]);
$response = Zttp::asFormParams()->post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => config('services.recaptcha.secret'),
'response' => $request->input('g-recaptcha-response'),
'remoteip' => $_SERVER['REMOTE_ADDR']
]);
// dd($response->json());
if (! $response->json()['success']) {
throw new \Exception('Recaptcha failed');
}
$spam->detect(request('title'));
$spam->detect(request('body'));
$thread = Thread::create([
'user_id' => auth()->id(),
'channel_id' => request('channel_id'),
'title' => request('title'),
'body' => request('body'),
//'slug' => str_slug(request('title'))
]);
return redirect('/forums/' . $thread->channel->slug . '/' . $thread->slug);
}
As you can see, no where is a thread_id mentioned, yet in the error it looks like it's trying to insert into a thread_id column that I've never declared.
Thanks for reading.
I put the polymorphic relation in the model and the trait. Remove it from the Model and you're good to go.

why my updateOrInsert doesn't work laravel

I use updateOrInsert to avoid duplicate data, why doesn't the Update function work and always insert data?
foreach($datas as $data){
DB::table('users')->updateOrInsert([
'user_connect_id' => $user->connect_id,
'description' => $data['description'],
'created_by' => $login->name,
'modified_by' => $login->name,
'created_at' => Carbon::now(),
]);
}
Check out [updateOrInsert] this documentation (https://laravel.com/api/6.x/Illuminate/Database/Query/Builder.html#method_updateOrInsert). You need two parameters. One is the matching attributes (i.e., the attributes you would use to identify your record in case it exists), the other is your array (the new values you wish to insert or update the record with).
updateOrInsert(array $attributes, array $values = [])
Example
DB::table('users')->updateOrInsert(
[
'user_connect_id' => $user->connect_id
],
[
'user_connect_id' => $user->connect_id,
'description' => $data['description'],
'created_by' => $login->name,
'modified_by' => $login->name,
'created_at' => Carbon::now(),
]);
There are two arguments in updateOrInsert method.The updateOrInsert method accepts two arguments: an array of conditions by which to find the record, and an array of column and value pairs containing the columns to be updated.
For e.g :
DB::table('users')
->updateOrInsert(
['email' => 'john#example.com', 'name' => 'John'],
['votes' => '2']
);
Check this link for syntax : Laravel Doc
// Inseart code
public function create()
{
return view('admin.category.create');
}
public function store(Request $request)
{
$this->validate($request,[
'name' => 'required'
]);
$category = new Category();
$category->name = $request->name;
$category->slug = str_slug($request->name);
$category->save();
Toastr::success('Category Successfully Saved','Success');
return redirect()->route('admin.category.index');
}
// Update code
public function edit($id)
{
$category =Category::find($id);
return view('admin.category.edit',compact('category'));
}
public function update(Request $request, $id)
{
$this->validate($request,[
'name' => 'required|unique:categories'
]);
$category = Category::find($id);
$category->name = $request->name;
$category->slug = str_slug($request->name);
$category->save();
Toastr::success('Category Successfully Updated','Success');
return redirect()->route('admin.category.index');
}

Test the exist validator in Yii2 without database with mockeryBuilder()

I want to test my AR model without connect to database in Yii 2 so I use mockBuilder() but I dont know how can I pass the mock object to the model exist validator, for example:
class Comment extends ActiveRecord
{
public function rules()
{
return [
[['id', 'user_id', 'post_id'], 'comment'],
['comment', 'string',
'max' => 200
],
['user_id', 'exist',
'targetClass' => User::className(),
'targetAttribute' => 'id'
],
['post_id', 'exist',
'targetClass' => Post::className(),
'targetAttribute' => 'id'
]
];
}
}
class CommentTest extends TestCase
{
public function testValidateCorrectData()
{
$user = $this->getMockBuilder(User::className())
->setMethods(['find'])
->getMock();
$user->method('find')->willReturn(new User([
'id' => 1
]));
$post = $this->getMockBuilder(Post::className())
->setMethods(['find'])
->getMock();
$post->method('find')->willReturn(new Post([
'id' => 1
]));
// How can I pass to $user and $post to exist validator in Comment model?
$comment = new Comment([
'user_id' => 1,
'post_id' => 1,
'comment' => 'test...'
]);
expect_that($comment->validate());
}
}
ok, It's not a best code just I'd like to introduce what I want to do.
Yii2 ExistValidator uses ActiveQuery::exists() for check existence and you should replace generated validator to mockobject where the method createQuery returns mockobject of ActiveQuery where ::exists() return something you want (true/false) e.g.
$activeQueryMock = $this->getMockBuilder(ActiveQuery::className())
->disableOriginalConstructor()
->setMethods(['exists'])
->getMock();
$activeQueryMock->expects($this->any())
->method('exists')
->willReturn($value); //Your value here true/false
$model = $this->getMockBuilder(Comment::className())
->setMethods(['getActiveValidators'])
->getMock();
$model->expects($this->any())
->method('getActiveValidators')
->willReturnCallback(function () use ($activeQueryMock) {
$validators = (new Comment())->activeValidators;
foreach ($validators as $key => $validator) {
if (($validator instanceof ExistValidator) && ($validator->attributes = ['user_id'])) {
$mock = $this->getMockBuilder(ExistValidator::className())
->setConstructorArgs(['config' => get_object_vars($validator)])
->setMethods(['createQuery'])
->getMock();
$mock->expects($this->any())
->method('createQuery')
->willReturn($activeQueryMock);
$validators[$key] = $mock;
break;
}
}
return $validators;
});
$model->validate();

Lumen: update records via json body

I have a Laravel Lumen API. I'm seeing an issue with the update functionality.
In my controller, the code for updating an item is:
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required',
'description' => 'required',
'completed' => 'required',
]);
$todo = Todo::find($id);
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
return response()->json(['status' => 'success']);
}
I can update the todo item using:
http://lumen-todo.app/api/51?name=test&description=test&completed=1
however was hoping I could send the parameters in a json body, like this
PUT http://lumen-todo.app/api
{
"id": 1
"name": "Test",
"description": "Test",
"completed": 1,
}
For adding items, it works via a json body, so don't understand why it does not work for updates. For info, the 'add item' controller code is here:
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
'description' => 'required',
'completed' => 'required'
]);
$todo = new Todo();
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
return response()->json(['status' => 'success']);
}
If you want to get the json data from request payload, validate and store it, use
public function store(Request $request)
{
$data = $request->json()->all();
$this->validate($data, [
'name' => 'required',
'description' => 'required',
'completed' => 'required'
]);
$resource = $this->model->find($id);
$resource->fill($request);
$resource->save();
return response()->json(['status' => 'success']);
}
Instead of doing this:
$todo = new Todo();
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
Do, this:
use App\Todo;
protected $model;
public function __construct(Todo $model) {
$this->model = $model;
}
$resource = $this->model->find($id);
$resource->fill($request);
$resource->save();
Also, you can do json_decode() function to change your json params to array and use that to validate and save data.

Resources