any way every thing is save in data column
<?php
namespace App\Notifications;
class SendNotification extends Notification implements ShouldQueue
{
use Queueable;
public $message;
public $model_instance;
private $log;
/**
* Create a new notification instance.
*
* #param $message
* #param array $log
* #param Model $model_instance
*/
public function __construct($message, array $log = [],Model $model_instance = null )
{
$this->message = $message;
$this->log = $log;
$this->model_instance = $model_instance->id;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return [MicroserviceChannel::class, 'database'];
}
public function toMicroservice($notifiable)
{
return $this->message;
}
public function toDatabase($notifiable)
{
return $this->log;
}
public function toArray() {
return [
'group_id' => $this->model_instance
];
}
}
this is all of my notification class
but I add new column as group_id to this table
now nothing isn't store in data column
detailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetails
because it need more details :)
make sure add group_id in fillable in your model
toArray and toDatabase methods of notification classes must return a plain Array as explain here Formatting Database Notifications.
Just ensure toDatabase return a plain Array like toArray.
I can presume $this->id is the ID of the Model instance which the Notification is related to. So you must pass that model when you instanciate the notification class like this
$user->notify(new NotificationClass($model_instance));
Here I use $user->notify you can use any Model of classes which use Notifiable.
And in the NotificationClass you'll receive the $model_instance in the Constructor like this
class NotificationClass extends Notification {
public $model_instance;
public function __construct(Model $model_instance){
$this->model_instance = $model_instance;
}
public function toArray() {
return [
'group_id' => $this->model_instance->group_id;
];
}
}
You will have to pass the $group_id value when you call your notification like
$group_id=1;
$user->notify(new ActionsNotification($group_id));
and then in your created notification
protected $group_id;
public function __construct($group_id)
{
$this->group_id= $group_id;
}
public function toDatabase($notifiable)
{
return [
'group_id' => $this->group_id
];
}
Related
I have created a tiktok like app which retrieve data from mysql database using api from laravel, first i was using bavix/laravel-wallet package version 5.3.2. to create a virtual wallet for gift system in the app. And i have a function which used to send gift to another user (coins) and that user receive gifts in his wallet, i display a list of the Items which contain a number and value of the gifts he received from other users so he can redeem them later.
below is the class which was used to retrieve list of the gift of the user to and display on his wallet ready to be redeemed..
<?php
namespace App\Http\Resources;
use App\Models\Item as ItemModel;
use Bavix\Wallet\Models\Transfer;
use Illuminate\Http\Resources\Json\JsonResource;
class Gift extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
static $currency;
if (empty($currency)) {
$code = setting('payment_currency', config('fixtures.payment_currency'));
$symbol = $code;
$currency = $symbol !== $code ? $symbol : $code;
}
$data = [];
/** #var \App\Models\User $this */
/** #var ItemModel $item */
foreach (ItemModel::get() as $item) {
$transfers = $this->transfers()
->where('to_type', $item->getMorphClass())
->where('to_id', $item->getKey())
->where('status', Transfer::STATUS_PAID)
->count();
$data[] = [
'item' => Item::make($item),
'balance' => $transfers,
'value' => sprintf('%s%.2f', $currency, ($item->value * $transfers) / 100),
];
}
return $data;
}
}
The above class was getting a list of all the gifts which was received by the current user in the transfers table and 'to_type' column was returning the Item modal(App/Models/Item) and i was get the result correctly.
But the question here is when i update my laravel to verion 9 and bavix/laravel-wallet to version 9.0 the transfers variable return 0 data from the database because 'to_type' column in database change and does not return Item modal anymore otherwise it returning the Wallet Model and I have no idea how to change my codes to get the same result as from the previous versions.
I read the package documentation but i did not get any luck.
Below is the Item Model class ...
<?php
namespace App\Models;
use Bavix\Wallet\Interfaces\Customer;
use Bavix\Wallet\Interfaces\ProductInterface;
use Bavix\Wallet\Traits\HasWallet;
use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
class Item extends Model implements ProductInterface
{
use HasWallet, LogsActivity;
// protected static $logFillable = true;
// protected static $logOnlyDirty = true;
protected $fillable = [
'name', 'image', 'price', 'value', 'minimum',
];
/**
* #param Customer $customer
* #param int $quantity
* #param bool $force
*
* #return bool
*/
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logFillable()
->logOnlyDirty();
}
public function canBuy(Customer $customer, int $quantity = 1, bool $force = null): bool
{
return true;
}
public function getAmountProduct(Customer $customer): int|string
{
return $this->price;
}
public function getDescriptionForEvent(string $event): string
{
return sprintf('Item "%s" was %s.', $this->name, $event);
}
/**
* #return array
*/
public function getMetaProduct(): ?array
{
return ['title' => $this->name];
}
/**
* #return string
*/
public function getUniqueId(): string
{
return (string)$this->getKey();
}
}
Below is the item Db...
Below is the Transfer table
Below is the Wallet Table
Anyone who can help or get any direction on where to read so i can understand how to accomplish that..
i writing a little game for study and i am stuck, i have a class where i have methods for generate reports, and when i call any method from Controller site this one return me class variables in object.
Call method _Get or _Create returns:
{"id":null,"character_id":1,"name":null,"desc":null}
Class:
class GenerateRaport {
public $id;
public $character_id;
public $name;
public $desc;
public function _Get() {
$raport = PlayerRaport::where('character_id', $this->character_id)->orderBy('created_at', 'desc')->get();
return $raport;
}
public function _Create() {
$new = new PlayerRaport();
$new->character_id = $this->character_id;
$new->name = $this->name;
$new->desc = $this->desc;
$new->save();
return $new;
}
}
Controller:
class RaportController extends Controller
{
public function index(Request $request) {
$raport = new GenerateRaport();
$raport->character_id = \Auth::user()->character_id;
$raport->_Get();
return response()->json($raport, 200);
}
public function create(Request $request) {
$raport = new GenerateRaport();
$raport->character_id = \Auth::user()->character_id;
$raport->name = "Name";
$raport->desc = "Description";
$raport->_Create();
return response()->json($raport, 201);
}
}
#Edit:
class PlayerRaport extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'id', 'name', 'desc', 'character_id', 'viewed'
];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [
];
}
I think you are not passing your returned value into your response that's why your json values are null. (Refer to #Jigius comment)
Furthermore, I see you created GenerateReport so that viewed information is not display in json response.
While your implementation is ok, you could also have a look into Laravel's Eloquent: API Resources (Resource Collections if you return multiple rows).
You can save lot of effort by implement eloquent-resources to your solution.
Sample of find one
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PlayerRaport extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'desc' => $this->desc,
'character_id' => $this->character_id
];
}
}
use App\PlayerRaport;
use App\Http\Resources\PlayerRaport as PlayerRaportResource;
class RaportController extends Controller
{
public function show(Request $request) {
return new PlayerRaportResource(PlayerRaport::find(1));
}
}
I want (for project reason), to create an array in a class controller and pass it to a resource.
Consider in my controller class this method:
public function getExample(){
$attribute=array('otherInfo'=>'info');
return new ExampleResource($attribute);
}
and I in my class I would write sominthing like ExampleResource with:
public function toArray($request){
return[
'info' => $this->info
];
}
How I can convert the value $attribute to perform this operation return new ExampleResource($attribute); ?
Please do not suggest me to insert the field info in the model, this attribute can came from only from the external, from the controller and do not belong to the model in database.
class ExampleResource extends Resource
{
private $info;
/**
*
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function __construct($info)
{
$this->$info = $info;
}
public function toArray($request)
{
return[
'info'=>$this->$info,
'id' => $this->id
];
}
}
Add constructor to the resource class:
public function __construct($resource, $attribute)
{
$this->resource = $resource;
$this->attribute = $attribute;
}
Then in toArray():
return [
'info' => $this->attribute,
'created' => $this->created_at
];
And use it:
return new ExampleResource(Model::find($id), $attribute);
Resources are intended to be used to easily transform your models into JSON.
Take a look at this example:
use App\User;
use App\Http\Resources\UserResource;
Route::get('/user', function () {
return new UserResource(User::find(1));
});
You just want to return an array of data so you should just return the array, it will be automatically turned into JSON:
Route::get('/info', function () {
return ['info' => 'info ...'];
});
For more informations check the docs here
So i am trying to save Notifications in the database. But once an object of the model with values is passed to the Notification class, the data is not persisted in it and i get following message
Illuminate \ Database \ QueryException (HY000)
SQLSTATE[HY000]: General error: 1364 Field 'post_title' doesn't have a default value (SQL: insert into posts (updated_at,
created_at) values (2017-09-21 15:58:01, 2017-09-21 15:58:01))
Now i have Post_title and Post_description but they are not shown here.
Following is my Notification Class, strangely i am getting all the post related info in the constructor if i take dump of Post Object
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class PostCreated extends Notification
{
use Queueable,Notifiable;
protected $post;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($post)
{
$this->post = $post;
}
/**
* 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 toArray($notifiable)
{
return [
'post_id' => $this->post->id,
'user_id' => $this->post->user_id,
];
}
}
Let me know if more info is required.
EDIT: Post model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Feed\FeedItem;
/**
* #property array|string post_title
* #property array|string post_description
* #property array|string is_featured
* #property array|string is_rejected
* #property mixed id
*/
class Post extends Model implements FeedItem
{
use SoftDeletes;
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['deleted_at','created_at','updated_at','starting_time','ending_time'];
protected $fillable = [
'post_title', 'post_description', 'ebook_title', 'ebook_link', 'country_id', 'state_id', 'diary_id'
];
public function user()
{
return $this->belongsTo('App\Models\User');
}
public function hashTags()
{
return $this->belongsToMany('App\Models\HashTag', 'hash_tag_post', 'post_id', 'hash_tag_id')->withTimestamps();
}
public function getRelatedHashTagsAttributes()
{
return $this->tags->pluck('id');
}
public function categories()
{
return $this->belongsToMany('App\Models\Category', 'category_post', 'post_id', 'category_id')->withTimestamps();
}
public function state()
{
return $this->belongsTo('App\Models\Category', 'state_id', 'id');
}
public function country()
{
return $this->belongsTo('App\Models\Category', 'country_id', 'id');
}
public function sliders()
{
return $this->belongsToMany('App\Models\Slider', 'slider_post', 'post_id', 'slider_id')->withTimestamps();
}
public function comments()
{
return $this->hasMany('App\Models\Comment');
}
public function postUploadedDatas()
{
return $this->hasMany('App\Models\PostUploadedData');
}
public function likes()
{
return $this->hasMany('App\Models\Like');
}
public function hasAction($user)
{
if ($this->likes()->where('user_id', $user)->first())
{
return true;
}
return false;
}
public function diaries()
{
return $this->belongsToMany('App\Models\Post', 'diary_post', 'post_id', 'diary_id');
}
public function getFeedItemId()
{
return $this->id;
}
public function getFeedItemTitle()
{
return $this->post_title;
}
public function getFeedItemSummary()
{
return $this->post_description;
}
public function getFeedItemUpdated()
{
return $this->updated_at;
}
public function getFeedItemAuthor() : string
{
return "";
}
public function getFeedItemLink()
{
return action('TravellersInn\PostController#getFeedItems', [$this->url]);
}
public function getTipsFeed()
{
return Post::where('contant_id','LIKE','%'.'3'.'%')->get();
}
public function getImagesFeed()
{
return Post::where('contant_id','LIKE','%'.'2'.'%')->get();
}
public function getVideosFeed()
{
return Post::where('contant_id','LIKE','%'.'4'.'%')->get();
}
public function getEbooksFeed()
{
return Post::where('contant_id','LIKE','%'.'6'.'%')->get();
}
}
There are a couple of solves for this depending on what you want.
If you are always wanting at value for post_title and post_description then you need to add some validation and check that the values are being passed to your controller to be set in the db and that your model will fill these values.
See https://laravel.com/docs/5.5/validation
However, if the title and description aren't always set then this is potentially your database, not your code. If these fields are likely to be unused at times then you want to set the default for each field to '' or NULL.
Some thing like
ALTER TABLE <table> ALTER j SET DEFAULT '';
Finally
Tbh I don't think you need that constructor, but I could be wrong.
Either put value of post_title as blank or update schema to set default value as blank ->default("");
Column post_title is always needed any value if you not set as default value.
Also make sure you have added post_title in your model
protected $fillable = ['post_title',....];// all columns
i'm trying to test a simple class. I'm following this tutorial( http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456 ).
I have this error, while running tests:
Method Mockery_0_App_Interfaces_MealTypeRepositoryInterface::getValidator() does not exist on this mock object
Im using repository structure. So, my controller calls repository and that returns Eloquent's response.
I'm relatively new in php and laravel. And I've started learning to test a few days ago, so I'm sorry for that messy code.
My test case:
class MealTypeControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('App\Interfaces\MealTypeRepositoryInterface');
$this->app->instance('App\Interfaces\MealTypeRepositoryInterface' , $this->mock);
}
public function tearDown()
{
Mockery::close();
}
public function testIndex()
{
$this->mock
->shouldReceive('all')
->once()
->andReturn(['mealTypes' => (object)['id' => 1 , 'name' => 'jidlo']]);
$this->call('GET' , 'mealType');
$this->assertViewHas('mealTypes');
}
public function testStoreFails()
{
$input = ['name' => 'x'];
$this->mock
->shouldReceive('getValidator')
->once()
->andReturn(Mockery::mock(['fails' => true]));
$this->mock
->shouldReceive('create')
->once()
->with($input);
$this->call('POST' , 'mealType' , $input ); // this line throws the error
$this->assertRedirectedToRoute('mealType.create');//->withErrors();
$this->assertSessionHasErrors('name');
}
}
My EloquentMealTypeRepository:
Nothing really interesting.
class EloquentMealTypeRepository implements MealTypeRepositoryInterface
{
public function all()
{
return MealType::all();
}
public function find($id)
{
return MealType::find($id);
}
public function create($input)
{
return MealType::create($input);
}
public function getValidator($input)
{
return MealType::getValidator($input);
}
}
My eloquent implementation:
Nothing really interresting,too.
class MealType extends Model
{
private $validator;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'meal_types';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [];
public function meals()
{
return $this->hasMany('Meal');
}
public static function getValidator($fields)
{
return Validator::make($fields, ['name' => 'required|min:3'] );
}
}
My MealTypeRepositoryInterface:
interface MealTypeRepositoryInterface
{
public function all();
public function find($id);
public function create($input);
public function getValidator($input);
}
And finally, My controller:
class MealTypeController extends Controller {
protected $mealType;
public function __construct(MealType $mealType)
{
$this->mealType = $mealType;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$mealTypes = $this->mealType->all();
return View::make('mealTypes.index')->with('mealTypes' ,$mealTypes);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$mealType = new MealTypeEloquent;
$action = 'MealTypeController#store';
$method = 'POST';
return View::make('mealTypes.create_edit', compact('mealType' , 'action' , 'method') );
}
/**
* Validator does not work properly in tests.
* Store a newly created resource in storage.
*
* #return Response
*/
public function store(Request $request)
{
$input = ['name' => $request->input('name')];
$mealType = new $this->mealType;
$v = $mealType->getValidator($input);
if( $v->passes() )
{
$this->mealType->create($input);
return Redirect::to('mealType');
}
else
{
$this->errors = $v;
return Redirect::to('mealType/create')->withErrors($v);
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
return View::make('mealTypes.show' , ['mealType' => $this->mealType->find($id)]);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
$mealType = $this->mealType->find($id);
$action = 'MealTypeController#update';
$method = 'PATCH';
return View::make('mealTypes.create_edit')->with(compact('mealType' , 'action' , 'method'));
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
$mealType = $this->mealType->find($id);
$mealType->name = \Input::get('name');
$mealType->save();
return redirect('mealType');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
$this->mealType->find($id)->delete();
return redirect('mealType');
}
}
That should be everything. It's worth to say that the application works, just tests are screwed up.
Does anybody know, why is that happening? I cant see a difference between methods of TestCase - testIndex and testStoreFails, why method "all" is found and "getValidator" is not.
I will be thankful for any tips of advices.
Perhaps an aside, but directly relevant to anyone finding this question by its title:
If:
You are getting the error BadMethodCallException: Method Mockery_0_MyClass::myMethod() does not exist on this mock object, and
none of your mocks are picking up any of your subject's methods, and
your classes are being autoloaded, (e.g. using composer)
then before making your mock object, you need to force the loading of that subject, by using this line of code:
spl_autoload_call('MyNamespace\MyClass');
Then you can mock it:
$mock = \Mockery::mock('MyNamespace\MyClass');
In my PHPUnit tests, I often put that first line into the setUpBeforeClass() static function, so it only gets called once and is isolated from tests being added/deleted. So the Test class looks like this:
class MyClassTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
spl_autoload_call('Jodes\MyClass');
}
public function testIt(){
$mock = \Mockery::mock('Jodes\MyClass');
}
}
I have forgotten about this three times now, each time spending an hour or two wondering what on earth the problem was!
I have found a source of this bug in controller.
calling wrong
$v = $mealType->getValidator($input);
instead of right
$v = $this->mealType->getValidator($input);