Hare
Hare

Reputation: 11

How to restrict amount of special content_type objects in folderish type to only one object?

I am creating a folderish type (archetype 1) and I want to have possibility to add only a single object of (archetype 2) to this folder.

Upvotes: 1

Views: 131

Answers (4)

JC Brand
JC Brand

Reputation: 2692

Ok, so you want your second type archetype 2 to be addable only once inside archetype 1?

I would do it in such a way that the Add New dropdown on the green edit bar only shows archetype 2 if it can be added (the other solutions here require the user to first render the add form and then be told that this is not allowed).

You need to make sure that your folderish archetype 1 subclasses ConstrainTypesMixin.

I think if you use the folderish content types in Products.ATContentTypes you will automatically subclass this mixin class, but it helps to make sure.

Then, inside archetype 1, add the method: getLocallyAllowedTypes. This method is declared in the ConstrainTypesMixin class in Products/ATContentTypes/lib/constraintypes.py

In this method you can now add the logic to check if an instance of archetype 2 has already been added. If it has, don't return it as one of the locally allowed types. If it hasn't, then return it (with the other types if they exist).

Make sure to first call super() in this method to get the locally added types from the superclass's method.

To understand how this works, you can look at the *_addableTypesInContext* method in the FactoriesSubMenuItem class in plone/app/contentmenu/menu.py to see when and how this getLocallyAllowedTypes method is called.

Upvotes: 1

Rigel Di Scala
Rigel Di Scala

Reputation: 3230

You can override the createObject.cpy script and add a check there:

this_type = REQUEST.form.get('type_name') 
if this_type == 'MyATContentType':
    # MyATContentType needs a special check
    ctool = getToolByName(context, 'portal_catalog')
    this_path = '/'.join(context.getPhysicalPath())

    # Query the Catalog to see we already have an instance of this object here
    results = ctool.searchResults({'portal_type': this_type, 'path': this_path})

    if results:
        context.plone_utils.addPortalMessage(_(
            u'Sorry, but there already is an object of type %s here.' % this_type
        ))

        # Redirect to the edit form of the first found object.
        cv = results[0]
        cv_path = cv.getPath()
        return context.REQUEST.RESPONSE.redirect(cv_path + "/edit")

Provide the customized script, together with the associated .metadata file, in the skins/templates folder of your product.

Bonus tip: In Dexterity, you would add this check in dexterity.AddForm.update()

Upvotes: 0

Laurence Rowe
Laurence Rowe

Reputation: 2997

You are probably best off creating a custom add form (perhaps using z3c.form) and making the placing the restriction there.

Upvotes: 0

tisto
tisto

Reputation: 1347

You can restrict the addable types inside your folderish type ("archetype 1") to "archetype 2" by amending the "archetypes 1" types definition (profiles/default/archetype1.xml):

<?xml version="1.0"?>
<object name="archetype1">
   ...
  <property name="filter_content_types">True</property>  
  <property name="allowed_content_types">
    <element value="archetype2" />
  </property>
  ...
</object>

Upvotes: 1

Related Questions