I have an end API point
users/{user}
now in User resource, I want to return
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'name' => $this->name,
// 'comments' => $this->post->comments->keyBy('post_id')
'comments' => new CommentCollection($this->post->comments->keyBy->post_id)
];
}
CommentCollection class
public function toArray($request)
{
// return parent::toArray($request);
return [
'data' => $this->collection->transform(function($comment){
return [
'id' => $comment->id,
'comment' => $comment->comment,
];
}),
];
}
but the result will not include the post_id as key, how I can make it return the comments collection having key post_id?
Update
use App\models\Post;
use App\Http\Resources\Postas PostResource;
Route::get('/posts', function () {
return PostResource::collection(Post::all()->keyBy->slug);
});
This is working correctly, but if I will use post collection inside User resource as relationship, it is not working! and that is my requirement in comments collection.
What I did it, I created another ResourceGroupCollection class
<?php
namespace App\Http\Resources\Collection;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CommentGroupCollection extends ResourceCollection
{
public $collects = 'App\Http\Resources\Collection\CommentCollection';
public $preserveKeys = true;
public function toArray($request)
{
return $this->collection;
}
}
<?php
namespace App\Http\Resources\Collection;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CommentCollection extends ResourceCollection
{
public $collects = 'App\Http\Resources\Comment';
public $preserveKeys = true;
public function toArray($request)
{
return $this->collection;
}
}
and then
new CommentGroupCollection($comments->groupBy('post_id')),
just like this :
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'name' => $this->name,
// 'comments' => $this->post->comments->keyBy('post_id')
'comments' => new CommentCollection($this->post->comments)->keyBy('post_id')
];
}
Related
I send to Laravel this JSON data:
[
{"name":"...", "description": "..."},
{"name":"...", "description": "..."}
]
I have a StoreRequest class extends FormRequest:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|min:1|max:255',
'description' => 'nullable|string|max:65535'
];
}
}
In my controller I have this code, but it doesn't work with array:
public function import(StoreRequest $request) {
$item = MyModel::create($request);
return Response::HTTP_OK;
}
I found this solution to handle arrays in the Request rules():
public function rules()
{
return [
'name' => 'required|string|min:1|max:255',
'name.*' => 'required|string|min:1|max:255',
'description' => 'nullable|string|max:65535'
'description.*' => 'nullable|string|max:65535'
];
}
How can I update the StoreRequest and/or the import() code to avoide duplicate lines in rules()?
As you have an array of data you need to put * first:
public function rules()
{
return [
'*.name' => 'required|string|min:1|max:255',
'*.description' => 'nullable|string|max:65535',
];
}
I made a Models controller and use it as resources for almost all my Model. Now, when I try to get the data of a model and the related models, Laravel replace upper case letter with an underscore and the lower case letter. I need to let it with the upper case.
So there is the model where I got the issue at App\Models\Rate:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Rate extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $table = 'rates';
protected $fillable = [
'institution_id',
'name',
];
protected $info = [
'relations' => [
'rateRistournes' => [
'model' => 'RateRistourne',
'type' => 'hasMany',
],
'rateRows' => [
'model' => 'RateRow',
'type' => 'hasMany',
],
'rateTables' => [
'model' => 'RateTable',
'type' => 'hasMany',
],
],
'rules' => [
],
'hashid' => false,
];
public function getRelations()
{
return $this->info['relations'];
}
public function getRules()
{
return $this->info['rules'];
}
public function useHashid()
{
return $this->info['hashid'];
}
public function institution()
{
return $this->belongsTo(Institution::class);
}
public function rateTables()
{
return $this->hasMany(RateTable::class);
}
public function rateRows()
{
return $this->hasMany(RateRow::class);
}
public function rateRistournes()
{
return $this->hasMany(RateRistourne::class);
}
}
And this is the function that contain the query into ModelsController:
public function show($name, $id)
{
$data = $this->retrieveModelAndRelations($name, $id);
if (is_null($data)) {
return $this->sendError('Model not found.');
}
return $this->sendResponse($data->toArray(), 'Model retrieved successfully.');
}
private function retrieveModelAndRelations($name, $id)
{
$modelName = 'App\Models\\'.$name;
$model = new $modelName;
if ($id === 'null') {
...
} else {
$data = $modelName::when(isset($model->getRelations()['customer']), function($query) {
return $query->with('customer');
})...
})->when(isset($model->getRelations()['rateTables']), function($query) {
return $query->with(array('rateTables' => function($q) {
$q->orderBy('cashStart', 'ASC');
}));
})->when(isset($model->getRelations()['rateRows']), function($query) {
return $query->with(array('rateRows' => function($q) {
$q->orderBy('rate', 'ASC');
}));
})->when(isset($model->getRelations()['rateRistournes']), function($query) {
return $query->with(array('rateRistournes' => function($q) {
$q->orderBy('ristourne', 'ASC');
}));
})->find($id);
}
return $data;
}
And there is the result into the console:
created_at:(...)
deleted_at:(...)
id:(...)
institution_id:(...)
name:(...)
rate_ristournes:Array(1)
rate_rows:Array(1)
rate_tables:Array(1)
The 3 last line should be:
rateRistournes:Array(1)
rateRows:Array(1)
rateTables:Array(1)
Is there a way to force laravel to keep the relation key as I wrote it?
Something under the hood change the name and I don't know how to bypass it.
Change $snakeAttributes:
class Rate extends Model
{
public static $snakeAttributes = false;
}
I'm using Dingo API to create an API in Laravel 5.2 and have a controller returning data with
return $this->response->paginator($rows, new SymptomTransformer, ['user_id' => $user_id]);
However, I don't know how to retrieve user_id value in the SymptomTransformer! Tried many different ways and tried looking into the class but I'm relatively new to both Laravel and OOP so if anyone can point me to the right direction, it'd be greatly appreciated.
Below is my transformer class.
class SymptomTransformer extends TransformerAbstract
{
public function transform(Symptom $row)
{
// need to get user_id here
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
}
You can pass extra parameter to transformer constructor.
class SymptomTransformer extends TransformerAbstract
{
protected $extra;
public function __construct($extra) {
$this->extra = $exta;
}
public function transform(Symptom $row)
{
// need to get user_id here
dd($this->extra);
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
}
And call like
return $this->response->paginator($rows, new SymptomTransformer(['user_id' => $user_id]));
You can set extra param via setter.
class SymptomTransformer extends TransformerAbstract
{
public function transform(Symptom $row)
{
// need to get user_id here
dd($this->test_param);
return [
'id' => $row->id,
'name' => $row->name,
'next_type' => $next,
'allow' => $allow
];
}
public function setTestParam($test_param)
{
$this->test_param = $test_param;
}
}
And then:
$symptomTransformer = new SymptomTransformer;
$symptomTransformer->setTestParam('something');
return $this->response->paginator($rows, $symptomTransformer);
If you are using Dependency Injection, then you need to pass params afterwards.
This is my strategy:
<?php
namespace App\Traits;
trait TransformerParams {
private $params;
public function addParam() {
$args = func_get_args();
if(is_array($args[0]))
{
$this->params = $args[0];
} else {
$this->params[$args[0]] = $args[1];
}
}
}
Then you implement the trait in your transformer:
<?php
namespace App\Transformers;
use App\Traits\TransformerParams;
use App\User;
use League\Fractal\TransformerAbstract;
class UserTransformer extends TransformerAbstract
{
use TransformerParams;
public function transform(User $user)
{
return array_merge([
'id' => (int) $user->id,
'username' => $user->username,
'email' => $user->email,
'role' => $user->roles[0],
'image' => $user->image
], $this->params); // in real world, you'd not be using array_merge
}
}
So, in your Controller, just do this:
public function index(Request $request, UserTransformer $transformer)
{
$transformer->addParam('has_extra_param', ':D');
// ... rest of the code
}
Basically, the trait is a bag for extra params.
I get an error while using getAttributes method : "Call to a member function getAttributes() on a non-object".
Now, In my Controller:
$notifications = Notifications::return_new()->getAttributes();
var_dump($notifications);
In model
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->all();
}
Now, the Yii docs say that getAttribute() takes an array as a parameter, so I've tried
$notifications = Notifications::return_new()->getAttributes('text');
but it still persists with the same error. Any help?
Here is the model
<?php
namespace frontend\models;
use Yii;
*/
class Notifications extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'notifications';
}
public function rules()
{
return [
[['created_on', 'user_id', 'text'], 'required'],
[['user_id'], 'integer'],
[['created_on'], 'safe'],
[['text'], 'string', 'max' => 255]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'created_on' => 'Created On',
'user_id' => 'User ID',
'text' => 'Text',
];
}
public static function count_new()
{
$new = Notifications::find()->where(['is_seen' => 0])->all();
return count($new);
}
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->all();
}
public function return_all(){
return Notifications::find()->all();
}
public static function checkst(){
return Notifications::find()->where(['id' => 3])->one();
}
public function return_by_date () {
// write something here.
}
}
If you use all() you obtain a collection of models and then you should refere to
Notifications::return_new()[0]->getAttributes();
otherwise you can
public static function return_new(){
return Notifications::find()->where(['is_seen' => 0])->one();
}
and in this case you can use
$notifications = Notifications::return_new()->getAttributes();
I'm trying to seed a database using some model factories but I'm getting error call to member function create() on a non-object
Below are my model factories:
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->make()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->make()->id,
'remember_token' => str_random(10),
];
});
In my seeder I'm using the following to create 2 organizations and a associate a user and a department to each organization and then to make a user the manager of that department:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = $o->users()->save(factory(App\User::class)->make());
$department = $o->departments()->save(factory(App\Department::class)->make());
$department->managedDepartment()->create([
'organisation_id' => $o->id,
'manager_id' => $user->id,
]);
});
However I'm getting fatalerrorexception call to member function create() on a non-object
I thought $department is an object?
My department model is as follows:
class Department extends Model
{
protected $fillable = ['name','organisation_id'];
public function organisation()
{
return $this->belongsTo('App\Organisation');
}
/* a department is managed by a user */
public function managedDepartment()
{
$this->hasOne('App\ManagedDepartment');
}
}
And my managedDepartment model is as follows:
class ManagedDepartment extends Model
{
protected $table = 'managed_departments';
protected $fillable = ['organisation_id', 'department_id', 'manager_id',];
public function department()
{
$this->belongsTo('App\Department');
}
public function manager()
{
return $this->belongsTo('App\User');
}
}
Can anyone help?
Try to return your relation
public function department()
{
return $this->belongsTo('App\Department');
}
And here
/* a department is managed by a user */
public function managedDepartment()
{
return $this->hasOne('App\ManagedDepartment');
}
I think it will resolve your problem.
Firstly, do not make foreign keys fillable!
Secondly, where is your organisation function in ManagedDepartment? You should create one, otherwise the following will not work, because association is not possible.
Thirdly, I think you should change make() to create() in the following
$factory->define(App\Organisation::class, function ($faker) {
return [
'name' => $faker->company,
];
});
$factory->define(App\Department::class, function ($faker) {
return [
'name' => $faker->catchPhrase,
'organisation_id' => factory(App\Organisation::class)->create()->id,
];
});
$factory->define(App\User::class, function ($faker) {
return [
'email' => $faker->email,
'password' => str_random(10),
'organisation_id' => factory(App\Organisation::class)->create()->id,
'remember_token' => str_random(10),
];
});
Furthermore:
factory(App\Organisation::class, 2)
->create()
->each(function ($o)
{
$user = factory(App\User::class)->create();
$o->users()->attach($user->id);
$department = factory(App\Department::class)->create();
$o->departments()->attach($department);
$managedDep = new ManagedDepartment();
$managedDep->associate($o);
$managedDep->associate($user);
$managedDep->associate($department);
$managedDep->save();
});