Merged doc doc-dc
authorDamien Correia
Fri, 21 Dec 2018 17:28:34 +0100
branchdoc-dc
changeset 142 5a82a9a2ea46
parent 141 9ab9f762abed
child 143 1d052540f8cd
Merged doc
src/source/dev_guide/custom-skin.rst
src/source/dev_guide/howto-adapter.rst
src/source/dev_guide/howto-template.rst
src/source/dev_guide/internals.rst
--- a/src/source/dev_guide/custom-skin.rst	Fri Dec 21 15:52:29 2018 +0100
+++ b/src/source/dev_guide/custom-skin.rst	Fri Dec 21 17:28:34 2018 +0100
@@ -207,3 +207,66 @@
 .. tip::
     When a setting_interface is associated to a renderer, you can access to `settings` attributes through the template
 
+
+.. _templatehowto:
+
+How to define or change a template for a specific skin?
+=======================================================
+
+Override the default template for a renderer
+--------------------------------------------
+
+If you want to modify the template for a particular rendering mode, you can use the function :py:func:`override_template`
+
+.. code-block:: python
+
+	from pyams_template.template import override_template
+
+	from my_website.skin.public.layer import ICustomLayer
+	from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
+
+
+	override_template(context=KeyNumberPortletHorizontalRenderer,
+					template="templates/keynumber-horizontal.pt",
+					layer=ICustomLayer
+					)
+
+
+This new template can be applied to a particular :ref:`Skin <skinhowto>` by specifying on which layer to use this renderer
+*(ex: layer=IMyWebsiteLayer)*
+
+
+
+Redefine the default template for a renderer
+--------------------------------------------
+
+You must redefine an adapter to add new variables or static resources for your new template,
+
+.. code-block:: python
+
+	# import interfaces
+	from my_website.skin.public.layer import ICustomLayer
+
+	from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings
+	from pyams_portal.interfaces import IPortletRenderer, IPortalContext
+
+	# import packages
+	from my_website.skin.public import my_carousel_init ,my_carousel_animation
+
+	from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
+	from pyams_template.template import template_config
+	from pyams_utils.adapter import adapter_config
+	from zope.interface import Interface
+
+
+	@adapter_config(context=(IPortalContext, IBaseLayer, Interface, IKeyNumberPortletSettings),
+	                provides=IPortletRenderer)
+	@template_config(template='templates/keynumber-horizontal.pt', layer=ICustomLayer)
+	class MyCustomKeyNumberPortletHorizontalRenderer(KeyNumberPortletHorizontalRenderer):
+		"""Key numbers portlet horizontal renderer"""
+
+		resources = (my_carousel_init, my_carousel_animation)
+
+
+The attribute :py:attr:`resources` is used to load in the template static resources. The application will automatically
+integrate resource content when the template is calling.
--- a/src/source/dev_guide/howto-adapter.rst	Fri Dec 21 15:52:29 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-.. _adapterhowto:
-
-
-How to define an annotations adapter?
-=====================================
-
-Adapters are important concepts of ZCA and PyAMS framework. If you don't know what are adapters, see :ref:`zca`.
-
-
-What are annotations?
-+++++++++++++++++++++
-
-When an adapter have to add persistent attributes to a persistent class, it can add these attributes directly into
-persistent instances. But this way can lead to conflicts when several adapters want to use the same attribute name for
-different kinds of information.
-
-Annotations are an elegant way to handle this use case: they are based on a BTree which is stored into a
-specific instance attribute (*__annotations__*). Any adapter can then use this dictionary to store it's own
-informations, using it's own namespace as dictionary key.
-
-ZODB browser allows you to display existing annotations:
-
-.. image:: ../_static/annotations-1.png
-
-This example displays several annotations, each using it's own namespace:
-
-.. image:: ../_static/annotations-2.png
-
-
-Designing interfaces
-++++++++++++++++++++
-
-The first step with ZCA is to design your interfaces.
-
-The are going to base our example on PyAMS_content 'paragraphs' component: a content class is marked as a
-*paragraphs container target*, a class that can store paragraphs. But the real storage of paragraphs is done by
-another *container* class:
-
-.. code-block:: python
-    :linenos:
-
-    from zope.annotation.interfaces import IAttributeAnnotatable
-    from zope.containers.constraints import containers, contains
-
-
-    class IBaseParagraph(Interface):
-        """Base paragraph interface"""
-
-        containers('.IParagraphContainer')
-
-
-    class IParagraphContainer(IOrderedContainer):
-        """Paragraphs container"""
-
-        contains(IBaseParagraph)
-
-
-    class IParagraphContainerTarget(IAttributeAnnotatable):
-        """Paragraphs container marker interface"""
-
-
-    PARAGRAPH_CONTAINER_KEY = 'pyams_content.paragraph'
-
-
-- line 5 to 8: :class:`IBaseParagraph` is the base interface for all paragraphs; constraint implies that paragraphs
-  can only be stored in a container implementing :class:`IParagraphContainer` interface.
-- line 11 to 14: :class:`IParagraphContainer` is the base interface for paragraphs containers; constraint implies that
-  such a container can only contain objects implementing :class:`IBaseParagraph` interface.
-- line 17 to 18: :class:`IParagraphContainerTarget` is only a *marker* interface which doesn't provide any method or
-  attribute; it only inherits from :class:`IAttributeAnnotatable`, which implies that classes implementing this
-  interface allows other classes to add informations as annotations through a dedicated *__annotations__* attribute.
-- line 21: this is the key which will be used to store our annotation.
-
-
-Creating persistent classes
-+++++++++++++++++++++++++++
-
-The first step is to declare that a given content class can store paragraphs:
-
-.. code-block:: python
-    :linenos:
-
-    from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget
-    from zope.interface import implementer
-
-    @implementer(IParagraphContainerTarget)
-    class WfNewsEvent(WfSharedContent):
-        """News event class"""
-
-Here we just say "Well, I'm a shared content, and I'm OK to store paragraphs!".
-
-So we can design the paragraphs container class. It's this class which will *really* store the paragraphs:
-
-.. code-block:: python
-    :linenos:
-
-    @implementer(IParagraphContainer)
-    class ParagraphContainer(BTreeOrderedContainer):
-        """Paragraphs container"""
-
-The paragraphs container class inherits from a :class:`BTreeOrderedContainer` and implements
-:class:`IParagraphContainer`.
-
-The last operation is to create the adapter, which is the *glue* between the *target* class and the paragraphs
-container:
-
-.. code-block:: python
-    :linenos:
-
-    from pyams_utils.adapter import adapter_config, get_annotation_adapter
-
-    @adapter_config(context=IParagraphContainerTarget, provides=IParagraphContainer)
-    def paragraph_container_factory(target):
-        """Paragraphs container factory"""
-        return get_annotation_adapter(target,
-                                      PARAGRAPH_CONTAINER_KEY,
-                                      ParagraphContainer,
-                                      name='++paras++')
-
-PyAMS provides a shortcut to create an annotation adapter in :func:`pyams_utils.adapter.get_annotation_adapter`.
-It's mandatory arguments are:
-
-- **context** (line 6): the context to which the adapter is applied
-- **key** (line 7): the string key used to access and store context's annotations
-- **factory** (line 8): if the requested annotation is missing, a new one is created using this factory (which can be a class or
-  a function)
-
-Optional arguments are:
-
-- **markers** (None by default): if set, should be a list of marker interfaces which will be assigned to object
-  created by the factory
-- **notify**: if *True* (default), an :class:`ObjectCreatedEvent` event is notified on object creation
-- **locate**: if *True* (default), context is set as *parent* of created object
-- **parent**: if *locate* is True and if *parent* is set, this is the object to which the new object should be *parented*
-  instead of initial context
-- **name** (None by default): some objects need to be traversed, especially when you have to be able to access them through an URL; this
-  is the name given to created object.
-
-
-Using your adapter
-++++++++++++++++++
-
-Starting from your *content* object, it's then very simple to access to the paragraphs container:
-
-.. code-block:: python
-    :linenos:
-
-    event = WfNewsEvent()
-    paragraphs_container = IParagraphContainer(event, None)
-
-And that's it! From now I can get access to all paragraphs associated with my initial content!!
-
-
-Managing traversal
-++++++++++++++++++
-
-As said before, sometimes you have to be able to *traverse* from an initial content to a given sub-content
-managed by an adapter.
-
-PyAMS defines a custom :class:`pyams_utils.traversing.NamespaceTraverser`: when a request traversing subpath is
-starting with '++' characters, it is looking for a named traverser providing :class:`ITraversable` interface
-to the last traversed object.
-
-.. code-block:: python
-    :linenos:
-
-    @adapter_config(name='paras', context=IParagraphContainerTarget, provides=ITraversable)
-    class ParagraphContainerNamespace(ContextAdapter):
-        """++paras++ namespace adapter"""
-
-        def traverse(self, name, furtherpath=None):
-            return IParagraphContainer(self.context)
-
-- line 1: the adapter is named "paras"; this is matching the *++paras++* name which was given to our annotation adapter
-- line 2: the adapter is just a simple context adapter, so inheriting from :class:`pyams_utils.adapter.ContextAdapter`
-- lines 5 to 6: the *traverse* method is used to access the adapted content; if a name like "++ns++value" is given
-  to an adapted object, the "value" part is given as *name" argument.
-
-From now, as soon as an URL like "/mycontent/++paras++/" will be used, you will get access to the paragraphs container.
-This is a standard BTree container, so will get access to it's sub-objects by key.
--- a/src/source/dev_guide/howto-template.rst	Fri Dec 21 15:52:29 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-.. _templatehowto:
-
-
-How to define or change a template for a specific skin?
-=======================================================
-
-Override the default template for a renderer
---------------------------------------------
-
-If you want to modify the template for a particular rendering mode, you can use the function :py:func:`override_template`
-
-.. code-block:: python
-
-	from pyams_template.template import override_template
-
-	from my_website.skin.public.layer import ICustomLayer
-	from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
-
-
-	override_template(context=KeyNumberPortletHorizontalRenderer,
-					template="templates/keynumber-horizontal.pt",
-					layer=ICustomLayer
-					)
-
-
-This new template can be applied to a particular :ref:`Skin <skinhowto>` by specifying on which layer to use this renderer
-*(ex: layer=IMyWebsiteLayer)*
-
-
-
-Redefine the default template for a renderer
---------------------------------------------
-
-You must redefine an adapter to add new variables or static resources for your new template,
-
-.. code-block:: python
-
-	# import interfaces
-	from my_website.skin.public.layer import ICustomLayer
-
-	from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings
-	from pyams_portal.interfaces import IPortletRenderer, IPortalContext
-
-	# import packages
-	from my_website.skin.public import my_carousel_init ,my_carousel_animation
-
-	from pyams_default_theme.component.keynumber.portlet import KeyNumberPortletHorizontalRenderer
-	from pyams_template.template import template_config
-	from pyams_utils.adapter import adapter_config
-	from zope.interface import Interface
-
-
-	@adapter_config(context=(IPortalContext, IBaseLayer, Interface, IKeyNumberPortletSettings),
-	                provides=IPortletRenderer)
-	@template_config(template='templates/keynumber-horizontal.pt', layer=ICustomLayer)
-	class MyCustomKeyNumberPortletHorizontalRenderer(KeyNumberPortletHorizontalRenderer):
-		"""Key numbers portlet horizontal renderer"""
-
-		resources = (my_carousel_init, my_carousel_animation)
-
-
-The attribute :py:attr:`resources` is used to load in the template static resources. The application will automatically
-integrate resource content when the template is calling.
--- a/src/source/dev_guide/internals.rst	Fri Dec 21 15:52:29 2018 +0100
+++ b/src/source/dev_guide/internals.rst	Fri Dec 21 17:28:34 2018 +0100
@@ -3,15 +3,213 @@
 Understanding PyAMS internals
 =============================
 
+Adapters
+--------
+
+Adapters are important concepts of ZCA and PyAMS framework. If you don't know what are adapters, see :ref:`zca`.
+
 
 Annotations
 -----------
 
+When an adapter have to add persistent attributes to a persistent class, it can add these attributes directly into
+persistent instances. But this way can lead to conflicts when several adapters want to use the same attribute name for
+different kinds of information.
+
+Annotations are an elegant way to handle this use case: they are based on a BTree which is stored into a
+specific instance attribute (*__annotations__*). Any adapter can then use this dictionary to store it's own
+informations, using it's own namespace as dictionary key.
+
+ZODB browser allows you to display existing annotations:
+
+.. image:: ../_static/annotations-1.png
+
+This example displays several annotations, each using it's own namespace:
+
+.. image:: ../_static/annotations-2.png
+
+
+Designing interfaces
+--------------------
+
+The first step with ZCA is to design your interfaces.
+
+The are going to base our example on PyAMS_content 'paragraphs' component: a content class is marked as a
+*paragraphs container target*, a class that can store paragraphs. But the real storage of paragraphs is done by
+another *container* class:
+
+.. code-block:: python
+    :linenos:
+
+    from zope.annotation.interfaces import IAttributeAnnotatable
+    from zope.containers.constraints import containers, contains
+
+
+    class IBaseParagraph(Interface):
+        """Base paragraph interface"""
+
+        containers('.IParagraphContainer')
+
+
+    class IParagraphContainer(IOrderedContainer):
+        """Paragraphs container"""
+
+        contains(IBaseParagraph)
+
+
+    class IParagraphContainerTarget(IAttributeAnnotatable):
+        """Paragraphs container marker interface"""
+
+
+    PARAGRAPH_CONTAINER_KEY = 'pyams_content.paragraph'
+
+
+- line 5 to 8: :class:`IBaseParagraph` is the base interface for all paragraphs; constraint implies that paragraphs
+  can only be stored in a container implementing :class:`IParagraphContainer` interface.
+- line 11 to 14: :class:`IParagraphContainer` is the base interface for paragraphs containers; constraint implies that
+  such a container can only contain objects implementing :class:`IBaseParagraph` interface.
+- line 17 to 18: :class:`IParagraphContainerTarget` is only a *marker* interface which doesn't provide any method or
+  attribute; it only inherits from :class:`IAttributeAnnotatable`, which implies that classes implementing this
+  interface allows other classes to add informations as annotations through a dedicated *__annotations__* attribute.
+- line 21: this is the key which will be used to store our annotation.
+
+
+Creating persistent classes
+---------------------------
+
+The first step is to declare that a given content class can store paragraphs:
+
+.. code-block:: python
+    :linenos:
+
+    from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget
+    from zope.interface import implementer
+
+    @implementer(IParagraphContainerTarget)
+    class WfNewsEvent(WfSharedContent):
+        """News event class"""
+
+Here we just say "Well, I'm a shared content, and I'm OK to store paragraphs!".
+
+So we can design the paragraphs container class. It's this class which will *really* store the paragraphs:
+
+.. code-block:: python
+    :linenos:
+
+    @implementer(IParagraphContainer)
+    class ParagraphContainer(BTreeOrderedContainer):
+        """Paragraphs container"""
+
+The paragraphs container class inherits from a :class:`BTreeOrderedContainer` and implements
+:class:`IParagraphContainer`.
+
+The last operation is to create the adapter, which is the *glue* between the *target* class and the paragraphs
+container:
+
+.. code-block:: python
+    :linenos:
+
+    from pyams_utils.adapter import adapter_config, get_annotation_adapter
+
+    @adapter_config(context=IParagraphContainerTarget, provides=IParagraphContainer)
+    def paragraph_container_factory(target):
+        """Paragraphs container factory"""
+        return get_annotation_adapter(target,
+                                      PARAGRAPH_CONTAINER_KEY,
+                                      ParagraphContainer,
+                                      name='++paras++')
+
+PyAMS provides a shortcut to create an annotation adapter in :func:`pyams_utils.adapter.get_annotation_adapter`.
+It's mandatory arguments are:
+
+- **context** (line 6): the context to which the adapter is applied
+- **key** (line 7): the string key used to access and store context's annotations
+- **factory** (line 8): if the requested annotation is missing, a new one is created using this factory (which can be a class or
+  a function)
+
+Optional arguments are:
+
+- **markers** (None by default): if set, should be a list of marker interfaces which will be assigned to object
+  created by the factory
+- **notify**: if *True* (default), an :class:`ObjectCreatedEvent` event is notified on object creation
+- **locate**: if *True* (default), context is set as *parent* of created object
+- **parent**: if *locate* is True and if *parent* is set, this is the object to which the new object should be *parented*
+  instead of initial context
+- **name** (None by default): some objects need to be traversed, especially when you have to be able to access them through an URL; this
+  is the name given to created object.
+
+
+Using your adapter
+------------------
+
+Starting from your *content* object, it's then very simple to access to the paragraphs container:
+
+.. code-block:: python
+    :linenos:
+
+    event = WfNewsEvent()
+    paragraphs_container = IParagraphContainer(event, None)
+
+And that's it! From now I can get access to all paragraphs associated with my initial content!!
+
+
 Traversal
 ---------
 
-Namespaces
-----------
+Sometimes you have to be able to *traverse* from an initial content to a given sub-content
+managed by an adapter.
+
+PyAMS defines a custom :class:`pyams_utils.traversing.NamespaceTraverser`: when a request traversing subpath is
+starting with '++' characters, it is looking for a named traverser providing :class:`ITraversable` interface
+to the last traversed object.
+
+.. code-block:: python
+    :linenos:
+
+    @adapter_config(name='paras', context=IParagraphContainerTarget, provides=ITraversable)
+    class ParagraphContainerNamespace(ContextAdapter):
+        """++paras++ namespace adapter"""
+
+        def traverse(self, name, furtherpath=None):
+            return IParagraphContainer(self.context)
+
+- line 1: the adapter is named "paras"; this is matching the *++paras++* name which was given to our annotation adapter
+- line 2: the adapter is just a simple context adapter, so inheriting from :class:`pyams_utils.adapter.ContextAdapter`
+- lines 5 to 6: the *traverse* method is used to access the adapted content; if a name like "++ns++value" is given
+  to an adapted object, the "value" part is given as "name" argument.
+
+From now, as soon as an URL like "/mycontent/++paras++/" will be used, you will get access to the paragraphs container.
+This is a standard BTree container, so will get access to it's sub-objects by key.
+
+
+Managing traversal
+------------------
+
+As said before, sometimes you have to be able to *traverse* from an initial content to a given sub-content
+managed by an adapter.
+
+PyAMS defines a custom :class:`pyams_utils.traversing.NamespaceTraverser`: when a request traversing subpath is
+starting with '++' characters, it is looking for a named traverser providing :class:`ITraversable` interface
+to the last traversed object.
+
+.. code-block:: python
+    :linenos:
+
+    @adapter_config(name='paras', context=IParagraphContainerTarget, provides=ITraversable)
+    class ParagraphContainerNamespace(ContextAdapter):
+        """++paras++ namespace adapter"""
+
+        def traverse(self, name, furtherpath=None):
+            return IParagraphContainer(self.context)
+
+- line 1: the adapter is named "paras"; this is matching the *++paras++* name which was given to our annotation adapter
+- line 2: the adapter is just a simple context adapter, so inheriting from :class:`pyams_utils.adapter.ContextAdapter`
+- lines 5 to 6: the *traverse* method is used to access the adapted content; if a name like \"++ns++value"\ is given
+  to an adapted object, the "value" part is given as "name" argument.
+
+From now, as soon as an URL like "/mycontent/++paras++/" will be used, you will get access to the paragraphs container.
+This is a standard BTree container, so will get access to it's sub-objects by key.
+
 
 .. _traverser: