In Plone adding a member variable in a view class instance automatically makes it a part of view acquisition chain. The problem is described in detail here:
http://collective-docs.readthedocs.org/en/latest/views/browserviews.html#views-and-automatic-member-variable-acquisition-wrapping
What is the suggested approach for dealing with this problem
Can we have Plone main template based views without implicit acquisition
How about viewlets and portlet renderers then?
If not... how one should deal with the problem so that self.xxx variables do not get extra acquisition wrapping?
Use Acquisition.aq_inner() to strip away the extra wrapping and restore the object to it's original path. Please, do not use the single-item list approach as described in the document you link to.
To show one example from the linked document, but corrected with aq_inner():
from Acquisition import aq_inner
self.obj = self.context.reference_catalog.lookupObject(value)
return aq_inner(self.obj).absolute_url() # Acquistion chain corrected
Alternatively, you can use the aq_inner attribute:
self.obj = self.context.reference_catalog.lookupObject(value)
return self.obj.aq_inner.absolute_url() # Acquistion chain corrected
but that only works on objects that inherit from Acquisition.Explicit or Acquisition.Implicit; the aq_inner() function returns the passed argument verbatim if it is not a Acquisition-wrapped object.
Related
I have a React + Flux application that uses multiple tab-pages of data. Each tab-page displays the same kind of data (e.g. an invoice), but from another object. Based on other posts I read on this subject, I decided to create a collection in the 'InvoiceStore' that contains an 'Invoice' object for every tab page that displays an invoice.
On every tab (in the details of the invoice), there are multiple widget-like components. These components are nested in multiple layers.
The challenge is that every component should know for which invoice object the data must be displayed. I know that I can arrange that by passing data (actual data or the 'key' of the item in the invoices collection) from the top component of an invoice (tab) to each of its descendants, but that would imply that the components in the middle would need to pass the received properties to its children. This seems like overkill to me.
Is it possible to have some kind of variable that has a scope of one component and its descendants? Or is there another sort of 'standardized' solution for this challenge?
Suggestions are really appreciated!
You can pass through props with JSX spread attributes: {...this.props}, which are based on the ES7 spread operator proposal.
This destructures all the props you received in the parent and passes them to the child. Occasionally, you don't want to pass all the props, and then you need to comb out (or add in) the props you want to pass explicitly. For that, it may be useful to use the new destructuring syntax available in ES6.
Example:
<MyChildComponent
foo={bar}
baz={qux}
{...this.props}
/>
There is also an undocumented, hacky technique using this.context, but that API is unstable and is likely to change. The spread operator is currently the technique recommended by the React team.
There is no "scope" concept in React, since React way prefers composition design pattern. The child component has to be as self-complete as possible, which should not know anything about the parent component except for the required props. Thus the object is required for each child component.
An alternative is to provide a public method getItem(itemId) in the InvoiceStore. But still one would have to pass the invoiceId by props.
I have a Dexterity content type based on plone.directives.form.Schema which has a number of form hints for assigning defaults:
#form.default_value(field=ITrial['start_on'])
def default_start_on(data):
return datetime.now()
Some of the defaults are more complex, passing back objects that are themselves instances of Dexterity types. These objects are essential for the main type's setup, which is triggered by various events.
I'm now in the process of testing. Ideally, I'd like to be able to use something like:
item = createContentInContainer(folder, 'ctcc.model.trial', 'item')
That is, I'd like the defaults to be picked up by the item without having to be manually passed into the constructor.
If I was using zope.schema I could use FieldProperty to set up proxies to the schema fields. Is there something equivalent for Dexterity, or perhaps a function for pushing an object through form creation?
Solution: I ended up going with David's option #1, intercepting ObjectCreatedEvent.
#grok.subscribe(ITrial, IObjectCreatedEvent)
def create_trial(trial, event):
if getattr(trial, 'start_on', None) is None:
trial.start_on = default_start_on(None)
It stills feels like I'm replicating part of form behaviour, but at least it's using the same functions that are providing the form defaults.
As you've discovered, the #form.default_value decorator is respected by z3c.form forms, but not when items are created in other ways. You have several options:
Write a handler for the ObjectCreatedEvent for your content type which sets up the necessary default values. This is the simplest approach to implement, but may not work if there are other handlers of this event that need the values in place.
Create your own subclass of Dexterity's generic Item class, and use it instead of Item as the basis for your content type. Then you can customize the __init__ method to set whatever you want. This would require migration of existing content items though, if you already have some.
This is a more complicated option. Replace the factory utility used to construct the content type. createContentInContainer ends up looking for an IFactory utility with a name equal to the factory attribute of the content type's FTI. The default implementation is in plone.dexterity.factory but you could replace it with a different one that does more.
Does anybody know if it is possible in a compound template to use a string item in the package and execute it as if were a dreamweaver template? And whether you apply the same method to other mediators (like razor)?
Thanks
Mark
I suspect this is not possible.
Package.EvaluateExpression may be useful, but as the name suggests it'll only work on expressions, not large snippets of code with embedded expressions (i.e. TEL)
Engine.GetMediator expects a Template and returns the appropriate Mediator for it. Your problem then is that the IMediator interface only defines the Transform method, which requires an Engine, a Template and a Package.
I can't think of any elegant ways around these. Maybe write your own Mediator, but that would still expect a Package, not a string, so you'd have to first store the string based Item from another TBB.
My advice: Sounds like you need to go back to the drawing board and find an alternative solution to your problem.
I'm afraid that won't be possible on just any item in the Package, since the Engine expects Templates to be based on Tridion items.
If your Template Item is based on a Tridion Item you can probably get pretty far by starting at the Engine.GetMediator method. If it isn't, you'll have to find some way to turn it into a valid Template object.
Template template = ...
IMediator mediator = engine.GetMediator(template);
mediator.Transform(engine, template, package);
When I have to create a Component object from a Tridion-based Item in the Package, I normally do something like this:
Component component = new Component(item.GetAsXmlDocument().DocumentElement,
engine.GetSession);
I haven't tried, but expect that you can do the same for a Template - given that you start with a valid Item from the Package representing a Template to begin with. You can probably clone the XML from an existing Item or find some other way to fake it.
If you get this to work, it will work across all registered template types. The Engine provides no special treatment for the types that come with Tridion.
I am creating some Magnolia templates and would like to know if any one has found a way to create a #cms.newBar and somehow use a node as the list of available paragraphs. The syntax is as below:
[#cms.newBar newLabel="Add Content" paragraph="template1, template2" /]
I want to use the node instead to avoid having to come back and add new templates when they are created.
I have seen the docs here and know that nothing is specified but wanted to see if anyone had found a way?
You can do several things, all boiling down to the same:
configure a string property containing "template1, template2", in your template definition. Assuming you're using Freemarker as the templating language, refer to it with ${def.thatProperty} (def references your template definition)
have your model class return that value: ${model.whatsCooking}, where your model class has a method String getWhatsCooking() which returns "template1, template2" (or whatever else you could come up with that decides what paragraphs should be available
STK does something similar to (1) - its template definitions contains Lists of "available" paragraphs, and its templates use some utility method to turn that into a comma-separated list, use with the new bar, so something like ${stk.toStringList(def.main.paragraphs)} (I can't recall the exact names and semantics, but you get the gist).
You should perhaps consider looking into STK for that, and a whole lot of things.
As for documentation, perhaps the templating guide and other docs will be more useful than the javadoc/tlddoc in this case.
HTH,
I would like to use collective.easytemplate to generate templated emails (for content rules). However, I am not sure if it can output an objects workflow state. Anybody know if it is possible and how it is done?
Thanks.
You can, it is possible, and one way is to use the portal_workflow tool e.g. from parts/omelette/plone/app/contentrules/tests/test_action_workflow.py:
self.assertEquals('published',
self.portal.portal_workflow.getInfoFor(self.folder.d1, 'review_state'))
More generally, something like:
context.portal_workflow.getInfoFor(context, 'review_state')
in a page template should work. Or use the portal_catalog as Spanky suggests e.g. if "obj" is a catalog "brain" (i.e. part of a result set from a catalog search) then:
obj.review_state
should work.
The portal_catalog also has an index of the workflow's Review State, so if you don't already have the object you're working on (e.g. context ≠ the object) you could use the catalog, look up the object and get the review state from the resulting "brains" object.
Apparently there are ALSO browser view methods available to you as well, and I notice that one of them is workflow_state. See:
http://plone.org/documentation/manual/theme-reference/page/otherinfo