Laravel 6 with function not showing related data - php

I've made a really simple function in Laravel 6 that uses with():
$forms = Form::with('itemsForms')->get();
return response()->json([
'code' => 200,
'data' => $forms
]);
The following are the relationships between Form and ItemsForm:
//Form
protected $fillable = [
'title',
'subtitle',
'text',
'name',
'email',
'phone_number',
'address',
'board',
'date',
'file',
'purchasable',
'payment_for',
'invoice_amount',
];
protected $visible = [
'title',
'subtitle',
'text',
'name',
'email',
'phone_number',
'address',
'board',
'date',
'file',
'purchasable',
'payment_for',
'invoice_amount',
];
public function itemsForms()
{
return $this->hasMany('App\ItemsForm');
}
//ItemsForm
protected $fillable = [
'item_id', 'form_id'
];
public function form()
{
return $this->belongsTo('App\Form', 'form_id');
}
The thing is it doesn't retrieve any data from ItemsForm.
Here's some of what I've tried:
I tried changing parameter in with to other similar names but in each case I got an error of "relationship not found" or something like that. When I use itemsForms I get no error.
I tried debugging it enabling the query log. Here's what I got:
array:2 [
0 => array:3 [
"query" => "select * from `forms`"
"bindings" => []
"time" => 5.77
]
1 => array:3 [
"query" => "select * from `items_forms` where `items_forms`.`form_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)"
"bindings" => []
"time" => 1.03
]
]
I tried getting the ItemsForm data and it retrieves it with no issue (ItemsForm::all()).
Any idea of what could be causing this?
Edit: the schema for ItemsForm is the following:
Schema::create('items_forms', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('item_id');
$table->unsignedBigInteger('form_id');
$table->foreign('item_id')
->references('id')->on('items')
->onDelete('no action')
->onUpdate('no action');
$table->foreign('form_id')
->references('id')->on('forms')
->onDelete('no action')
->onUpdate('no action');
});

Change the relationship as follows..
In Form class
public function itemsForms()
{
return $this->hasMany('App\ItemsForm','form_id','id');
}
In ItemsForm
public function form()
{
return $this->belongsTo('App\Form', 'id','form_id');
}
You can use the relationship as
$res = Form::find($id);
foreach($res->itemsForms as $item)
{
echo $item->item_id;
}

I finally found out what the issue was.
The issue was I didn't include itemsForms in the visible array (even though it is not part of the database fields).
There was no particular reason to include the visible array in my case so I deleted it but if I had wanted to keep it I should have included itemsForms as an element of the array.

Related

Eager Load Pivot in nested BelongsToMany with Api Resource

I need your help!
I'm having problems returning pivot table information when using ApiResources.
If I have a model like this:
Post.php
public function likes()
{
return $this->belongsToMany(Like::class)
->withPivot(['points']) // I want this in my PostResource::collection !
}
When defining its Resources:
LikeResource.php
public function toArray($request)
{
return [
'like_field' => $this->like_field
];
}
PostResource.php
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes'))
];
}
Then in PostController.php
return PostResource::collection(Post::with('likes')->get())
It will return something like this:
Controller Response
[
{
'title' => 'Post 1'
'likes' => [
{
'like_field' => 'Test'
},
{
'like_field' => 'Test 2'
}
]
},
{
'title' => 'Post 2',
...
}
]
The problem is, using that LikeResource::collection() it does not appends pivot information. How could I add 'points' of the pivot table when defining that PostResource??
Thats all,
Thx!
Solution
Well, simply reading a bit in Laravel Docs, to return pivot information you just has to use the method $this->whenPivotLoaded()
So, the PostResource becomes:
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes')),
'like_post' => $this->whenPivotLoaded('like_post', function() {
return $this->pivot->like_field;
})
];
}

Laravel pagination append data in one variable and other in another variable

I am facing a problem in laravel pagination. In laravel when I called paginate() method it returns
{
"total": 50,
"per_page": 15,
"current_page": 1,
"last_page": 4,
"first_page_url": "http://laravel.app?page=1",
"last_page_url": "http://laravel.app?page=4",
"next_page_url": "http://laravel.app?page=2",
"prev_page_url": null,
"path": "http://laravel.app",
"from": 1,
"to": 15,
"data":[
{
// Result Object
},
{
// Result Object
}
]
}
This type of Object. What I want is that I want to set data in one vairable for example $a and except data all other value in $b.
But when I added appends('data') of my paginate variable it did not working correctly. I did not find a solution after googling it. Please help me to solve this.
Here is User model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable {
use Notifiable;
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'status', 'role_id',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
My Controller Code is
public function index() {
$users = User::where('status', 1)->paginate(10);
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users->appends('data')->toArray(),
],
]
);
}
I tried this code
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users->only($user['data'])->toArray(),
'users_pagination' => $users->except($user['data'])->toArray(),
],
]
);
In this users work correctly but users_pagination not working correctly. In both the users, users_pagination returns same value
Try this
$paginateData = User::where('status', 1)->paginate(10);
$arrPaginateData = $paginateData->toArray();
$users = $arrPaginateData['data'];
unset($arrPaginateData['data']); //remove data from paginate array
$pageInfo = $arrPaginateData;
Return in response
return response()->json(
[
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users,
'users_pagination' => $pageInfo
],
]
);
Why not try to iterate the object? the below code will attached user specific data into each users.
public function index() {
$users = User::where('status', 1)->paginate(10);
foreach($users as $users){
$users->data = 'your data here';
}
return response()->json([
'error' => 0,
'errorMsg' => '',
'data' => [
'users' => $users,
],
]
);
}
If you want to use Laravel appends you have to follow as per the document.

Laravel 5.3 get boolean value from associative array

I have a ImageController like this:
$image = Image::where('id', $id)->first();
return [
'image' => $image,
'image_360' => $image['360']
];
The previous lines return to the browser the following:
{
"image": {
"id": 1,
"name": "default.jpg",
"360": 1,
},
"image_360": null
}
The Image migration:
$table->increments('id');
$table->string('name');
$table->boolean('360');
The Image model:
class Image extends Model
{
protected $fillable = ['name', '360'];
protected $casts = [
'360' => 'boolean'
];
}
Why $images['360'] returns null if its value is true?
Here is the workaround way: I've tryed many ways but havenot get a direct way to access the number value as descripted in this post
return [
'image' => $image,
'image_360' => array_values($image->toArray())[2];
];

Sorting calculated fields in Yii2 (Grid View)

i am need to sort some fields (asc,desc) in GridView, but same fields are calculated. Look at code below:
SearchModel:
class ObjectSearch extends Object {
use SearchModelTrait;
public function rules()
{
return [
['id', 'integer', 'min' => 1],
];
}
public function search($params)
{
$this->company_id = \Yii::$app->user->identity->companyId;
$query = Object::find()->where(['company_id' => $this->company_id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'name',
'lastReportResult' => [
'asc' => ['lastReportResult' =>SORT_ASC ],
'desc' => ['lastReportResult' => SORT_DESC],
'default' => SORT_ASC
],
'reportPercentDiff'
]
]);
if (!($this->load($params,'ObjectSearch') && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'id');
return $dataProvider;
}
Methods in Object model:
public function getLastReportResult()
{
$lastReport = $this->getLastReport();
$message = 0;
if (!empty($lastReport)) {
$statistic = new ReportStatistic($lastReport);
$message = $statistic->getPercent();
}
return $message;
}
/**
* #return int
*/
public function getReportPercentDiff()
{
$lastReport = $this->getLastReport();
$message = 0;
if (!empty($lastReport)) {
$statistic = $lastReport->getReportDiff();
if (!empty($statistic['diff'])) {
$message = $statistic['diff']['right_answers_percent_diff'];
} elseif (!empty($statistic['message'])) {
$message = $statistic['message'];
}
}
return $message;
}
So, by this methods, i am calculating a values of two fields, which are need's sorting. This way doesn't working, i have a Database Exception, because object table hasn't this fields. exception
How to do sorting of this fields ?
Update: I am the author of this answer and this answer is not accurate. Preferred way is to use database view
Add two public properties to ObjectSearch.php and mark it as safe
class ObjectSearch extends Object {
use SearchModelTrait;
public $lastReportResult, $reportPercentDiff;
public function rules()
{
return [
['id', 'integer', 'min' => 1],
[['lastReportResult', 'reportPercentDiff'], 'safe']
];
}
public function search($params)
{
$this->company_id = \Yii::$app->user->identity->companyId;
$query = Object::find()->where(['company_id' => $this->company_id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'name',
'lastReportResult' => [
'asc' => ['lastReportResult' =>SORT_ASC ],
'desc' => ['lastReportResult' => SORT_DESC],
'default' => SORT_ASC
],
'reportPercentDiff' => [
'asc' => ['reportPercentDiff' =>SORT_ASC ],
'desc' => ['reportPercentDiff' => SORT_DESC],
'default' => SORT_ASC
],
]
]);
if (!($this->load($params,'ObjectSearch') && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'id');
return $dataProvider;
}
Then in index.php (view file in which you are having grid view) add lastReportResult and reportPercentDiff in array of all attributes (list of all attributes ob Object model)
...
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// your other attribute here
'lastReportResult',
'reportPercentDiff',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
...
For more info you can visit Kartik's blog at Yii
Though this is an old thread, stumbled upon this and tried to find other method to achieve sorting of purely calculated field to no avail... and this post unfortunately is not an answer as well... It just that I feel the need to post it here to give a heads up to those that still looking for the solution so as not to scratch their heads when trying the solution given and still fail.
The given example from documentation or referred links as far as I have tested only works if you have a column within the database schema (whether in the main table or the related tables). It will not work if the virtual attribute/calculated field you create is based on calculating (as an example multiplication of 2 column on the table)
e.g:
table purchase: | purchase_id | product_id | quantity |
table product: | product_id | unit_price |
then, if we use a virtual attribute 'purchase_total' for model 'purchase' which is the multiplication of quantity and unit_price (from the join table of purchase and product on product_id), eventually you will hit an error saying 'purchase_total' column can not be found when you tried to sort them using the method discussed so far.

Cake 3 saving belongsToMany relation crashes

I currently have an belongsToMany relationship between two Table, Skus and Medias. I named the join table skus_images though.
I'm here trying to save only ids, not inserting new data in an HABTM way.
I have in my form :
echo $this->Form->input('images._ids', ['options' => $images, 'multiple' => 'checkbox']);
And everything is working fine there, I'm correctly getting my Medias listed.
But whenever I try to submit the form, I get this :
Error: Call to a member function get() on a non-object
File /home/weshguillaume/AndyToGaby/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php
Line: 874
I've defined my relationship as such in SkusTable :
$this->belongsToMany('Images', [
'className' => 'Media.Medias',
'joinTable' => 'skus_images',
'targetForeignKey' => 'image_id'
]);
The context doesn't give any insights, neither does the stack trace as it's both (almost) empty. Thanks :)
EDIT:
Controller add method:
public function add($product_id)
{
$skus = $this->Skus->newEntity();
if ($this->request->is('post')) {
$skus = $this->Skus->patchEntity($skus, $this->request->data(), [
'associated' => [
'Attributes'
]
]);
if ($this->Skus->save($skus)) {
$this->Flash->success('The skus has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The skus could not be saved. Please, try again.');
}
}
$attributes = $this->Skus->Attributes->find('list');
$images = $this->Skus->Products->getMedias('list', $product_id, 'photo');
$this->set(compact('skus', 'products', 'attributes', 'images', 'product_id'));
$this->set('_serialize', ['skus']);
}
Controller posted data:
[
'product_id' => '65',
'attributes' => [
'_ids' => ''
],
'reference' => '',
'quantity' => '420',
'is_default' => '0',
'images' => [
'_ids' => [
(int) 0 => '90'
]
]
]
Forgot to add the name of the association in the patchEntity associated option. Still shouldn't throw a fatal error so I created a github ticket.

Categories