I am working with four tables in Laravel and trying to display data to a view. I believe I am stuck because one of the tables has a composite primary key.
I have the following in my controller:
public function show($id)
{
//Get application for drug
$application = PharmaApplication::where('ApplNo', $id)->first();
//Return all products for application
$drugs = $application->products;
return view('profiles.drug', compact('drugs'));
}
I have the following in my PharmaApplication model:
public function products()
{
return $this->hasMany('App\PharmaProduct', 'ApplNo', 'ApplNo');
}
I have the following in my view (which I cannot complete)
#foreach ($drugs as $drug)
<li>{{$drug->Strength}}</li>
<li>{{$drug->Form}}</li>
<li>{{$drug->Form}}</li>
#endforeach
I am trying to accomplish the following:
Get the application for a drug - this part of my code works
Return an array of objects for the products (i.e. 7 products that belong to one application). I can do this but get stuck going to the next part.
Next, I have to use the array of objects and search a table with the following columns: MarketingStatusID, ApplNo, ProductNo. I know how to query this table and get one row using DB Query, but then how do I get the proper result to that query within the for loop in my view?
Finally, I use the MarketingStatusID to retrieve the MarketingStatusDescription which I will know how to do.
Please tell me details process and files in which changes need to make for showing the foreign key value in place of id as shown in the snap below:
Data Gridview generated using Ajax Crud Generator
My Scenario is I have two table 1) Screen and 2) SubScreen Table, The
Table Screen has two fileds screenId and screenName
And Table SubScreen has subscreenId subscreenName and Screen_ScreenId (as a foreign key) in the view of SubScreen Table I want to show screenName (from Screen table) in place of Screen_ScreenId (of SubScreen Table View)
Finally I found a solution to show foreign key value in place of foreign key id: I am posting this solution so that others who face the same issue can use this method to implement this in their code..
In the model class a relation function need to be created in my case:
my model class is Subscreen.php this has a relation function
public function getScreenScreen()
{
return $this->hasOne(Screen::className(), ['screenId' => 'Screen_ScreenId']);
}
the above mentioned function was auto generated when generated the model using the gii module.
What extra i did here in the model is added one more function code is as shown below
public function getScreenName()
{
return $this->screenScreen->screenName;
}
-------------------------Model changes ends up here-----------------------------
Now come to the _columns.php file of the view which was auto generated while generating the CRUD code using the Ajax Crud Generator extension..
...
[
'class'=>'\kartik\grid\DataColumn',
'attribute'=>'Screen_ScreenId',
'value'=>function($model){return $model->getScreenName();},
],
...
the last line in above code 'value'=>function($model) {return $model->getScreenName();}, is added by me as a extra line to get the functionality up in the view...this made it possible for me to show the ScreenName in place of their Id in the view.
Hope this will help you to solve the same issue...
I'm creating a food menu which the administrator can order/sort by dragging and dropping. This menu consists of multiple categories (ProductCategory) and products (Product).
I'm using HTML5Sortable on the client-side to allow nested d&d. The markup is pretty simple:
<div class="categories">
#foreach($categories as $category)
<div class="category">
#foreach($category->products as $product)
<div class="products">
<div class=""product" data=id="{{ $product->id }}">
{{ $product->name }}
</div>
</div><!-- /products !-->
#endforeach
</div><!-- /category !-->
#endforeach
</div>
And the corresponding javascript:
$('.categories').sortable({
items: '.category'
});
$('.products').sortable({
items: '.product'
});
// Will be called when the user is done repositioning the products and categories
function getOrderedList() {
var data = {};
$('.categories').find('.category').map(function(i) {
var category = $(this);
data[i] = {};
data[i].id = category.data('id');
data[i].products = category.find('.product').map(function() {
return $(this).data('id');
}).get();
});
data = JSON.stringify(data); // Send data to server
}
The function getOrderedList will send a JSON string back to Laravel, which contains the sorted category id's and product id's:
{"0":{"id":1,"products":[2,3,1,4,5,6,7,8,9,10]},"1":{"id":2,"products":[11,12,13,14]},"2":{"id":3,"products":[15,16,17,18]}}
How would I make this work on the back-end? I guess I must store this array somewhere in the database and later find and order the models by the id's?
In short: What is a clean and flexible solution for sorting (nested) models (within Laravel)?
A common convention is Weight, add a field called (Int)Weight on the products table, which is used to define the order of the items.
Once a change in the order occurs you only update the weight field.
When you retrieve the items, you sort them by Weight.
it becomes similar to an Array
Id Name Weight
01 'product 1' 2
02 'product 2' 0
03 'product 3' 1
when you order it by weight you get
product 2
product 3
product 1
it's similar to an array because
$products[0] = 'product 2'
$products[1] = 'product 3'
$products[2] = 'product 1'
Note that if you want to make it even more dynamic, you can create a polymorphic model that can satisfy multiple models.
Please refer to https://laravel.com/docs/5.1/eloquent-relationships#many-to-many-polymorphic-relations
Polymorphic Relations example
Create table Weights (migration example)
$table->increments('id');
$table->integer('value');
$table->integer('weightable_id')->unsigned();
$table->string('weightable_type');
Create model Weight
class Weight extends Eloquent
{
public function weightable()
{
return $this->morphTo();
}
}
now with any other model
class Products extends Eloquent
{
...
public function weight()
{
return $this->morphOne(Weight::class);
}
}
this way you can just add that method to any model you want then you can sort your model with it.
P.S. make sure any model that uses it, creates that relation immediately after creating the model
i do not recommend this method, it's much better if you explicitly define the weight field in the Products table, i understand how much you want your code to be dynamic, but everything comes at a cost
Performance goes down, it's not easy to visualize your code once you establish polymorphic relations, its more like starting to use Jumps instead of Functions
First, the JSON that you are producing shouldn't be an object where the keys are just array indices. Instead it should be an array of objects that looks like this:
[{"id":1,"products":[2,3,1,4,5,6,7,8,9,10]},{"id":2,"products":[11,12,13,14]},{"id":3,"products":[15,16,17,18]}]
Since the products table to product_categories table has an obvious many to one relationship, you'd just use the product_categories_id foreign key on the products table to represent the relationships laid out in your JSON.
In the nested objects of your JSON, every value in the products key array will have a foreign key that corresponds to the id key value in the same nested object (this is the product_category_id column on your products table).
Your API endpoint function would then look something like this:
public function myApiEndpoint(){
$input = Input::get('input');
$input = json_decode($input, true);
foreach($input as $category){
Product::whereIn('id', $category['products'])->update(array(
'product_category_id' => $category['id']
));
}
}
I am updating the model directly in the API controller here, but you should really do any model changes through a repository that's also implementing an interface.
The above will work if you only ever have one menu (with it's categories and products). If you want multiple menus, then you'll need a menus table along with a three way pivot table (with columns menu_id, product_id, and product_category_id).
I just implement this behavior using this library:
https://github.com/spatie/eloquent-sortable
It is very simple to implement, basically you need an extra column to keep the order and the library will do the rest, here is a part of the documentation:
Implement the Spatie\EloquentSortable\Sortable interface.
Use the trait Spatie\EloquentSortable\SortableTrait.
Optionally specify which column will be used as the order column. The default is order_column.
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
class MyModel extends Eloquent implements Sortable
{
use SortableTrait;
public $sortable = [
'order_column_name' => 'order_column',
'sort_when_creating' => true,
];
...
}
I have an issue that I can't use the sortWhitelist in paginate to enable the sort function towards the "2nd level's associated model's columns. (it works with the 1st level associated model's). Let me describe it clearly:
Table Background:
Users: id, name
Tickets: id, code, name, price
TicketsDiscounts: id, ticket_code, user_id, price
There is a default price in Tickets, and sometimes there are discounted tickets, offering a cheaper price.
Wish to do:
I am making the view page of Tickets, which doesn't only show the Ticket itself's data, also a table showing
TicketDiscounts records whereTickets.ticket_code = Tickets.code, and
Users records where TicketDiscounts.user_id = Users.user_id.
Issue:
It actually works fine, til I want to add some sort functions for the table.
I know there is a config key called sortWhitelist, but in this case it only supports "linking" TicketsDiscounts.
Like:
Tickets---->TicketsDiscounts [OK]
Tickets---->TicketsDiscounts---->Users [NOT OK]
In TicketsController.php:
public function view($id = null) {
$ticket = $this->Ticket->get($id);
$setting = [
"sortWhitelist" => [
"Users.id", "Users.name", "TicketsDiscounts.price"
]
];
$paginate_discountsowners = $this->paginate(
$this->Tickets->TicketsDiscounts
->findByTicketsCode($ticket->code)
->contain("Users"), $setting
);
$this->set('paginate_discountsowners', $paginate_discountsowners);
$this->set('_serialize', ['paginate_discountsowners']);
}
In view.ctp:
<td><?= $this->Paginator->sort("id", "User ID", ["model" => "Users"]) ?></td>
<td><?= $this->Paginator->sort("name", "User Name", ["model" => "Users"]) ?></td>
<td><?= $this->Paginator->sort("price", "Discount Price", ["model" => "TicketsDiscounts"]) ?></td>
Researched:
CakePHP - paginate and sort 2nd level association <-- This one is very close, but its CakePHP 2.x, I read it but hardly found this post useful for my case.
Pagination Sort in Cakephp 3.x <-- This is 3.x, well, but it is about 1-level associated model only.
Thank you for reading my post, any ideas are welcomed.
I stumbled over something similar. I have the structure Teachers -> Users -> Persons and want to sort by the person's forename.
TeachersController:
public $paginate = ['sortWhitelist' => ['Persons.forename']];
View:
<?= $this->Paginator->sort('Persons.forename') ?>
So, in short I think you can just have to change your first and second sort links to refer to the fields Users.id and Users.name.
Am learning laravel and I encountered a problem saving data into my database from my form.
My instance
when a user tries to make a multiple purchase of products ie.when a user purchases more than one product,i wanted to save the names of products that belongs to the purchase user made into my 'PURCHASES' table having an 'ID' of '1'.
Names of product to be save;
1.productA
2.productB
3.productC
Codes
FORM IN MY VIEW
<input type='hidden' name='product_name'
#foreach($order as $order)
value='{{$order->product_name}}'
#endforeach >
MY purchase CONTROLLER
Saving the names;
$purchase = new Purchase;
$purchase->product_name = $posted['product_name'];
$purchase->save();
When i initiate the function i get an error exception reading 'Trying to get property of non-object' from my view from the line;
#foreach($order as $order)
value='{{$order- >product_name}}'
#endforeach >
How do i go about this problem?
There are a lot of strange things in your code unless I'm reading it wrong, but most likely when you're seeing that error in a view it's because you didn't pass that data into the view. Take this example:
Controller
public function showProducts() {
// assuming $order_array is a set of product IDs that is part of an order
$orders = array('products' => Products::whereIn('id', $order_array);
return View::make('your/view' compact('orders'));
}
I don't quite understand what you're trying to do but passing the object array 'orders' to the view allows you to then call your line:
#foreach($orders as $order)
code here
#endforeach