I have some indexes in portal_catalog, for various types.
Given a portal_type and a fieldname, how can I find out the name of the index (if any) for that field?
Some relevant pointers to documentation about zcatalog might help me too!
Thanks..
There is no easy one-on-one way to determine this. In Plone 4, there are basically three different ways that an index in the catalog can obtain the information from your content type.
Index configuration
First and foremost, indexes can optionally be configured with the name(s) of the attributes or methods to index on a given object. Indexes generally have a getIndexSourceNames method that'll tell you what items they'll index.
Usually this is the same as the index id, but this is not a given. Generally, if your field accessor is listed in the result of getIndexSourceNames then that index will be indexing that field for a given type:
from Products.CMFCore.utils import getToolByName
catalog = getToolByName(context, 'portal_catalog')
for index in catalog.index_objects():
if field.accessor in index.getIndexSourceNames():
print 'Index %s indexes %s' % (index.getId(), field.getName()'
In the above examples, I assumed you already have a hold of your field object in the variable field, with an actual instance of your type in the variable context.
Custom indexing adapters
When an object is indexed, the catalog also constructs a wrapper around the object and will look up indexing adapters for your object. These adapters are registered both for the indexed name (so the name listed in getIndexSourceNames) and an interface or class. If your content class implements that interface or has an indexing adapter directly registered for it's class or a base class, the indexing adapter can be brought into play.
Indexing adapters are arbitrary snippets of code, and thus could call any field on your content object to produce their results. There is no programmatic way for you to determine if a given field on your content type will be used, or if any fields will be used at all.
The CMFPlone.CatalogTool module lists several examples of indexing adapters, these are all registered for Interface, meaning all objects:
allowedRolesAndUsers collects security information about your object.
getObjPositionInParent determines the position of the current object in it's container. Thus, this indexer does not need any information from the object itself to determine it's value.
sortable_title takes your content Title value and generates a value suitable for sorting catalog search results with. It normalizes the value, lowercases it, and prefixes numbers with leading zeros to make sorting on numbered titles easier.
Direct method access
Fields are basically generated methods on your content object. But your content class can also implement methods on it's class. The same remarks as for custom indexing adapters apply here; these are arbitrary Python code so they could be using your content type fields, aggregating and mangling the information before passing it to the index.
The Archetypes BaseObject class (used in all Archetypes content types) defines the SearchableText method for example. This method takes all available fields with the searchable property set to True, tries to get each field value as plain text, and aggregates the results for the SearchableText index.
Conclusion
You can only make educated guesses about index contents as they relate to your fields. By introspecting index configuration, you won't see if there might be a custom indexer adapter masking your field (register a getField index adapter and it'll be used instead of directly calling getField). Custom indexers and class methods can still access your fields and pass on the information to a catalog index.
You just add an index for the method or attribute name that you want to use for the index value--there's nothing too tricky about it and it can potentially all be done TTW
If you need a bit more logic to grab the index, check out this stackoverflow question: Problem with plone.indexer and Dexterity
Related
I have EntityField and UsersField(ListBox). When I change Entity to USERS, I need to pass: UsersLookupCall, when I change Entity to Projects, i need to pass ProjectUsersLookupCall to UsersField.
Also if that is possible, how to pass a parameter to that lookup call I am passing to another field?
Thanks
You can exchange the lookup-call on a (Smart-)Field simply by calling the setLookupCall(ILookupCall<T>) method on the field. However, since the value of the field is strongly typed and the type of the lookup must match the type of the field you can only set lookup calls with the same type.
You find a lot of examples on how to react on value changes in the Scout Beginners Guide.
You can set additional parameters on the lookup call by implementing the execPrepareLookup(ILookupCall<T>) method. Note: there are also specialized execPrepare* methods for the three lookup modes: key, text and rec.
When it comes to creating/updating custom objects, can I use both dedupeFields or lookupField when pushing the data to Marketo?
What is the difference between the two?
I'm not sure what do you mean under lookupField, as there is no such input field described in the API documentation of the Sync Custom Objects endpoint. (That is the endpoint to create or update custom objects.)
In the other hand, you do not need such a standalone lookup field, as with the input array you provide the objects you want to create or update, with all their important values. Have a look at the sample payload in the docs.
When input is used together with the optional dedupeBy and action fields, you have full control over which object you want to create or update.
Also, the endpoint expects the name of the dedupe field under dedupeBy key, as opposed to dedupeFields. So the name is singular; you can provide a single field name use, and it does what you can expect: if the value in the field for a given record is not unique, an error will be returned for the individual record.
I created a custom object and i want to get all its existing records. Is there a way of doing that via the REST API? Seems like a very basic and simple operation but i couldn't find information about it anywhere.
As you say, it seems like a basic task, but in the reality, it is more complex indeed.
Unfortunately, the Get Custom Object endpoint (which is the only endpoint to fetch Custom Objects) requires the filterType and filterValues parameters to be present as well. Basically this means that you have to have some information about the queried objects beforehand.
Also, a further restriction is that the value of filterType can only be one of the “searchable” fields of the Custom Object, meaning that it has to be either a Link field or a Dedupe field. (These fields are listed under the searchableFields property in the response from the Describe Custom Objects endpoint.)
So as mentioned above, you have to know the values for at least one of the properties of your Custom Objects before you make the query.
With additional queries though, you can grab these required values.
Let's say, you have your Custom Object linked to the Lead Object, and the Link field is called Owner Email (with the REST API name being ownerEmail) which links to the Email Address field of the Lead Object. In this case you could set the filterType to ownerEmail and set the emails of the leads as filterValues.
Then it is up to you how you gather the emails of those Leads who has a Custom Object attached. Luckily the REST API won’t throw an error if you provide a value that has no corresponding Custom Objects.
If your Custom Object is linked to a Lead, it's a bit complex but you can do like this:
Create a smart list and filter with "Has You Custom Object"
Get the smart list with API (GET /rest/asset/v1/smartLists.json)
Based on this list of Leads, get all Custom Objects (see the other answer).
I have a content app with a dominating unique field that I would like to use as the node name for new nodes. The problem is that it contains characters that cannot be part of a JCR node name, and thus if I were to link it to jcrName rather than a custom property it will get mutated into something that isn't useful for the fields original purpose (among others, the field value will contain slashes).
My current solution adds an additional field for the node name, and while this certainly works, it adds a UI field to the detail for no reason that is apparent to the users of the app.
Is there a way to have a field that reads and writes a string value to a custom property, yet that is also used (in its clened form) to name the node?
You could use this as a base, paying special attention to the code in 2.b.ii. (especially setNodeName), and ignoring the yaml bits.
I hope this helps!
I need to create a fairly complex rule in Drupal - I am willing to use either code or the interface to do so.
I am more familiar with the interface, however, as opposed to the Rules API.
Anyway, the rule will be as follows:
It will happen based on a form submission from entityforms (which is one entity). It will take the checkbox value of a field (not just the true or false, but rather the value submitted when a value is true or false). It will convert this number to an integer.
At this point things get interesting - I want to create a new entity of registrations (a different entity), which as far as I can tell, means I'll have to bring a registration into scope. I also need to bring node (and not just node: type and other data selectors, but specifically node) into scope, because the next step requires it.
So at this point, I should have three entities loaded into scope:
entityforms
registration
node
I believe the best way to bring registration into scope would be entity is of type? The documentation page says that content of type should be appropriate - but that seems like it might be related to the specific use case of the example - not in my more complex example where registration isn't the first entity dealt with, but rather a second.
https://drupal.org/node/1463042
So anyway, if all three of these entities is called in correctly, the ultimate result should be the following:
Value from boolean field (not the straight 1 or 0, but whatever the value to be submitted is switched to) from the entityform is converted to an integer, and inserted where entity host ID is required. In the section where host entity type is the value should be node.
I am also open to alternative suggestions if this seems overly complex or poorly architected.
The Host Entity Type cannot be of Entityform? Why be a Node since a Registration can be attached to any entity? Then you will get the id of the Entityform as also as any other fields from that entity type instead of Node. Next steps are the same.