Skip to content

Commit c81a125

Browse files
jensensstevepiercy
andauthored
a components chapter (#1367)
* intro for a components chapter * add to index * typos * some more text * more utilities * some spell checking * Rearrange introduction, removed empty headings Add meta information * Update tip submodules/volto * Finish cleaning up components.md * Move components.md into Conceptual guides --------- Co-authored-by: Steve Piercy <[email protected]>
1 parent efe86f9 commit c81a125

File tree

3 files changed

+213
-1
lines changed

3 files changed

+213
-1
lines changed

docs/conceptual-guides/components.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
myst:
3+
html_meta:
4+
"description": "Conceptual guide of the Zope Component Architecture in Plone"
5+
"property=og:description": "Conceptual guide of the Zope Component Architecture in Plone"
6+
"property=og:title": "Conceptual guide of the Zope Component Architecture in Plone"
7+
"keywords": "Plone, Plone 6, Zope Component Architecture, ZCA, interface, adapter, utility, event, subscriber, registry, lookup"
8+
---
9+
10+
# Component architecture
11+
12+
The {term}`Zope Component Architecture` (ZCA) is a Python framework for supporting component-based design and programming, utilizing the design patterns interface, adapter, abstract factory, and publish-subscribe.
13+
14+
Plone logic is wired together by Zope Component Architecture.
15+
It provides the "enterprise business logic" engine for Plone.
16+
17+
18+
## Concepts
19+
20+
The following high-level concepts are the core of the ZCA.
21+
22+
Interface
23+
: Abstract definition of the intended public behavior of an object providing the interface.
24+
25+
Adapter
26+
: Specific implementation of an interface.
27+
An adapter provides an interface on its own, and adapts one or more objects with specific interfaces.
28+
29+
Utility
30+
: Specific implementation of an interface either as a singleton or factored-on lookup.
31+
32+
Events and subscribers
33+
: Events are emitted, and a subscriber may listen to those events.
34+
Events provide an interface, and subscribers are registered for specific interfaces.
35+
Events are only dispatched to subscribers matching the interface of the event.
36+
37+
Registries
38+
: Adapters, utilities, and subscribers are registered in registries.
39+
Here the wiring is done.
40+
Additional to the interface, a name might be provided for adapters and utilities (so-called named adapters or named utilities).
41+
Registration can be done in Python code or via {term}`ZCML`, an XML dialect.
42+
43+
Lookup
44+
: The lookup functions are providing the logic to dynamically factor an adapter or utility matching the object that was fed in.
45+
You can ask to get an adapter to an object and pass in a name and the lookup method introspects the interface provided by the object and searches the registry for matches.
46+
47+
48+
## Design patterns
49+
50+
To better understand the Zope Component Architecture, it helps to review the basics of a few of the 23 classical [design patterns](https://en.wikipedia.org/wiki/Software_design_pattern).
51+
52+
The interface pattern (its former name, and is now called "protocol pattern") is used to define the behavior of the adapter.
53+
54+
> [...] a protocol or interface type is a data type describing a set of method signatures, the implementations of which may be provided by multiple classes that are otherwise not necessarily related to each other.
55+
> A class which provides the methods listed in a protocol is said to adopt the protocol, or to implement the interface.
56+
>
57+
> ~ _[Wikipedia, Protocol (object-oriented programming)](https://en.wikipedia.org/wiki/Protocol_(object-oriented_programming))_
58+
59+
The [marker pattern](https://en.wikipedia.org/wiki/Marker_interface_pattern) is an empty interface to associate metadata with a class.
60+
61+
Adapters in the ZCA are an implementation of the adapter design pattern in Zope.
62+
63+
> In software engineering, the adapter pattern is a software design pattern [...] that allows the interface of an existing class to be used as another interface.
64+
> It is often used to make existing classes work with others without modifying their source code.
65+
>
66+
> ~ _[Wikipedia, Adapter design pattern](https://en.wikipedia.org/wiki/Adapter_pattern)_
67+
68+
Both adapters and utilities are initialized by an abstract factory pattern using the registries.
69+
70+
> The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.
71+
> In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part of the theme.
72+
> The client does not know (or care) which concrete objects it gets from each of these internal factories, since it uses only the generic interfaces of their products.
73+
> This pattern separates the details of implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.
74+
>
75+
> ~ _[Wikipedia, Abstract factory pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern)_
76+
77+
The event system uses the publish-subscribe pattern.
78+
79+
> [...] publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be.
80+
> Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.
81+
>
82+
> ~ [Wikipedia, Publish–subscribe pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
83+
84+
85+
### Further reading
86+
87+
- [`zope.component`](https://zopecomponent.readthedocs.io/en/latest/index.html) documentation
88+
- [A Comprehensive Guide to Zope Component Architecture](https://github.com/baijum/zcadoc) by @baijum
89+
90+
91+
## Component architecture in Plone
92+
93+
Plone incorporates the component architecture in its design.
94+
95+
96+
### Registries
97+
98+
The component registry is used to register adapters, utilities, and subscribers.
99+
On lookup, it is used to find and initialize the matching adapter for the given objects, and name if given; to adapt; to find the right utility for an interface, and name if given; and to call the matching subscribers for an event.
100+
101+
We have two levels of registries.
102+
103+
Global component registry
104+
: The Global component registry is always and globally available as a singleton.
105+
Configuration is done in Plone using {term}`ZCML` files, which is a {term}`XML`-{term}`DSL`.
106+
Usually they are named {file}`configure.zcml`, but they may include differently named ZCML files.
107+
108+
Local component registry
109+
: Each Plone site has its own local component registry.
110+
If there are one, two, or more Plone sites created in one database, each has its own local component registry.
111+
The local registry is activated and registered on traversal time.
112+
If a lookup in the local registry fails, then it falls back to the lookup in the global registry.
113+
In theory, registries can be stacked upon each other in several layers, but in practice in Plone, we have two levels: local and global.
114+
Configuration is done in the profile {term}`GenericSetup` in a file {file}`componentregistry.xml`.
115+
Note its syntax is completely different from ZCML.
116+
117+
118+
### Utilities
119+
120+
Utility classes provide site-wide utility objects or functions.
121+
Compared to "plain Python functions", utilities provide the advantage of being plug-in points without the need for monkey-patching.
122+
123+
They are registered by marker interfaces, and optionally with a name, in which case they are called "named utilities".
124+
Accordingly, utilities can be looked up by name or interface.
125+
126+
Site customization logic or add-on products can override utilities for enhanced or modified functionality.
127+
128+
129+
#### Global and local utilities
130+
131+
Utilities can be either global or local.
132+
133+
global
134+
: Registered during Zope's start-up.
135+
Global utilities are registered in ZCML, and affect the Zope application server and all Plone site instances.
136+
137+
local
138+
: Registered at the Plone site or add-on installer time for a certain site.
139+
Local utilities are registered to persistent objects.
140+
The context of local utilities is stored in a thread-local variable which is set during traversal.
141+
Thus, when you ask for local utilities, they usually come from a persistent registry set up in the Plone site root object.
142+
143+
144+
#### Register a utility
145+
146+
You can register utilities in two ways, either by providing a _factory_, or a callable, which creates the object as a result, or by _component_, a ready-to-use object.
147+
Utility factories take no constructor parameters.
148+
149+
A utility factory can be provided by either a function or class.
150+
151+
function
152+
: The function is called and it returns the utility object.
153+
154+
class
155+
: The class `__call__()` method itself acts as a factory and returns a new class instance.
156+
157+
A utility component can be either a:
158+
159+
- function that needs to provide a (marker) interface, or
160+
- a global instance of a class implementing a marker interface, or
161+
in the case of a local registry, a so-called "local component" which persists as an object in the ZODB and itself needs to provide a marker interface.
162+
163+
Utilities may or may not have a name.
164+
165+
```{todo}
166+
A global utility is constructed when Plone is started and ZCML is read. (needs Verification)
167+
A local component is either a persistent object in the ZODB or constructed when (TODO: When? Traversal time? Lookup time?)
168+
```
169+
170+
```{note}
171+
If you need to use parameters, such as context or request, consider using views or adapters instead.
172+
```
173+
174+
To learn about some important utilities in Plone, read the chapter {doc}`/backend/global-utils`.
175+
176+
177+
```{todo}
178+
The rest of this chapter is a work in progress and an outline of great things to come.
179+
Pull requests are welcome!
180+
```
181+
182+
### Adapters
183+
184+
- general
185+
- views, viewlets
186+
- forms
187+
- overriding
188+
- adapters
189+
- utilities
190+
- views
191+
192+
193+
### Lookup
194+
195+
- lookup adapter
196+
- using the Interface as abstract factory
197+
- using the API
198+
- IRO, names ...
199+
- lookup an utility, names, singletons and factory based
200+
201+
202+
### Events and Subscribers
203+
204+
- general zope events
205+
- lifecycle events
206+
- important events in plone

docs/conceptual-guides/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ choose-user-interface
1919
distributions
2020
package-management
2121
make-build-backend-walk-through
22+
components
2223
```

docs/glossary.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,12 +582,14 @@ plonecli
582582
ZCA
583583
Zope Component Architecture
584584
Zope Component Architecture (ZCA) is a Python framework for supporting component based design and programming.
585+
It uses the design patterns of interface, adapter, factory, and subscriber.
585586
It is very well suited to developing large Python software systems.
586587
The ZCA is not specific to the {term}`Zope` web application server.
587588
It can be used for developing any Python application.
588589
Maybe it should be called Python Component Architecture.
590+
589591
```{seealso}
590-
See also https://zopecomponent.readthedocs.io/en/latest/index.html.
592+
https://zopecomponent.readthedocs.io/en/latest/index.html
591593
```
592594
593595
browser layer
@@ -676,6 +678,9 @@ trigger
676678
A trigger is an event in Plone that causes the execution of defined actions.
677679
Example triggers include object modified, user logged in, and workflow state changed.
678680
681+
DSL
682+
Domain Specific Language
683+
679684
navigation root
680685
An object marked as a navigation root provides a way to root catalog queries, searches, breadcrumbs, and so on, into that object.
681686

0 commit comments

Comments
 (0)