How to select only needed fields of objects? - pimcore

I am using the Pimcore API to fetch objects.
$myObjects = new Object\MyObject\Listing();
$myObjects->load();
$myObjects->getObjects();
Works as expected. Now I want to select only a specific field of my objects, e.g. the name field.
How can I tell Pimcore to select only fields that I want? Is it even possibile through the API or do I need to use custom SQL? If so, how can I do that?
Best regards

The pimcore listing is always returning the complete set of objects matching your listing condition...
If you want a fast and easy way to only select one field of your object, I recommend to use the pimcore db class:
$db = \Pimcore\Db::get();
$fieldsArray = $db->fetchCol("SELECT `YOUR_FIELD` FROM `object_query_CLASS-ID`");
This will return you an array width all 'YOUR_FIELD' values from the object query table of your class.
To get the class ID for your query dynamically your should use:
$classId = \Pimcore\Model\Object\MyObject::classId();
Edit:
To get more than one field column, you need to use 'fetchAll' instead of 'fetchCol':
$fieldsArray = $db->fetchAll("SELECT `YOUR_FIELD`, `YOUR_FIELD_2` FROM `object_query_CLASS-ID`");

Related

How to make filters in queries optional

How to make a query filter bound to a request parameter inactive if the parameter is not present?
For example: I have a query MyQuery that can be accessed through the projection MyProjection. I add a filter to that query where I say that MyDate field should be equal to {Request.QueryString:MyDate}. I want URLs like ~/MyProjection?MyDate=2016-03-08 to filter content items by the given value, but the url ~/MyProjection to just not filter by that field. But this is not what happens: a condition gets added to the query anyway and it's of the form '[minimum DateTime value] < MyDate < [maximum DateTime value]'. This is not good because it will filter out fields with NULL values. If I try to do the same with a numeric field, it's even worse because it throws exceptions when the parameter is not present.
I know I can create a new query and projection to get different options, but that seems like an overkill - also, what if I wanted to create an advanced search form, it would have to target a single projection.
Is there an "official" way to do this? Or a workaround? Or is this simply not supported in Orchard?
I'm not aware of a way to do this out of the box. However, you could pretty easily create your own filter with the behavior you want by implementing IFilterProvider.
Take a look at the Orchard.Projections module. That's where you'll find many of the default query filters (including the date field filter you referenced). Your's will likely be even simpler if you only need to handle a specific case.
For a very simple example, checkout the Orchard.Tags module (look in the projections folder). The contents of this folder will give you pretty much all the boilerplate you'll need to get started creating your own. Just plug in your own logic.

Orchard - Query Custom Fields in Content Item

I have a Content Type "News" with custom field "NewsDate" (DateTimeField) and "Active" (BooleanField)
Now I'm need to get 3 active atimes order desc by NewsDate
Get all news, make them toList() and from there manipulate the data is not a solution.
P.S. I need to do something like:
var items = contentManager
.Query(Entities[PageType.Press])
.OrderByDescending<CommonPartRecord, DateTime?>(record => record.PublishedUtc)
.Slice(0, 3);
but instead of PublishedUTC use my custom field "NewsDate" and add Active == true, However it is not possible due to Orchard architecture of storing custom data in a separate field as XML data.
UPDATED:
In a nutshell I want to generate from code behind the following Query:
DECLARE #temp as TABLE(id int, xmldata xml)
INSERT #temp VALUES(1,'<Data><News><NewsDate>07/14/2011 11:42:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link></News></Data>')
INSERT #temp VALUES(2,'<Data><News><NewsDate>07/11/2011 12:11:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link></News></Data>')
INSERT #temp VALUES(3,'<Data><News><NewsDate>02/21/2012 16:56:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link><NewsLink></NewsLink></News></Data>')
SELECT
TOP 3 [id],
[xmldata].value('(Data/News/NewsDate)[1]', 'datetime') as NewsDate
FROM #temp
ORDER BY NewsDate DESC
P.S. I looked through the code for DynamicContentQueryTests, however all the examples uses the Part, and in my case Fields are just in the ContentItem:
E.g. News content type contains NewsDate field (datetime field) and some parts as well
Any suggestions are greatly appreciated.
Querying fields is possible since 1.4 through Projector and underlying index tables and new APIs on Content Manager. Your simplest bet actually may be to create a projection.
To get the values of fields that have been attached directly to a Content Item, you need to first look for the Content Part with the same name as the item, which is created by Orchard. So in your case in the Parts list for each News Content Item you'll find a part called "NewsPart", and inside this the Fields property will have your NewsDate and Active fields.
However, like you say Orchard serializes the field values into XML for storage to prevent it having to change the database structure every time you add/remove a field to/from a content type. For this reason, querying and ordering by fields is not recommended because all the serialized data needs to be de-serialized for each Content Item. If you want to be able to do this, the best way is to make your own Content Part with a Content Part Record and use your own table for storage, then you can do this:
contentManager.Query<NewsPart, NewsPartRecord>()...
...and query/sort on whatever values you like.
Bertrand is correct. Check this link : http://www.davidhayden.me/blog/projector-module-in-orchard-cms. You can implement your requirements easily with Projection Module. The link will tell you the steps to do that. If you don't want a widget, you can create a page with your query too. Once the module is enabled, you will see the option to create a Projection Page in the left hand side navigation.
EDIT :
Can't you simply parse the XML? You can query your content type 'News'. Something like -
var contentItems = contentManager.Query<ContentPart>("News").Join<TitlePartRecord>().Join<AutoroutePartRecord>().Join<CommonPartRecord>().List();
Once you have that, you can access the XML data by :
foreach (var item in contentItems)
{
var contentItem = (ContentItem)item.ContentItem;
ContentItemVersionRecord contentItemRecord = contentItem.VersionRecord;
string data = contentItemRecord.Data;
//Call some function here to parse 'data' and store the object in the list.
}
'data' has the information in XML format that you need.
You can parse it and then store the objects in your list that you can order by your custom field.

Default Sort of tr:table?

Is there a way to sort the initial data displayed on UI using tr:table? I know there are sort properties which can be defined on tr:column and which are used to sort the data present in the table.
But the requirement here is to have the data sorted by default when the page is opened. Is there a way to do that except sorting the table data from back end?
You can't sort a table by default, but you have to do it programmatically. With a little bit of work you can write a reusable PhaseListener which you can control from your JSF page.
Make sure it only handles a single phase (for example PhaseId.RESTORE_VIEW) and use it to set the sort order using setSortCriteria:
List<SortCriterion> sortCriteria = new ArrayList<SortCriterion>(1);
String property = "myProperty";
boolean ascending = true;
sortCriteria.add(new SortCriterion(property, ascending));
myCoreTable.setSortCriteria(sortCriteria);
Now you only have to add two <f:attribute/>s on your table to pass both the property name and the ascending boolean so you can create a reusable listener for all your tables.
In your <tr:document> you can have a <f:attribute/> with a list of table ID's to process.
as far as I know: No!
You can read from here for more information:
"TRINIDAD-1491"

Synchronous paging against Azure Table Storage

I am new to working with Azure table Storage but I have being able to put together the code below that successfully allows my query to accept filterQuery (string) specified by the user -- for ex: (Amount le 5000.00) -- and to retrieve all rows (entities) matching the criteria.
Dim sBuilder As New System.Text.StringBuilder
Dim query = MyBase.CreateQuery(Of cData)("CustomerData")
Dim userQuery = String.Format("(PartitionKey eq '{0}' and {1})", AppID, filterQuery)
sBuilder.AppendFormat(userQuery)
query = query.AddQueryOption("$filter", sBuilder.ToString).AsTableServiceQuery().Take(50)
Dim results As List(Of cData) = query.Execute.ToList
I should point out that this way of allowing the user to specify the filter string is key for me since I am using a generic class that has a dictionary inside of it in order to allow my caller to pass in any number of elements to store into a given entity. Therefore, this solution allows the user to drive how he wants his query to search by and my code does not have to 'know' anything about his custom fields.
Now I need to add pagination. My understanding is that the 'Execute' method I am using handles the pagination for you so if there are 7,000 records matching the criteria, my code will sit until all the entries are retrieved/returned. However, I want to instead allow my user to specify how many entities he wants returned at a time (max results) and allow him to then make subsequent calls using continuation tokens to get the next 'batch' of matching entities.
Any thoughts on how I can achieve this without losing my ability to allow the user to specify his search criteria in a simple string?
I think you can just do query.EndExecuteSegmented(query.BeginExecuteSegmented(...))
Check out the code for SmarxToDo: http://blog.smarx.com/posts/todo-list-app-using-asp-net-mvc-and-windows-azure-tables
You may want to implement your query using REST API (http://msdn.microsoft.com/en-us/library/dd179421.aspx). You will get XML response back from storage service which you can parse to create the collection of objects.

ExecuteJoinedDataSet but with Where()

I did some searching and see that ExecuteJoinedDataSet will not work with the Where clause in 2.1. If I want to query a table with WHERE, but want the FK objects values to be bindable is the easiest way to just create a custom class(my table has tons of FK references).
Could you give us an example of what kind of query you are trying to write? If you are just trying to return a DataTable without creating a custom class just write your query and use the ExecuteReader which Returns an IDataReader. The IDataReader is bindable and if you need more you can just load it into a DataTable.

Resources