I have user resource as follow:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->posts()->paginate(10)),
];
}
In User model, there is hasMany relation posts
My problem with paginating, the links and meta of post paginate does not show just get 10 posts without links of paginate
My controller
$user = User::query()
->where('id', $userId)
->with('posts')
->firstOrFail();
return new UserResource($user);
I think it's because you return the posts attribute as a collection not pagination.
Try
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => $this->posts()->paginate(10),
];
Laravel doesn't handle this case for you.
You have just 2 options:
Write a custom pagination logic
Just use two different API's with dedicated pagination in the posts API (recommended)
Related
I was using these codes in my controller to get all the data from my 2 tables and it works fine
$All = Customers::with('order')->paginate(10);
return response()->json([
'code' => 0,
'success' => true,
'data' => $All
], 200);
Here is how I define the relationship between these 2 tables
class Customers extends Model
{
public function order()
{
return $this->hasMany(Orders::class, 'customer_id', 'id');
}
}
class Orders extends Model
{
public function customers()
{
return $this->belongsTo(Customers::class, 'customer_id', 'id');
}
}
Now my desire output is to hide the order id, order timestamps and change the customer_id to customer's name (the customer's name is not in my orders db table).
I'm using 'data' => DataResource::collection($All) in my controller and this is my DataResource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'order' => $this->order
];
}
and of course the output is same with the image above.
My database structure:
orders table:
customer table:
Can anyone help me with that?
The answer is simple and basically a copy of the official documentation. You simply need to wrap your orders in an OrderResource as well.
// DataResource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'order' => OrderResource::collection($this->order)
];
}
// OrderResource
public function toArray($request)
{
return [
'items' => $this->items,
'quantity' => $this->quantity
];
}
I don't really understand why you would want to include the customer_name in your orders when it is already present on the customers object one hierarchy above. But if you really want to add it, you should be able to do so with: 'customer_name' => $this->customers->name.
As a side note: you really should be more consistent with your naming. Why is the resource called DataResource when it is about Customers? Why is your model called Customers in plural form rather than Customer in singular, which is the convention (and more logical if you consider that one model represents one customer). Why is your belongsTo relation called customers() in plural when it returns one customer, while your hasMany relation is called order whereas it returns one or more orders?
I'm developing a laravel application with user and post model and i'm getting an error of:
Field 'user_id' doesn't have a default value
I have set up relationships for both models. Post belongs to user and a user can have as many posts. The user_id is not being saved to the post table in the database.
Post Controller:
class PostController extends Controller
{
public function postCreatePost(Request $request){
$this->validate($request, [
'body' => 'required'
]);
$post = new Post([
'body' => $request->input('body')
]);
$post->save();
return redirect()->route('dashboard');
}
Route:
Route::post('/createpost', [
'uses' => 'PostController#postCreatePost',
'as' => 'post.create'
]);
You need to specify user_id:
$post = new Post([
'body' => $request->input('body'),
'user_id' => auth()->user()->id
]);
Or you could use relationship:
$user = auth()->user();
$user->posts()->create(['body' => $request->input('body')]);
Also, don't forget to add user_id to the $fillable array in the Post model.
The reason is you are not giving a user_id when saving a post.
One solution is.
$post = new Post([
'body' => $request->input('body'),
'user_id' => $your_use_id
]);
I've used the Gii AJAX Crud generator, and I'm being driven up a wall by my own stupidity. I am using Yii 2 and want to search with many to many, on a table that has that relation with ITSELF in a junction table, with the Grid View.
table tag (id, name).
table tag_child (parent_id, child_id)
Class Tag
...
public function getParents()
{
return $this->hasMany(self::className(), ['id' => 'child_id'])
->viaTable('tag_child', ['parent_id' => 'id']);
}
public function getChildren()
{
return $this->hasMany(self::className(), ['id' => 'parent_id'])
->viaTable('tag_child', ['child_id' => 'id']);
}
And in my grid-view /columns:
[
'class' => '\kartik\grid\DataColumn',
'attribute'=>'name',
],
[
'class' => '\kartik\grid\DataColumn',
'label' => 'Tag Type',
'value' => function($tag) {
return $tag->displayTagTypes();
},
'attribute' => 'tagTypes'
],
TagQuery.php
...
public $tagTypes;
public function search($params)
{
$query = Tag::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// $query->where('0=1');
return $dataProvider;
}
$query->joinWith('parents p');
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'tag.name', $this->name]);
return $dataProvider;
}
I'm able to display the results in my index table with that value function, but my Tag filter isn't able to search by tagTypes. How do I populate that?
As an example, when it's not many to many, I can use set my attribute to 'joinedTableName.value' and it works as soon as I add a $query->orFilterWhere('like', 'parent.name', $this->id) or whatever. But I'm at a loss now...
Declare $searchModel = new TagQuery() in your controller, then pass the $searchModel to the view and include it in the GridView options as 'filterModel' => $searchModel.
Either that, or you can do really custom filters using specific filterTypes and filter logic for each column.
You declare public tagType in the query model, but you don't do anything with it. $query->andFilterWhere(['like', 'tag.name', $this->tagType]);
I am converting an internal API from HTML (back-end) processing to JSON (using Knockout.js) processing on the client-side to load a bunch of entities (vehicles, in my case).
The thing is our database stores sensitive information that cannot be revelead in the API since someone could simply reverse engineer the request and gather them.
Therefore I am trying to select specifically for every relationship eager-load the columns I wish to publish in the API, however I am having issues at loading a model relationship because it seems like Eloquent automatically loads every column of the parent model whenever a relationship model is eager loaded.
Sounds like a mindfuck, I am aware, so I'll try to be more comprehensive.
Our database stores many Contract, and each of them has assigned a Vehicle.
A Contract has assigned an User.
A Vehicle has assigned many Photo.
So here's the current code structure:
class Contract
{
public function user()
{
return $this->belongsTo('User');
}
public function vehicle()
{
return $this->belongsTo('Vehicle');
}
}
class Vehicle
{
public function photos()
{
return $this->hasMany('Photo', 'vehicle_id');
}
}
class Photo
{
[...]
}
Since I need to eager load every single relationship listed above and for each relationship a specific amount of columns, I need to do the following:
[...]
$query = Contract::join('vehicles as vehicle', 'vehicle.id', '=', 'contract.vehicle_id')->select([
'contract.id',
'contract.price_current',
'contract.vehicle_id',
'contract.user_id',
'contract.office_id'
]);
[...]
$query = $query->with(['vehicle' => function ($query) {
$query->select([
'id',
'trademark',
'model',
'registration',
'fuel',
'kilometers',
'horsepower',
'cc',
'owners_amount',
'date_last_revision',
'date_bollo_expiration',
'bollo_price',
'kilometers_last_tagliando'
]);
}]);
$query = $query->with(['vehicle.photos' => function ($query) {
$query->select([
'id',
'vehicle_id',
'order',
'paths'
])->where('order', '<=', 0);
}]);
$query = $query->with(['user' => function ($query) {
$query->select([
'id',
'firstname',
'lastname',
'phone'
]);
}]);
$query = $query->with(['office' => function ($query) {
$query->select([
'id',
'name'
]);
}]);
[...]
return $this->response->json([
'error' => false,
'vehicles' => $vehicles->getItems(),
'pagination' => [
'currentPage' => (integer) $vehicles->getCurrentPage(),
'lastPage' => (integer) $vehicles->getLastPage(),
'perPage' => (integer) $vehicles->getPerPage(),
'total' => (integer) $vehicles->getTotal(),
'from' => (integer) $vehicles->getFrom(),
'to' => (integer) $vehicles->getTo(),
'count' => (integer) $vehicles->count()
],
'banner' => rand(0, 2),
'filters' => (count($input) > 4),
'filtersHelpText' => generateSearchString($input)
]);
The issue is: if I do not eager load vehicle.photos relationship, columns are loaded properly. Otherwise, every single column of Vehicle's model is loaded.
Here's some pictures so you can understand:
Note: some information have been removed from the pictures since they are sensitive information.
You can set a hidden property on your models which is an array of column names you want to hide from being output.
protected $hidden = ['password'];
I am trying to update a blog post but I am getting unique key error from database part then I went without using model and directly accessing ORM but then again no success.
This is my routes spesific to edit
Route::get('/getedit/{slug}', array('as' => 'getedit', 'uses' => 'AdminController#getEdit'))->before('auth');
Route::post('/postedit', array('as' => 'postedit', 'uses' => 'AdminController#postEdit'))->before('auth');
Controller
public function getEdit($slug)
{
$article = Post::where('slug', '=' , $slug)
->firstOrFail();
return View::make('admin.edit', array(
'title' => $article->title,
'mainarticle' => $article->article,
'slug' => $article->slug,
'category' => $article->category
));
}
// Updates articles to database
public function postEdit()
{
$rules = [
'title' => 'required',
'article' => 'required',
'slug' => 'required|unique:posts,slug,9',
'category' => 'required'
];
$input = Input::all();
$validator = Validator::make($input, $rules);
if ($validator->fails()) {
return Redirect::route('getedit')
->withErrors($validator);
// withInput not defined
}
else
{
$slug = $input['slug'];
/*$affectedRows = Post::where('slug', '=', $slug)->update([
'title' => $input['title'],
'article' => $input['article'],
'slug' => $input['slug'],
'category' => $input['category']
]);*/
/*$affectedRows = Post::where('slug', '=', $slug)->firstOrFail();
$affectedRows->title = $input['title'];
$affectedRows->article = $input['article'];
$affectedRows->slug = $input['slug'];
$affectedRows->category = $input['category'];
$affectedRows->save();*/
$post = DB::table('posts')->where('slug', '=', $slug)->update([
'title' => $input['title'],
'article' => $input['article'],
'slug' => $input['slug'],
'category' => $input['category']
]);
if ($post) {
return Redirect::route('dashboard')
->with('flash_message','Article Successfully Inserted');
}
else
{
return Redirect::route('dashboard')
->with('flash_message','Error updating data');
}
}
}
My model is just creating object of database (I am accidentally following fat controller and thin model approach as I am just trying the framework).
I have tried using Post::find(1)->update($data); method but that is returning unique violation and my current approach is just executing else statement which is triggered upon update failure.
Note: I am new to Laravel and trying this for the first time.
When you update a post, you'd rather send a POST (or better PATCH/PUT- http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) request to given resource.
That said, you would include edited row key in the url, and change your method to something like this:
// route
Route::post('/postedit/{id}', array('as' => 'postedit', 'uses' => 'AdminController#postEdit'))
->before('auth');
// controller
public function postEdit($id)
{
// if no posts with $id found, throws exception - catch it and eg. show 404
$post = Post::findOrFail($id);
$rules = [
'title' => 'required',
'article' => 'required',
'slug' => 'required|unique:posts,slug,'.$id, // to ignore this row in unique check
'category' => 'required'
];
// validate
$post->fill($input)->save(); // fill() in order to use mass-assignement check
// alternatively you can just update:
// $post->update($input);
// but then make sure $input has only elements corresponding to the table columns
Additionally, read about route grouping, so you don't need to add before('auth') to those routes separately.
You should check your database table indexes. You should make sure that only slug has unique index.
I see that you are checking unique for slug but you hardcoded 9 in the rule:
'slug' => 'required|unique:posts,slug,9',
It should be:
'slug' => 'required|unique:posts,slug,'.$id,
where $id id of post you try to edit.
You should include such id in your form as hidden element and not search records with slug that you have because it seems you can edit your slug and you may edit the wrong record or edit nothing.