Laravel fractal transformers - not getting includes - laravel

I am using fractal package in laravel 5.3. I have a player model who has hasMany relationship with videos, so one player has many videos.
Player model:
public function videos()
{
return $this->hasMany(Video::class);
}
Video model:
public function player()
{
return $this->belongsTo(Player::class);
}
I am trying to send player data and include videos data with it. This is the code in the controller:
$player = fractal()
->item($player)
->parseIncludes(['videos'])
->transformWith(new PlayerTransformer)
->toArray();
And this is the PlayerTransformer:
<?php
namespace App\Transformer;
use App\Player;
class PlayerTransformer extends \League\Fractal\TransformerAbstract
{
protected $availableIncludes = [
'videos'
];
public function transform(Player $player)
{
return [
'id' => $player->id,
'first_name' => $player->first_name,
'last_name' => $player->last_name,
'image' => $player->image_filename,
'club' => $player->club,
'birthday' => $player->birthday,
];
}
public function includeVideos(Player $player)
{
$videos = $player->videos()->where('processed', 1)->get();
return $this->collection($videos, new VideoTransformer);
}
}
I am getting the player data, but I don't get anything for videos. This doesn't work, but what is even weirder if try that with videos, in whose transformer I don't even have includes function:
<?php
namespace App\Transformer;
use App\Video;
class VideoTransformer extends \League\Fractal\TransformerAbstract
{
public function transform(Video $video)
{
return [
'id' => $video->id,
'uid' => $video->uid,
'title' => $video->title,
'image' => $video->getThumbnail(),
'description' => $video->description,
'views' => $video->viewCount(),
'created_at' => $video->created_at->diffForHumans(),
];
}
}
But, when I try to include the player data there, that works:
$videos = fractal()
->collection($videos)
->parseIncludes(['player'])
->transformWith(new VideoTransformer)
->toArray();
I have tried then to apply the same setup I have for the video transformer and remove the $availableIncludes and includeVideos in the player transfomer, but it again didn't work there. What am I doing wrong?

I was doing a get without authentication to test my controller and it was giving the error:
PHP Fatal error: Type of App\Transformers\CustomerCategoryTransformer::$availableIncludes must be array (as in class League\Fractal\TransformerAbstract) in /app/Transformers/CustomerCategoryTransformer.php on line 8
I commented out the line:
protected $defaultIncludes = [];
protected $availableIncludes = [];
My code:
<?php
namespace App\Transformers;
use App\Models\CustomerCategory;
use League\Fractal\TransformerAbstract;
class CustomerCategoryTransformer extends TransformerAbstract
{
// protected $defaultIncludes = [];
// protected $availableIncludes = [];
public function transform(CustomerCategory $model)
{
return [
'id' => $model->id,
'uuid' => $model->uuid,
'seq' => $model->seq,
'slug' => $model->slug,
'name' => $model->name,
'active' => $model->active,
'created_at' => $model->created_at->toDateTimeString(),
'updated_at' => $model->updated_at->toDateTimeString(),
];
}
}

Related

How can I store forign key a field employee_id without entering it?

I have two tables and the relationship between them is one to many
the model employee is :
class Employee extends Model implements HasMedia
{
use HasFactory;
protected $guarded = [];
protected $casts = [
];
public function familyDetails()
{
return $this->hasMany(FamilyDetails::class,'employee_id');
}
and the model FamilyDetails is:
class FamilyDetails extends Model
{
use HasFactory;
public function employee()
{
return $this->belongsTo(Employee::class,'employee_id');
}
I have an interface asking me to enter information
FamilyDetails table
But within this table there is an employee_id field that joins the two tables together
this is controller:
class FamilyDetailsController extends Controller
{
public function store(StoreFamilyDetailsRequest $request)
{
$familyDetails = FamilyDetails::create($request->validated())->with('employee');
return new FamilyDetailsResource($familyDetails);
}
}
and this is StoreFamilyDetailsRequest :
class StoreFamilyDetailsRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'Name_kanji' => ['required'],
'Relationship' => ['required'],
'Nama_katakana' => ['required'],
'Grade_In_school' => ['required'],
'Date_of_birth*' => ['required|array'],
'Date_of_birth.*day' => ['required'],
'Date_of_birth.*year' => ['required'],
'Date_of_birth.*month' => ['required'],
];
}
public function validated($key = null, $default = null)
{
return [
'Name_kanji' => $this->Name_kanji,
'Nama_katakana' => $this->Nama_katakana,
'Relationship' => $this->Relationship,
'Grade_In_school' => $this->Grade_In_school,
'Date_of_birth' => Carbon::create(
$this->Date_of_birth['year'],
$this->Date_of_birth['month'],
$this->Date_of_birth['day'])->format('Y-m-d'),
];
}
this is FamilyDetailsResource :
class FamilyDetailsResource extends JsonResource
{
public function toArray($request)
{
return [
'Name_kanji' => $this->Name_kanji,
'Relationship' => $this->Relationship,
'Nama_katakana' => $this->Nama_katakana,
'Grade_In_school' => $this->Grade_In_school,
'Date_of_birth' => [
'month' => $this->Date_of_birth->month,
'day' => $this->Date_of_birth->day,
'year' => $this->Date_of_birth->year,
]
];
}
}
When I run the code in postman the following error appears :
Briefly, how can I store the foreign key field when it is not
It asks me to enter it
in the interface???????
Can you explain more about your relationship table?
I think you can erase your code with in controller store if not used
class FamilyDetailsController extends Controller
{
public function store(StoreFamilyDetailsRequest $request)
{
$familyDetails = FamilyDetails::create($request->validated());
return new FamilyDetailsResource($familyDetails);
}
}

Problems with Laravel and validation

Im building CRUD for my application in Laravel 9. I defined some fields in my database as NOT NULL. Those values will be completed by code at the time a new user is created.
The first field Im dealing with is 'creado' (same as 'created at' in english) field (and I dont want to use built in timestamp)
User model:
public $timestamps = false;
protected $fillable = [
'username',
'password',
'apellidos',
'nombres',
'tipoDocumento',
'nroDocumento',
'cuit',
'cuil',
'fechaNacimiento',
'sexo',
'domicilio',
'domicilioNro',
'domicilioPiso',
'domicilioDepto',
'localidad',
'codigoPostal',
'telefonoFijo',
'telefonoCelular',
'telefonoAlt',
'email',
'creado', //This is the value
];
protected $hidden = [
'password',
'password_repeat', //This value is still being displayed in error msg...
'remember_token',
];
protected $casts = [
'creado' => 'datetime', //Dont think its necessary
];
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
public function setCreadoAttribute()
{
//This method never get called...
$this->attributes['creado'] = date("Y-m-d H:i:s");
}
RegisterRequest:
public function rules()
{
return [
'username' => 'required|unique:clientes,username',
'password' => 'required|min:8',
'password_repeat' => 'required|same:password',
'apellidos' => 'required',
'nombres' => 'required',
'fechaNacimiento' => 'required',
'sexo' => 'required',
'tipoDocumento' => 'required',
'nroDocumento' => 'required|unique:clientes,nroDocumento',
'cuil' => 'nullable|min:11|max:11',
'cuit' => 'nullable|min:11|max:11',
'domicilio' => 'required',
'domicilioNro' => 'required',
'localidad' => 'required',
'codigoPostal' => 'required',
'telefonoCelular' => 'required',
'email' => 'required|unique:clientes,email',
'creado' => 'nullable|date',
];
}
Controller:
public function register(RegisterRequest $request)
{
$cliente = Clientes::create($request->validated());
return redirect("login")->with("success","Bla Bla Bla");
}
In view, all fields are present, except 'creado'. If I add input type text named creado, it works. Else the field its not included in the query. I dont know why its not working when I marked it as nullable.
$casts array and setCreado can be removed.
Then, you can use an accessor, in your model:
protected function creado(): Attribute
{
return Attribute::make(
get: fn ($value) => date("Y-m-d H:i:s"),
);
}
Mas info ;) Accessors
Importante this:
This method name should correspond to the "camel case" representation of the true underlying model attribute / database column when applicable.
Finally, I was able to fix this using this approach:
In ClientsController
public function register(RegisterRequest $request)
{
$cliente = new Cliente;
$cliente = Cliente::make($request->validated());
$cliente->setCreadoAttribute();
$cliente->save();
return redirect("login")->with("success","Cuenta creada exitosamente");
}
In Client model:
public function setCreadoAttribute()
{
$this->attributes['creado'] = date("Y-m-d H:i:s");
}
Im not really sure if this is the best way or the best practice to accomplish what I was needing, but for now it works.
From the docs
If you need to customize the names of the columns used to store the timestamps, you may define CREATED_AT and UPDATED_AT constants on your model:
<?php
class Flight extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}

Cannot return null for non-nullable field - rebing/graphql

I have a problem with GraphQL(rebing-graphql)/Larvel app. App works fine when I query normal GraphQL query(single not nested), but when I query nested one, I face "debugMessage":"Cannot return null for non-nullable field \"Make Type.name\".
Normal query which works fine:
{model{id,name}}
Nested query that I want to execute:
{model{id,name,make_id{id,name}}
Where am I made mistake?
Thanks in advance.
Make Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
class Make extends Model
{
use HasFactory;
protected $fillable = [
'name',
'logo',
'website',
];
public function models()
{
return $this->hasMany(\App\Models\Model::class);
}
}
Model Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model as MModel;
class Model extends MModel
{
use HasFactory;
protected $fillable = [
'make_id',
'name',
'website',
];
public function make()
{
return $this->belongsTo(Make::class);
}
}
MakeQuery (Graphql part)
<?php
namespace App\GraphQL\Queries;
use App\Models\Make;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
class MakeQuery extends Query
{
protected $attributes = [
'name' => 'Make Type',
'description' => 'Fetch Make Query'
];
public function args(): array
{
return ["id" => ['type' => Type::int()]];
}
public function type(): type
{
return Type::listOf(GraphQL::type('make'));
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return Make::where("id",$args['id'])->get();
}
return Make::all();
}
}
MakeType
<?php
namespace App\GraphQL\Types;
use App\Models\Make;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
class MakeType extends GraphQLType
{
protected $attributes = [
'name' => 'Make Type',
'description' => 'Make API Type',
'model' => Make::class
];
public function fields(): array
{
return [
"id" => [
'type' => Type::nonNull(Type::int()),
'description' => 'Make ID'
],
"name" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
],
"logo" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
],
"website" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
]
];
}
}
ModelQuery
<?php
namespace App\GraphQL\Queries;
use App\Models\Model;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
class ModelQuery extends Query
{
protected $attributes = [
'name' => 'Model Type',
'description' => 'Fetch Model Query'
];
public function args(): array
{
return [
"id" => ['type' => Type::int()]
];
}
public function type(): type
{
return Type::listOf(GraphQL::type('model'));
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return Model::where("id", $args['id'])->get();
}
return Model::all();
}
}
ModelType
<?php
namespace App\GraphQL\Types;
use App\Models\Make;
use App\Models\Model;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
class ModelType extends GraphQLType
{
protected $attributes = [
'name' => 'Model Type',
'description' => 'Model API Type',
'model' => Model::class
];
public function fields(): array
{
return [
"id" => [
'type' => Type::nonNull(Type::int()),
'description' => 'Model ID'
],
"make_id" => [
'type' => GraphQL::type('make'),
'description' => 'Model_ID'
],
"name" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Model Name'
],
"website" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Model website'
]
];
}
}
There are several things that you have to done to get your code works:
First: Be sure that your tables are full and have valid key relations.
Second: In ModelType change make_id to makeId.
Third: Reload composer autoload with composer dump-autoload.
Finally: In your Model Model it's better to define a column like below:
public function makeId()
{
return $this->belongsTo(Make::class, 'make_id', 'id');
}
I hope these steps would help you.

GROUP BY the relationship data in laravel

I am fetching products along with its relationship. I have done this:
$data = $this->products->with('images')->with('colors')->where('slug', $slug)->first();
And in the Product model, I have written:
public function images(){
return $this->hasMany('App\Models\ProductImages', 'product_id');
}
public function colors(){
return $this->hasMany('App\Models\ProductSizes', 'color_id');
}
I am storing color_id in the product_sizes table so now when I do dd($data). It gives me 5 data inside the object where the size_id are different but the color_id are same. Is it possible to group the data coming in colors relationship?
I tried using array_unique in the blade but that did not gave me to use the following function:
public function colorInfo(){
return $this->belongsTo('App\Models\Color', 'color_id');
}
I want to group the color_id coming in the colors relationship to display available colors of the product.
Code as per request:
Product Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = ['name','slug','sku','category_id','brand_id','video','status', 'specification', 'description','warranty', 'vendor_id'];
public function getRules(){
$rules = [
'name' => 'bail|required|string|unique:products,name',
'slug' => 'bail|required|string|unique:products,slug',
'sku' => 'bail|required|string|unique:products,sku',
'specification' => 'bail|required|string',
'description' => 'bail|required|string',
'category_id' => 'required|exists:product_categories,id',
'brand_id' => 'nullable|exists:brands,id',
'vendor_id' => 'nullable|exists:vendors,id',
'video' => 'nullable|string',
'warranty' => 'nullable|string',
'status' => 'nullable|in:active,inactive',
];
if($rules != 'add'){
$rules['name'] = "required|string";
$rules['slug'] = "required|string";
$rules['sku'] = "required|string";
}
return $rules;
}
public function category(){
return $this->belongsTo('App\Models\ProductCategory');
}
public function brand(){
return $this->belongsTo('App\Models\Brand');
}
public function VendorName(){
return $this->belongsTo('App\Models\Vendor', 'vendor_id');
}
public function images(){
return $this->hasMany('App\Models\ProductImages', 'product_id');
}
public function sizes(){
return $this->hasMany('App\Models\ProductSize', 'product_id');
}
public function colors(){
return $this->hasMany('App\Models\ProductSize', 'product_id');
}
public function finalCategory(){
return $this->belongsTo('App\Models\SecondaryCategory', 'category_id');
}
}
PRoduct Sizes Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ProductSize extends Model
{
protected $fillable = ['product_id','size_id', 'selling_price', 'purchase_price', 'discount','stock', 'color_id', 'quantity','total_price'];
public function getRules(){
$rules = [
'product_id' => 'required|exists:products,id',
'size_id' => 'required|exists:sizes,id',
'color_id' => 'required|exists:colors,id',
'selling_price' => 'required|string',
'purchase_price' => 'required|string',
'quantity' => 'required|string',
'total_price' => 'required|string',
'discount' => 'nullable|string',
'stock' => 'required|string',
];
return $rules;
}
public function colorInfo(){
return $this->belongsTo('App\Models\Color', 'color_id');
}
}
Get the product first.
$data = $this->products->with(['images', 'colors'])->where('slug', $slug)->first();
To get the distinct colors for that product.
$unique_product_colors = $data->colors->unique('color_id');
unique('color_id') method can be applied on a collection instance to get a new collection in which all the items will have unique color_id
Try This
$data = $this->products->with('images')->with('colors')->where('slug', $slug)->groupBy('product_sizes.color_id')->first();

Error storing Topic Model into the database using Sentinel

I have a small forum, im trying to create topic and replies for the store method.
routes.php
Route::get('board/{id}/create', 'TopicsController#create');
Route::post('board/{id}/create', 'TopicsController#store');
TopicsController.php
public function store()
{
$this->request->user()->topics()->create([
'board_id' => $this->request->id,
'title' => $this->request->title,
'body' => $this->request->body
]);
return redirect(url('/board/' . $this->request->id));
}
I am receiving this error.
Call to a member function topics() on null
Also note, i am using Sentinel https://github.com/rydurham/Sentinel from this repo.
<?php namespace App\Models;
class User extends \Sentinel\Models\User
{
protected $fillable = ['email', 'first_name', 'last_name'];
protected $hidden = ['password'];
public function topics()
{
return $this->hasMany(Topic::class);
}
public function replies()
{
return $this->hasMany(Reply::class);
}
public function getGravatarAttribute()
{
$hash = md5(strtolower(trim($this->attributes['email'])));
return "https://www.gravatar.com/avatar/$hash";
}
}
Updated Model
public function store($id)
{
$user = Sentry::getUser($id);
$user->topics()->create([
'board_id' => $this->request->id,
'title' => $this->request->title,
'body' => $this->request->body
]);
return redirect(url('/board/' . $this->request->id));
}
It seems that your user object is null. Properly retrieve the user using the id
public function store($id)
{
$user = \App\Models\User::find(\Sentinel::getUser()->id);
$user->topics()->create([
'board_id' => $this->request->id,
'title' => $this->request->title,
'body' => $this->request->body
]);
return redirect(url('/board/' . $this->request->id));
}

Resources