Sulu CMS: how to search/filter for content of a specific type with specific values for specifc attributes? - sulu

Short description of the situation:
We're running a forked version of Sulu 1.5.2, PHP 7.1, Windows server environment, db connection with PostgreSQL
We have a website structure/tree where we have house templates at the top level; each house has one house_rooms and one house_occupants template; each house_rooms template has N house_rooms_room templates, and each house_occupants template has N house_occupants_occupant templates. This represents an actual House that has N Rooms and N Occupants.
Now I'd like to know if there is a way to specifically get, for instance, all the house_occupants_occupant content that follows a certain pattern of attributes (for instance: their gender attribute having value 'female' and their date_of_birth parameter being >= 1990/01/01), without having to load each house, then find its house_occupantspage among the children, and then loop over that template's house_occupants_occupant children and filter the thus begotten content according to their gender and date of birth attributes.
I already found that there is a ContentRepository class that can ::findAll() and ::findByUuids(), but there doesn't seem to be a way to filter on specific attributes (like template type, template attributes, ...). So I took a roundabout way of creating my own "repository" that does direct PDO queries on the phpcr_nodes table in the database, to specifically scan the props attribute for the occurence of a certain template name:
$this->pdo->query("SELECT identifier, props FROM phpcr_nodes WHERE props LIKE '%>house_occupants_occupant<%'");
I can see that the propscontains a string value representing an XML document that somehow translates into the entire template with attribute-value pairs, however it is obscured regarding tag-levels and how certain attributes relate to certain values. So in theory I could use a specific XML parser to turn this into something human-readable, so that for my house_occupants_occupant data I could get something like:
// what I would get after putting the props through a certain XML parser:
$xmlHumanReadableData = [
'<the_uuid_of_occupant_1>' => [
...
'gender' => 'female',
'date_of_birth' => '1992-05-18T00:00:00.000+00:00',
...
],
... //etcetera etcetera
];
When I would have that, I could filter the readable data to ascertain which content I want to keep, add the node-uuid to some $theUuids variable, and then retrieve the actual content using Sulu's ContentRepository::findByUuids($theUuids) method. That would "only" require 2 queries and some PHP array filtering in between, which is a great deal better than looping over all the children content starting from a certain parent and doing this until you've traversed all the parents and all their children... (Certainly, the overhead would increase if you'd want to search for, for instance, all house nodes where at least one of its house_occupants_occupant nodes represents a child less than 10 years old, since you'd need extra queries to "set up" the filterdata used in the final query. But still: a great deal better than looping everything... ;-) )
So my question is sort-of twofold:
What is the Sulu-specific XML parser I can use to turn the XML string value in this props column into something human-readable, with proper attribute-value pairs?
And/or, hopefully: is there a way I can avoid all this nonsense and just use a less low-level way of retrieving content of a specific template type with specific values for specific attributes ?

The ContentRepository you've found is already an abstraction to some of our requirements for pages. Your requirements are already quite specific, so you should write your own query using SQL-2, the query language for PHPCR.
This should enable you to write a query which matches your requirements.

Related

ABAP Domain and Data Types Understanding

so my company wants me to learn ABAP for SAP and I have started on the road to learn this. My background is mainly VB.net and sqlserver with T-SQL but also have experience in c#.
With ABAP though I am needing some clarification or confirmation on the understanding of Data Types and Domain. If anyone can help.
My understanding currently is we have a table, in the table we have fields and the fields have data types and lengths if needed. Example: We have a table Customer, I could have a customerNumber field with the data type of char(10). To me this mean in the table customer we have a field called CustomerNumber that will have 10 characters.
However with ABAP we have Domains, Data elements then the field, does this mean we have a field named whatever we want. As the field could mean anything we assign a data element which has the descriptions of the sort of data stored within the field. However to store the format and data type we need to assign the Domain to the Data element.
For example I call a field ZCUSNO, currently this means nothing however if I assign the ZCTNMR (with description of customer number) Data element this tells us that the field ZCUSNO is ZCTNMR so ZCUSNO is a customer number field.
Now within the data elements we would have a domain and for our example ZCTNMR data element (the customer number) we could assign ZCTDOM as the domain which would be what I recognise as the data types so Char 20, Char 100 or integer field etc.
Is my understanding correct on this? and could someone give me a clear indication of what the difference between a Domain > Data Element is against what I would know as data types in sqlserver.
Thanks
I don't know if it's 100% correct, but that's is the way I use, like you say.
You can reuse the Domain, If you don't plan to reuse you can use direct the Data Element and refer this to a built-in-type.
Data Element is to define semantic of the field, like label, translation, etc
Domain is to define techinical info of the field, like Type, conversions, predefined Values,e tc
E.G.
Domain:
DOM_VALUE you define it's 10 position and 2 Decimals
Data Element:
UNIT_VAL you refer it to DOM_VALUE and define label as "Unit Value"
TOTAL_VAL you refer it to DOM_VALUE and define label as "Total Value"
Your understanding is pretty correct and not much can be added here.
You should clearly get the main thing.
Domains store technical data (decimal points, length, type, predefined values and so on)
Data elements store semantic data (labels, texts, search help binding, etc.)
Not every table field has data element (they can possess builtin type) but every field has type (either primitive or wrapped in data element).
If you wanna use your field in screens (Dynpros), ALV grids or other reports, then create data elements that will bear business meaning of your field.
If you use this field just for calculations or other utility internal tasks, then don't bother yourself.
As usual table date field (type of variable) uses data element which uses domain.
When you create fields in table and use predefined types instead of data elements you will have some problems in future, when you'll need to see the data on alv_grid.
Actually, you will see that you have some problems even before this (when you will try to make a maintenance view the header will have something like "+" symbol).
And of course we usually try to create 1 domain for 2 and more Data Elements.
In domain you talk about main logic.
In Data Element I always talk about Field label settings (how it'll show in future and some other things)
Final: Actually, the good practice, as I think to create a domain for data element, it may help you in future.
I hope that it helps you. Good luck!

n-n relationships for multiple content types

I'm working on a project based on Laravel 5.3 and Backpack CRUD. My project has about 8 different content types (news, page, portfolio, events, team, video, gallery, jobs).
I need to be able to add tags to every content type (n-n), and every content type has its own specific tags, so tags are NOT shared between the content types.
If I want to use the select_multiple or select2_multiple field type, I would need 8 tables for the content itself, 8 pivot tables, and 8 tables for the tags(!).
Obviously I would like to have just one table for the tags, but if I use the select_multiple or select2_multiple field type, I get all tags in the edit-form of every content type.
So, my question is: Is there an elegant way to filter the results of the select_multiple or select2_multiple field type?
I have created a simple schema with two content types:
http://dbdesigner.net/designer/schema/60412
In this example I want to be able to filter the tag list on content_type_id, when I'm editing the content of news or page. So I just want to see the news tags in the news-edit form, and just the page tags, in the page-edit form.
Or maybe I should just use the select_multiple field type as intended, and accept the 8 tag tables(?)
Any help or advice would be greatly appreciated.
I think a clean way would be to:
create different models for each tag use, so NewsTag, PageTag, PortfolioTag etc. that would only extend the Tag model and use a global scope to filter the results after content_type_id;
use backpack select2_multiple fields with NewsTag, PageTag, PortfolioTag etc; anything you set on the Tag model will be used (including the table attribute, mutators, accessors, etc);
Cheers!

elasticsearch array field of keywords - how to index it

I've got input that is analogous to tags, where there are a couple of strings per record, and they should be thought of as keywords, not to be tokenized or broken up or analyzed in any particular way. I want it to show up in faceting "as-is", including spaces, slashes, dashes and ampersands.
I don't think I need multi_field here. There is one input value per record "keyPhrases" but the input value is a simple json array of strings.
I want elasticsearch to insert into the facets each of the values, and tag the record with all of the phrases.
Usually there are only one or two or three phrases per record, but there could be more. The set of keyPhrases is fairly small, like 30 or at most like 50. They could be thought of as "categories".
The faceting keeps breaking up the input strings and using lowercasing, even though I'm trying to specify not_analyzed, keyword tokenizer, keyword analyzer, and trying things like that.
I have other fields that keep their spacing and capitalization as I desire in the facets returned, however those fields are not_analyzed and are also store: true, but are also just exactly 1 string input per record, as opposed to many per record.
I could just take the top 1 keyPhrase per record and flatten it, but ideally all the tags would work and be available as facets.
Any ideas on how to do this?
Well, this is embarrassing.
My strict mapping wasn't actually committed to the server at the time I was trying this.
(I was dropping the index and creating the index again with each new mapping, and hadn't realized it, and this was not the final mapping, so it was getting loaded and then dropped.)

Drupal 7: Sorting multiple content types in Views, with different date fields

I'm using Drupal 7, with the Views, Feeds and Views PHP modules (among others, but I think those are the only relevant ones).
My goal is a single view that combines (a) multiple RSS feeds brought in through the Feeds module, (b) two or three content types of my own, for contant created manually on my site. The result will be a block and a page that has a stream of all my latest work, wherever it is -- my own site or another site (as long as that other site has an RSS feed, of course).
The ideal result would show a single list, sorted by date, mingling the items without regard for content type.
My problem: The Feeds module and my custom content types have different date fields. My content types have a field called Original Date, which I set when I create content (eg, adding an article I wrote three years ago -- I clearly want it to be sorted by when it was published, not when I added it to the site). However, each feed_item has a date field, Published Date, that corresponds to the date in the RSS feed and is received with the rest of the item by RSS.
I have tried to use the Views PHP functionality to use if/then statements, in a variety of ways. For example, I check what the content_type is, and then set a variable to either the Original Date or by the Published Date, depending on the content type. Alternatively, I have tested whether the Original Date field is set; if so, I return that field, otherwise I return the Published Date field. They all fail in various ways. Most throw PHP errors that are visible even to anonymous users (obviously a problem).
I have tried these various approaches directly in the Sort Criterial section of Views; I've also tried to come up with the date in the Fields section, and then have a Sort criterion call that result. I've converted everything to a Unix timestamp, to make sure I have something simple to sort by; I've tried leaving dates as dates. No luck any which way.
Here's the really weird part: I have successfully used these approaches to display the correct date, so that (for example) the block shows • TITLE | Original Date for custom content types, and • TITLE | Published Date for feed items. But when I try the same approach(es) to sort by date, it fails.
Am I overlooking something simpler? Do I have to use PHP Views? Is there some other way to sort a View of multiple content types by a combination of two different (though similar) fields?
Thanks!
tf
Have you tried using the relationship feature of views? You could use that to get access to all of the date fields of all of the content types, then add some conditional code to the field item and you should be golden. (That is, if I'm understanding the question correctly...)
I found many possible solutions and summarized them here: https://drupal.org/node/2133879
However, this is a simple solution that I'd recommend:
In a custom module use the hook_views_query_alter() function to alter the sort criteria to use CASE ... WHEN to add a conditional in the orderby condition. A good example is shown here:
<?php
/**
* Implements hook_views_query_alter
* #param type $view
* #param type $query
*/
function MODULE_views_query_alter(&$view, &$query) {
if ($view->name == 'views_name' && $view->current_display == 'display_name') {
$query->orderby = array(
array(
'field' => 'CASE WHEN field_data_field_date_publication.field_date_publication_value
THEN field_data_field_date_publication.field_date_publication_value
ELSE node.created END',
'direction' => 'DESC',
)
);
}
}
?>

Best way to give options for starts with or contains in REST query

I have a REST service that allows people to put in a course title as part of the query to get scores, but, sometimes they may want to get a group, such as Calculus% for Calc 1, 2 and 3.
But, what is the best way to give them an option that makes sense?
For example, I have http://localhost/myrest/any/any/Calculus III
where the first two parameters are student id and some grade category.
I don't think having http://localhost/myrest/any/any/contains/Calculus III is a good use as then I will need to force them to use equals if that is what they are looking for.
Another option is http://localhost/myrest/any/any/Calculus% or http://localhost/myrest/any/any/%Calc% is another option, but then you have removed the option to easily use % as an allowed character.
So, to give additional filtering options in a REST URL, what is the best (defined as simplest/most intuitive for the user) way to allow contains or starts with.
In your system, would the following query list all subjects in the grade category?
http://localhost/myrest/any/any/
If yes, then one option you can consider is extracting the non-exact subject name into a GET parameter. Thus without breaking the current logic where having a full name of the subject in the URL provides the score for that subject, you'd also have the ability to filter the list of subjects within the same grade category by means of the GET parameter.
For example:
http://localhost/myrest/any/any/?search=Calculus*
... could provide a result like this:
<subjects>
<subject uri="/myrest/any/any/Calculus%20I">A</subject>
<subject uri="/myrest/any/any/Calculus%20II">B</subject>
<subject uri="/myrest/any/any/Calculus%20III">C</subject>
</subjects>