Add a collection to another collection - collections

I need to add to the collection "compagni_palestra" which is in the folder "palestra" the members of the collection "compagni" which is in the folder "classe" in order to keep the group "compagni" and put it into the extended group "compagni_palestra".
Here below the code that doesn't run.
//check in
palestra.compagni_palestra.addAll(classe.compagni) ;
The error showed by AnyLogic is the following:
The method addAll(Collection<? extends Classe>) in the type ArrayList<Classe> is not applicable for the arguments (ArrayList<Studente>). Location: Mod_03/Studente/Palestra1 - State

It appears from the error that each collection is for a different object type, one contains Classe type, the other contains Studente type.
If you want to store elements of any Java class, make sure the element class selected is Object.

Related

Symfony Workflow - Is it possible to use doctrine relation as state holder?

I am trying to adopt the Symfony workflow component to my app.
As documentation says marking_store points to string. I was googling for it - it can be a string or json_array-field of a Doctrine entity.
But what if I have an Entity BlogPost with a relation BlogPostStatus that have two fields: some primary id and statusName. Can I configure the workflow component to change statuses of my BlogPost (i.e set new BlogPostStatus to BlogPost entity) and persist it to database?
Now I have only one solution: Add to my BlogPost entity non-mapped field and when it's changed change status of Entity.
Do you have a better solution?
For all built-in marking_store implementations the following is true:
If the functions setMarking or getMarking exist on the object holding the state, they will be used to set or get the marking respectively.
There are 3 built-in marking stores, the SingleStateMarkingStore (using the property accessor, hence setMarking/getMarking), the MultiStateMarkingStore (same), the MethodMarkingStore (explicitly calling those functions, you can change the function via the property setting of your marking_store config).
The difference lies within the argument provided in the setMarking call, for single state (this is the state_machine type, and by default NOT the the workflow type), the argument is the place (or state) where the mark is placed. For multi state (workflow type by default), the argument is an array where the keys are places and the values are marks, usually the marks are 1, and empty places are omitted.
So, I'll assume that your BlogPost (currently) only has a single state at any given time, and what you have to do now is to transform the marking given into the status entity - I will assume your workflow has type state_machine:
/** in class BlogPost */
public function setMarking(string $marking/*, array $context*/) {
$this->status->statusName = $marking;
}
public function getMarking() {
return $this->status->statusName;
}
special cases
If the BlogPostStatus should be a different one (for example, a constant object), then you'd have to use the new interface that dbrumann linked, and hook into the event to add that to the context.
If the BlogPostStatus may not exist at the time of the setMarking/getMarking, you have to create it on the fly in the setter and check for it in the getter. But I'm sure you're capable of doing that ;o)
Also if you're not using the single state workflows but multi state instead, you have to find a way to transform the array of (places->marks) into your status object and vice versa.

Asp.NET MVC Model Binding Not Picking Up A Value for List Item

I've got an object with a list defined inside it which points to a type that can be inherited. From what I understand MVC's default model binder will always instance the base type when reading data back in to this array from a form so by default I will have a list of base types.
So I need to use my own model binder and override CreateModel to instance a specific type (say from a hidden field). However when I do this and use
bindingContext.ValueProvider.GetValue("ModelType")
it always returns null even though through using fiddler I can see that form value Settings[0].ModelType contains my objects type and I need this value in CreateModel to instance the correct type.
Solved it. If your array objects need to be typed based on each item you need to use the following call to get "into" the array item
bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType")
I'm not sure if this is the standard way to do it. If anyone has any better suggestions feel free to add them

Dynamically chose type depending on JSON content

In an ASP.NET MVC 4 application I get a JSON response from an external server that contains an array of "fields". Each field is of an individual type and contains an array of values of that type.
I'd like to deserialize that JSON either into a DynamicObject so that I can access the indivudual value propreties or I need some kind of a child class chooser which decides which class, derived from a "ValueBase" class, is needed to access the different properties of the individual value object.
I hope you know what I mean... it's a little bit complicating.
I've already tried to deserialize it into a DynamicObject (a class that derives from DynamicObject that is). But I get error messages when accessing that object's dynamic properties in the View that the properties I'd like to display don't exist.
So how does a class that derives from DynamicObject have to look like to accept and grant access to the individual differen "value"-properties provided by the JSON code?
And if that wasn't possible or the wrong way to go, how would I have to implement a suitable type chooser class?
Thanks a lot!
I've kinda solved it myself.
Instead of directly converting the returned JSON object (a JSON array to be more precise) into a specific class I fetch it as a dynamic and give it into the constructor of a class that contains a collection of instances of another class the object actually ought to be of (I get a JSON array returned from the webservice anyway). In the constructor of the collection class I decide depending on a value of the JSON object of which inherited class the new object is gonna be and put that into the collection. Yeah, I walked that way afoot somehow but it works.
Looks like this:
public CollectionClass(dynamic dyn)
{
foreach(var item in dyn.items) {
switch((string)item.external_id) { // might have used a Dictionary instead but...
case "member":
this._collection.Add(new Member(item));
break;
case "date":
this._collection.Add(new Date(item));
break;
default: break;
}
}
}
The Member-class itself contains a similar constructor which also requires a dynamic parameter. And it also "builds itself up" depending on values inside the item.
If there's any easier way or a "royal road" of achieving this I'd be grateful for any further advice.

Index Specific Type without Its Contained Types

I add a FieldIndex for my content type according to the Plone.org instructions.
In the ZMI, I can see the indexed items at /mysite/portal_catalog/Indexes/Building. My content type (providing IMyType, with one field building) is folderish and contains a Photo (providing IPhoto, without building field) as allowed_content_types in profiles/default/types/MyType.xml file.
I want indexing only for MyType's building field. However, it seems items of Photo type get indexed with the value from their parents. That's annoying. Does the code #indexer(IMyType) mean indexing for IMyType and its contained types? How can I index only for IMyType?
What an indexer does is to get the attribute directly from the object being indexed. In Plone that is as special wrapper, one that will use registered indexers (as created with the #indexer decorator) if they exist.
However, if you index happens to index building and that is also an attribute on your IMyType objects directly, any contained objects will have that attribute through acquisition as well. Registering an indexer for IMyType does not prevent this.
There are a few ways around this:
Use a different name for your indexer, one that doesn't match the attribute name. Note that if all you do is index an attribute the indexer is redundant though, the index could just as well retrieve the attribute directly.
Register a "catch all" indexer:
from zope.interface import Interface
#indexer(Interface)
def catchall_ignore(ob, **kw):
# Raising AttributeError means: do not index anything
raise AttributeError
Instead of direct attribute access, now this indexer method will be used instead for Photos, causing the indexer to not register a value for building.
This is how acquisition works.
here how to workaround this:
http://plone.293351.n2.nabble.com/how-to-prevent-portal-catalog-from-indexing-acquisition-values-td2650735.html
"use a custom indexer that does the aq_explicit check."

Making sure my extended lists always show "current" data?

When you create a Data Extender for a CME list – for instance to add a column for the Schema as in this example – it all works fine and dandy whenever you do actions that force a List reload.
However, some actions don’t force a list reload (like editing a component in a folder, then saving & closing) and it looks like Anguilla is loading the data for the item that changed using a different mechanism that loads only the data for the item in question (which makes sense).
If I would want my extended list view to behave properly and also load my additional attributes whenever a given item changes (instead of only when the list view is reloaded) what else do I need to do?
I found how Anguilla takes care of this. When you implement a Data Extender, you are extending the information regarding the items displayed in the list, which basically means that you are extending the Data (Model) behind the item in question.
Each Item in Tridion has its own class in the Anguilla Framework, for example a Component has its own Tridion.ContentManager.Component javascript "class".
Having said this, and going back to the example that shows the schema name of the component, we are not actually extending the model, since that information is already available in the component. However, we need to overwrite the methods exposed on each used for displaying information in the lists the item is in, in this case a Component.
So, when we deal with a Data Extender, if we want a full implementation of this functionality, we not only need to define the data extender:
<ext:dataextender
name="IntelligentDataExtender"
type="Com.Tridion.PS.Extensions.IntelligentDataExtender,PS.GUI.Extensions">
<ext:description>Shows extra info</ext:description>
</ext:dataextender>
But also we need to define what's the column we are adding:
<ext:lists>
<ext:add>
<ext:extension name="IntelligentColumnExtender"
assignid="IntelligentDataColumnExtender">
<ext:listDefinition>
<ext:selectornamespaces/>
<ext:columns>
<column
xmlns="http://www.sdltridion.com/2009/GUI/extensions/List"
id="IntelligentData"
type="data"
title="Additional Info"
selector="#ExtendedInfo"
translate="String"/>
</ext:columns>
</ext:listDefinition>
<ext:apply>
<ext:view name="DashboardView" />
</ext:apply>
</ext:extension>
</ext:add>
</ext:lists>
Once we have this, the GUI will display the column we just added: "Additional Info"
Well, now we need to achieve the list refreshing when the item is edited/checked-out and in, etc...
For that, we need to extend the model and implement a few methods in the Object we are extending. In this example I am extending the Page object, so whenever a page is edited, the row in the list we want to update gets refreshed, together with the rest of the cells in the table.
To extend the model we need to define what types are we extending, in this example I am going to use the "Page" class as an example. First of all you need to define the model extension in the config file of your Editor:
<cfg:group name="Com.Tridion.PS.Extensions.UI.Model"
merger="Tridion.Web.UI.Core.Configuration.Resources.DomainModelProcessor"
merge="always">
<cfg:domainmodel name="Com.Tridion.PS.Extensions.UI.Model">
<cfg:fileset>
<cfg:file type="script">/Scripts/PSPage.js</cfg:file>
</cfg:fileset>
<cfg:services />
</cfg:domainmodel>
</cfg:group>
and
<ext:modelextensions>
<cfg:itemtypes>
<cfg:itemtype id="tcm:64" implementation="Com.Tridion.PS.Extensions.UI.PSPage" />
</cfg:itemtypes>
</ext:modelextensions>
As you can see I am extending the Page by using the "Com.Tridion.PS.Extensions.UI.PSPage" class that is defined in the Javascript file "/Scripts/PSPage.js".
The only method that handles the row refreshing is the following:
Com.Tridion.PS.Extensions.UI.PSPage.prototype.getListItemXmlAttributes
= function PSPage$getListItemXmlAttributes(customAttributes) {
var attribs = {};
var p = this.properties;
if (customAttributes) {
for (var attr in customAttributes) {
attribs[attr] = customAttributes[attr];
}
}
//This adds my custom column back when the item is updated
attribs["ExtendedInfo"] = p.extendedInfo;
return this.callBase(
"Tridion.ContentManager.Page",
"getListItemXmlAttributes",
[attribs])
};
As you can see I am implementing the "ExtendedInfo" attribute which is the one displayed in my additional column.
There's more than just adding a Data Extender when dealing with adding a column to our lists. I will write a post in my blog here to provide with a fully working example.
I hope it makes sense.
Well, Jaime correctly described how CME updates changed items in Lists. But I want to add some additional information on how List controls, domain model List and Items are interact with each other. This might help you building your own extension with similar functionality.
Most of the domain model List items inherit from Tridion.ContentManager.ListTcmItems class. On the moment when any List item, based on mentioned class, is loaded it will be registered in Lists Registry (and un-registered when the List is unloaded). This will allow Model to use registered Lists as source of static data for Items and to update changed Items data in these Lists.
Update Item static data
For example, we have loaded ListCategories and there is only one Category in the List:
var pub = $models.getItem("tcm:0-1-1");
var list = pub.getListCategories();
list.load();
// After list is loaded
list.getXml();
That getXml() returns an XML like (simplified):
<tcm:ListCategories>
<tcm:Item ID="tcm:1-4-512" Type="512" Title="Keys" />
</tcm:ListCategories>
After that, if you try to get some static data for Category "Keys" it will be already set:
var category = $models.getItem("tcm:1-4-512");
category.isLoaded(); // return false
category.isStaticLoaded(); // return false
category.getTitle(); // return undefined
category.getStaticTitle(); // return "Keys"!
That is possible because $models.getItem call will do two things: it will return an existing (or create a new) domain model object and call $models.updateItemData method with it. This method call will go through all registered Lists in the Lists Registry and for all Lists whose TimeStamp bigger than Item's Last Update TimeStamp will call list.updateItemData with the model object.
The updateItemData method will check if the passed Item is in the list and if it is, then the Item will be updated with the static data that is available from the List.
Updating data of changed Items in the List
When a domain model Item is modified (updated, removed, created new) one of these methods is called:
$models.itemUpdated
$models.itemRemoved
These methods will go through the Lists in Lists Registry and call list.itemUpdated (or list.itemRemoved). These methods will check is passed Item is contained in their List and if so they will update the List xml from the Item data.
For that purpose there is a getListItemXmlNode method in the Tridion.ContentManager.Item class. This method will build List xml node based on the array of attributes, provided by getListItemXmlAttributes method on the Item. That's what Jaime mentioned in his answer.
If the List xml was updated, one of these events will be fired on List object:
itemadd
itemupdate
itemremove
Listening to these events on a List object in your view will allow you to timely update your List Control.
So if you want this mechanism to work with your extension, stick to these rules:
If you are creating new domain model List object - it should inherit Tridion.ContentManager.ListTcmItems class or it should implement the getId(), itemUpdated(item), itemsUpdated(item), itemRemoved(item) and updateItemData(item) methods
If you want to see changes in List control - attach handlers to corresponding events on the domain model List object and update your List control
If you are creating new domain model Item - it should inherit Tridion.ContentManager.Item class and you should improve getListItemXmlAttributes method to return correct array of attributes for the List
The CME will indeed update the items in the list dynamically after the save occurs, without going to the server.
To do so, it calls a method named "getListItemXml" which returns the update XML element for the list. It will then update or add this element, which will update or add the item in the list view.
getListItemXml is a method of the different Model objects.
So how do you take advantage of this? I'm not sure.
Perhaps you could overwrite the method (or maybe getListItemXmlAttributes is best) with your own to add the additional data?
There is also an "itemupdate" event fired whenever an item is updated in the list.
You can hook into that by doing something like this:
var myEventHandler = function(event)
{
$log.message("Item updated. TridionEvent object passed: " + event);
}
var view = $display.getView();
var list = view.getListObject("uri-of-Folder");
list.addEventListener("itemupdate", myEventHandler);
I suppose you could use that to update the list entry for the item after the fact.
Be sure to call removeEventHandler at some point too.
None of this is optimal, obviously.
But I don't know of any extension point that would solve this particular problem.
I think I would (attempt to) implement this by monitoring the items in a folder periodically and updating that list after this polling mechanism had detected a change in that folder.
For example, I would write some javascript timeout or interval that runs in the background and checks the items in the current folder. If it detects a change, it triggers the update of the list.
Alternatively, you could also try to intercept the action that changed your list (e.g. the creation of a new item), maybe by means of an event system, and as such update your list. I don't think this is much different than the first approach, as I think it still implies some level of polling from the GUI side.

Resources