Yii2 display multiple values from one relation in GridView - search

I did my grid by the this instruction http://www.yiiframework.com/wiki/653/displaying-sorting-and-filtering-model-relations-on-a-gridview/
and it worked. But now I need to have two columns with data related to one column. For example in person/index the gridView must display cityName and cityRegion from the related record in the City table.
I managed to display the data, but can't get the search functionality working.
In the example from the link, at the end of the function search() there is
$query->andFilterWhere([
//... other searched attributes here
])
// Here we search the attributes of our relations using our previously configured
// ones in "TourSearch"
->andFilterWhere(['like', 'tbl_city.name', $this->city])
->andFilterWhere(['like', 'tbl_country.name', $this->country]);
I think I should have something like:
->andFilterWhere(['like', 'tbl_city.name', $this->city])
->andFilterWhere(['like', 'tbl_city.region', $this->city])
...but I don't know how to get the actual search values for (in this case name and region).
Thanks!
EDIT*
Here is the whole search() and rules definition: http://pastebin.com/mUVDYNiH
Currently the sorting of prod_ProductCode and prod_Manufacturer is working, but the search boxes for them doesn't show up.

Check here yii2 ActiveQuery 'OR LIKE' filter:
$query->andFilterWhere([
'or',
['like', 'tbl_city.name', $this->city],
['like', 'tbl_city.region', $this->city],
]);

Related

Whats the best way to handle related data ids using Tabulator

Using Tabulator, if you have a 'select' editor and want it to link to values 'Male' and 'Female' but underneath male and female are values from another physical database table with id values of 1 and 2 (which are different than the 'row' id), whats the best way to do something like this?
The 'select' editor has ways to specify the display of items in the drop down and a literal display of the selected value, but no place for a hidden (not displayed) underlying ID of the selected value to pass when saving the data.
We could wrap the select data values in divs with a data attribute for the selects values ids and then pass that when updating, but are not sure this is the best option considering how Tabulator works. We could also just pass the raw selected value and then look it up on the server to get the associated ID, but that seems like a lot of overhead and tightly couples the server to the client, which wouldn't work for something like a 3rd party API where we have no server control.
Any thoughts on how best to handle something like this are appreciated!
The select editor allows for values to be passed in a number of ways, including specifying both the items value and its user visible label
If you want to show a different lable to the value you want to store, you can pass in an object, where the key of each property is the value that will be stored if it is selected, and the value of each property will be the lable displayed for it in the list.
{title:"Name", field:"name", editor:"select", editorParams:{
values:{
"steve":"Steve Boberson",
"bob":"Bob Jimmerson",
"jim":"Jim Stevenson",
}
}}
For more complex option lists you can use an array of objects, that allows you to define option groups, and disabled options.
{title:"Name", field:"name", editor:"select", editorParams:{
values:[
{ //option group
label:"Men",
options:[ //options in option group
{
label:"Steve Boberson",
value:"steve",
},
{
label:"Bob Jimmerson",
value:"bob",
},
]
},
{ //option group
label:"Women",
options:[ //options in option group
{
label:"Jenny Jillerson",
value:"jenny",
},
{
label:"Jill Betterson",
value:"jill",
},
]
},
{//ungrouped option
label:"Other",
value:"other",
},
]
}}
For full details on how to use this editor, checkout the Editor Documentation
Finally figured this out. You need to use the lookup formatter to display the text value using the same params as the select editor. This is not obvious since none of the select editor examples in the docs show use of it. Anyway, here is a simple example showing it in both directions. Of course you would want to abstract the data out instead of literally duplicating it, but here to help show the literal use, it is duplicated:
{
title:"Example",
field:"example",
editor: "select",
editorParams:{
"1": "Cute",
"2": "Fine",
"3": "Scary",
},
formatter:"lookup", // display option, but store value
formatterParams:{
"1": "Cute",
"2": "Fine",
"3": "Scary",
}
}

How to filter on view using complex query

I am trying to filter on a view which emits bookName and bookItem.
emit([doc.basicInfo.bookName,doc.basicInfo.bookItem], 1);
it gives me below result without any query:
{"total_rows”:10,”offset":0,"rows":[
{"id":"d4e5548fb01e6e2c559e702fe7b138ad","key":["correctaccouts","billing"],"value":1},
{"id":"863c46c645b6344719a08231606f2a7d","key":["credeaccount","system"],"value":1},
{"id":"68d39e64c406127960dc735e8167eee3","key":["credeaccount11","system"],"value":1},
{"id":"1ab4d31588d76a42e85b526a316074de","key":["mayankamazon","billing"],"value":1},
{"id":"3204f5db5df91886373f95995ce09a2d","key":["mayankazure","asset"],"value":1},
{"id":"452c040048fb2b779205b3785615d368","key":["mayankmaaa","system"],"value":1},
{"id":"23f01f7bc60c2c8f24f6b741584a69fa","key":["TEST_AWS_Delete212sss12","asset"],"value":1},
{"id":"f0093f474e0d50f046b9fdc9145bdc91","key":["vijeth-myteam111115555555","asset"],"value":1},
{"id":"c3bce8dd1482d841f445fbd617ba1db7","key":["vijeth-myteam11111555sss5555","asset"],"value":1},
{"id":"347479ba91696b73f4a57252cd00a358","key":["vijeth-myteamOnly","asset"],"value":1}
]}
Now I am trying to query on it using complex keys:
satrtkey=[{},"asset"]&endkey=[{},"asset"]
It should return me:
{"total_rows”:5,”offset":0,"rows":[
{"id":"3204f5db5df91886373f95995ce09a2d","key":["mayankazure","asset"],"value":1},
{"id":"23f01f7bc60c2c8f24f6b741584a69fa","key":["TEST_AWS_Delete212sss12","asset"],"value":1},
{"id":"f0093f474e0d50f046b9fdc9145bdc91","key":["vijeth-myteam111115555555","asset"],"value":1},
{"id":"c3bce8dd1482d841f445fbd617ba1db7","key":["vijeth-myteam11111555sss5555","asset"],"value":1},
{"id":"347479ba91696b73f4a57252cd00a358","key":["vijeth-myteamOnly","asset"],"value":1}
]}
But it still gives me all 10 records. I want to filter only records of type "asset".
To use key ranges, you must narrow down your research starting with the left fields to the right fields.
For example, if your key would be: [doc.basicInfo.bookItem,doc.basicInfo.bookName]
You could search with start_key=["asset",null]&end_key=["asset",{}]
Also, your current query is equivalent to key=[{},"asset"]. Instead, you should have tried: start_key=[null,"asset"]&end_key=[{},"asset"] but it should not work.
Example
View:
function (doc) {
emit([doc.basicInfo.bookItem,doc.basicInfo.bookName], 1);
}
Query:
http://localhost:5984/<db>/_design/<design_name>/_view/<view_name>?include_docs=true&inclusive_end=true&start_key=%5B%22asset%22%2Cnull%5D&end_key=%5B%22asset%22%2C%7B%7D%5D

Select Editor editorParams populate values from array in textfile?

I am using Tablulator v4.1. I am creating an interface for our pharmacy organization so a member can change the meeting information without doing any coding. One field is the meeting room location which is a select editor.
Is it possible to populate the values of editorParams with a path to an array stored in a different text file? Something like:
{title:"Room", field:"room", editor:"select", editorParams:{"/textfiles/roomvalues.txt"}},
I can then create another table to add/edit the possible room choices.
This code is what I currently use.
{title:"Room", field:"room", editor:"select", editorParams:{
values:{
"A":"Room A",
"B":"Room B",
"C":"Room C"}
}},
Thank you.
You can pass a function into the values property that can then return an array of values that you can load from elsewhere
{title:"Room", field:"room", editor:"select", editorParams:{
values:function(cell){
//lookup values from data source
return values;
}}},

Using a Lucene Filter to restrict items based on a list

I have a list of categories, e.g. 1000, 1001, 1002, 1003, etc... and users have access to only some of these categories. I want to filter my lucene.net search results based on only categories that the user has access to, or to omit results for items they don't have access to.
I have tried using the Lucene FieldCacheTermsFilter but this returns no results at all:
New Lucene.net.search.FieldCacheTermsFilter("category", {"1000", "1002"} )
Is there a better way to filter results based on a particular field having a value that exists in a list?
I solved this by using a BooleanQuery wrapper around my main query in all cases.
I took my originaly search query (MainQuery) and created a new BooleanQuery using occur.must for that and my security query as below:
dim SecurityQuery as New lucene.net.search.BooleanQuery( )
For Each id as string in AllowedIDs
q.Add(New TermQuery(New Lucene.Net.Index.Term("category", s)), Occur.SHOULD)
Next
Dim FinalQuery As New lucene.net.search.BooleanQuery( )
FinalQuery.Add( MainQuery, occur.must )
FinalQuery.Add( SecurityQuery, occur.must )
This doesn't use a Filter, so I am unsure as to whether this is the best performing option. But it works.

loopback relational database hasManyThrough pivot table

I seem to be stuck on a classic ORM issue and don't know really how to handle it, so at this point any help is welcome.
Is there a way to get the pivot table on a hasManyThrough query? Better yet, apply some filter or sort to it. A typical example
Table products
id,title
Table categories
id,title
table products_categories
productsId, categoriesId, orderBy, main
So, in the above scenario, say you want to get all categories of product X that are (main = true) or you want to sort the the product categories by orderBy.
What happens now is a first SELECT on products to get the product data, a second SELECT on products_categories to get the categoriesId and a final SELECT on categories to get the actual categories. Ideally, filters and sort should be applied to the 2nd SELECT like
SELECT `id`,`productsId`,`categoriesId`,`orderBy`,`main` FROM `products_categories` WHERE `productsId` IN (180) WHERE main = 1 ORDER BY `orderBy` DESC
Another typical example would be wanting to order the product images based on the order the user wants them to
so you would have a products_images table
id,image,productsID,orderBy
and you would want to
SELECT from products_images WHERE productsId In (180) ORDER BY orderBy ASC
Is that even possible?
EDIT : Here is the relationship needed for an intermediate table to get what I need based on my schema.
Products.hasMany(Images,
{
as: "Images",
"foreignKey": "productsId",
"through": ProductsImagesItems,
scope: function (inst, filter) {
return {active: 1};
}
});
Thing is the scope function is giving me access to the final result and not to the intermediate table.
I am not sure to fully understand your problem(s), but for sure you need to move away from the table concept and express your problem in terms of Models and Relations.
The way I see it, you have two models Product(properties: title) and Category (properties: main).
Then, you can have relations between the two, potentially
Product belongsTo Category
Category hasMany Product
This means a product will belong to a single category, while a category may contain many products. There are other relations available
Then, using the generated REST API, you can filter GET requests to get items in function of their properties (like main in your case), or use custom GET requests (automatically generated when you add relations) to get for instance all products belonging to a specific category.
Does this helps ?
Based on what you have here I'd probably recommend using the scope option when defining the relationship. The LoopBack docs show a very similar example of the "product - category" scenario:
Product.hasMany(Category, {
as: 'categories',
scope: function(instance, filter) {
return { type: instance.type };
}
});
In the example above, instance is a category that is being matched, and each product would have a new categories property that would contain the matching Category entities for that Product. Note that this does not follow your exact data scheme, so you may need to play around with it. Also, I think your API query would have to specify that you want the categories related data loaded (those are not included by default):
/api/Products/13?filter{"include":["categories"]}
I suggest you define a custom / remote method in Product.js that does the work for you.
Product.getCategories(_productId){
// if you are taking product title as param instead of _productId,
// you will first need to find product ID
// then execute a find query on products_categories with
// 1. where filter to get only main categoris and productId = _productId
// 2. include filter to include product and category objects
// 3. orderBy filter to sort items based on orderBy column
// now you will get an array of products_categories.
// Each item / object in the array will have nested objects of Product and Category.
}

Resources