You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Get an overview over the technologies used to extend Plone
16
+
In this part you will get an overview over the technologies used to extend the Plone backend.
19
17
20
18
Topics covered:
21
19
22
-
- Overriding Python components
20
+
- Extension packages
23
21
- Component architecture
24
22
- ZCML
25
23
- GenericSetup
26
24
```
27
25
28
-
As a developer you want to go further than simply configuring Plone, you want to extend and customize it.
26
+
As a developer you want to go further than simply configuring Plone.
27
+
You want to extend and customize it.
29
28
Plone is built to be extended.
30
29
Extendability is not an afterthought but is the core of Plone and the systems it is based on.
31
-
Instead it is the core of its architecture.
32
30
33
-
> Plone consists of a Python backend and a React frontend.
34
-
> They are connected via the REST API.
35
-
> Thus you have two different layers that you can customize.
31
+
How do you extend Plone?
36
32
37
-
Therefore we create two different extension packages to customize and extend Plone:
33
+
This depends on what type of extension you want to create.
38
34
39
-
1. One is a Python package that holds for example content types, behaviors and configuration.
40
-
2. The other is a JavaScript package that hold views, styling and customization of the frontend.
35
+
```{only} not presentation
36
+
- You can create extensions with new types of objects to add to your Plone site. Usually these are content types.
37
+
- You can create an extension that changes or extends functionality. For example to change the way Plone displays search results, or to make pictures searchable by adding a transformer from image to text.
38
+
```
41
39
42
-
Sometimes it is easy to know, which layer needs to be customized to achieve a certain result.
40
+
For most projects you combine multiple kinds of methods to extend Plone.
43
41
44
-
- All styling and JavaScript-based interaction is customized on the Volto side of Plone.
45
-
- Content types and other persistent data is customized or created in a Python package.
46
42
47
-
For more complex use cases you will need to add code to both parts of our customization story.
48
-
For example a content type is defined in the Python package and its visualization is defined in the JavaScript package.
43
+
(extending-packages-label)=
49
44
45
+
## Extension packages
50
46
51
-
(extending-technologies-label)=
47
+
Plone consists of a Python backend and a React frontend.
48
+
They are connected via the REST API.
49
+
Thus you have two different layers that you can customize.
52
50
53
-
## Extension technologies
51
+
Therefore we create two different extension packages to customize and extend Plone.
52
+
(These are similar to add-ons, but they are located in the project repository.)
54
53
55
-
How do you extend Plone?
54
+
1. One is a Python package that holds for example content types, behaviors and configuration.
55
+
(For the training project, this is located in {file}`backend/src/ploneconf/site`.)
56
+
2. The other is a JavaScript package that hold views, styling and customization of the frontend.
57
+
(For the training project, this is located in {file}`frontend/packages/volto-ploneconf-site`.)
56
58
57
-
This depends on what type of extension you want to create.
59
+
Sometimes it is easy to know which layer needs to be customized to achieve a certain result.
58
60
59
-
```{only} not presentation
60
-
- You can create extensions with new types of objects to add to your Plone site. Usually these are content types.
61
-
- You can create an extension that changes or extends functionality. For example to change the way Plone displays search results, or to make pictures searchable by adding a transformer from image to text.
62
-
```
61
+
- All styling and JavaScript-based interaction is customized on the frontend side of Plone.
62
+
- Content types and other persistent data are customized or created in a Python package.
63
+
64
+
For more complex use cases you will need to add code to both parts of our customization story.
65
+
For example a content type is defined in the Python package and its visualization is defined in the JavaScript package.
63
66
64
-
For most projects you combine multiple kinds of methods to extend Plone.
@@ -75,62 +77,82 @@ For most projects you combine multiple kinds of methods to extend Plone.
75
77
- Powerful and flexible
76
78
```
77
79
78
-
```{only} not presentation
79
-
The best way to extend Plone is via *Components*.
80
-
81
-
A bit of history is in order.
80
+
````{only} not presentation
82
81
83
-
When Zope started, object-oriented design was **the** silver bullet.
82
+
Plone uses a component architecture to provide loose coupling between different parts of the system.
84
83
85
-
Object-oriented design is good at modeling inheritance, but breaks down when an object has multiple aspects that are part of multiple taxonomies.
84
+
What does that mean?
85
+
There is a central registry of components that can fulfill predefined contracts, called interfaces.
86
+
If some code wants to make a call to another part of Plone, it should not do so directly.
87
+
Instead, it should ask the registry for a component that can provide the interface it is designed to use.
86
88
87
-
Some object-oriented programming languages like Python handle this through multiple inheritance. But it's not a good way to do it. Zope objects have more than 10 base classes. Too many namespaces makes code that's hard to maintain. Where did that method/attribute come from?
89
+
There are several kinds of components:
88
90
89
-
After a while, XML and Components became the next silver bullet (Does anybody remember J2EE?).
91
+
* *Utilities* provide a standalone service.
92
+
* *Adapters* provide a new way to access an existing object.
93
+
* *Subscribers* execute actions in response to events triggered on a different object.
90
94
91
-
Based on their experiences with Zope in the past, Zope developers thought that a component system configured via XML might be the way to go to keep the code more maintainable.
95
+
For example, there is an interface `INameFromTitle` which defines how to get the title for a content item.
96
+
(Get an adapter which is registered for the `INameFromTitle` interface, and get its `title` attribute.)
97
+
If you as a developer want to change how the title is calculated for a specific content type, you can register an `INameFromTitle` adapter for that content type.
92
98
93
-
Before Zope Components functionality was often extended by a practice called Monkey Patching: Changing code in other modules by importing and then modifying it at runtime.
99
+
This is the basis for Plone's extensibility.
100
+
Add-on packages can easily change core Plone functionality by adding or replacing components in the registry, without needing to directly change the code that uses those components.
94
101
95
-
Monkey Patching, like subclassing via multiple inheritance, does not scale. Multiple plugins might overwrite each other, you would explain to people that they have to reorder the imports, and then, suddenly, you will be forced to import feature A before B, B before C and C before A, or else your application won't work.
102
+
```{tip}
103
+
Many of the interfaces used by Plone core are defined in the `plone.base` package.
104
+
You can explore them here: https://github.com/plone/plone.base/tree/main/src/plone/base/interfaces
96
105
97
-
As the new concepts were radically different from the old Zope concepts, the Zope developers renamed the new project to Zope 3.
98
-
But it did not gain traction, was eventually renamed to Bluebream and then died out.
106
+
However, Plone is made up of many packages, so there are also a lot of interfaces defined elsewhere.
107
+
```
99
108
100
-
But the component architecture itself is quite successful and the Zope developers extracted it into the Zope Toolkit. The Zope toolkit is part of Zope, and Plone developers use it extensively.
109
+
```{note}
110
+
Earlier versions of Zope and Plone relied more on other ways of composing software, such as object-oriented inheritance.
111
+
But this led to very complicated objects that were difficult to reason about and override.
101
112
102
-
This is what you want to use.
113
+
Over time, many parts have been updated to use the component architecture.
114
+
But there are still some inner parts which use inheritance.
115
+
Sometimes it is necessary to use more invasive techniques like monkey-patching to override core Plone functionality.
103
116
```
104
117
118
+
````
119
+
120
+
105
121
(extending-components-label)=
106
122
107
-
## Configuring Zope Components with ZCML
123
+
## Configure Zope Components with ZCML
108
124
109
125
```{only} presentation
110
126
- zcml (Zope Component Markup Language) is used to register components
111
127
- components are distingushed by interfaces (contracts) that they require or provide
112
128
```
113
129
114
-
```{only} not presentation
115
-
ZCML, the Zope Configuration Mark-up Language is an XML based language used to configure Zope Components. With ZCML you declare utilities, adapters and browser views.
130
+
````{only} not presentation
131
+
The Zope Configuration Markup Language (ZCML) is an XML-based language used to configure Zope components.
132
+
With ZCML you register utilities, adapters and browser views using ZCML.
116
133
117
134
Components are distinguished from one another by the interfaces (formal definitions of functionality) that they require or provide.
118
135
119
-
During startup, Zope reads all these ZCML statements, validates that there are not two declarations trying to register the same components and registers everything. All components are registered by interfaces required and provided. Components with the same interfaces may optionally also be named.
136
+
During startup, Zope reads all these ZCML statements, validates that there are not two declarations trying to register the same components, and registers everything.
137
+
All components are registered by interfaces required and provided.
138
+
Components with the same interfaces may optionally also be named.
120
139
121
-
It may seem a little cumbersome that you have to register all components. But thanks to ZCML, you hardly ever have a hard time to find what and where extensions or customizations are defined. ZCML files are like a phone book.
140
+
```{tip}
141
+
ZCML is only processed at startup time.
142
+
If you make changes to a `.zcml` file, you have to restart the backend in order for the changes to take effect.
122
143
```
123
144
124
-
```{eval-rst}
125
-
.. epigraph::
126
-
127
-
Explicit is better than implicit
128
-
129
-
-- The Zen of Python
145
+
It may seem a little cumbersome that you have to register all components.
146
+
But thanks to ZCML, you hardly ever have a hard time to find what and where extensions or customizations are defined.
147
+
ZCML files are like a phone book.
148
+
````
130
149
150
+
```{epigraph}
151
+
Explicit is better than implicit
152
+
153
+
-- The Zen of Python
131
154
```
132
155
133
-
134
156
(extending-technologies-generic-setup-label)=
135
157
136
158
## GenericSetup
@@ -141,15 +163,24 @@ It may seem a little cumbersome that you have to register all components. But th
141
163
```
142
164
143
165
```{only} not presentation
144
-
The next thing is {py:mod}`Products.GenericSetup`.
166
+
Another tool for configuring Plone using XML files is {term}`GenericSetup`.
167
+
168
+
GenericSetup organizes XML configuration files in a _profile_.
169
+
When the profile is applied, it will update persistent settings stored in the database.
145
170
146
-
*GenericSetup* lets you define persistent configuration in XML files. *GenericSetup* parses the XML files and updates the persistent configuration according to the configuration. This is a step you have to run on your own!
171
+
Unlike ZCML, GenericSetup profiles are not read automatically.
172
+
You have to apply the profile on your own, usually by installing or upgrading an add-on.
173
+
When you do this, GenericSetup reads the XML files and updates the persistent configuration accordingly.
147
174
148
-
You will see many objects in Zope or the ZMI that you can customize through the web. If they are well behaving, they can export their configuration via *GenericSetup* and import it again.
175
+
GenericSetup profiles are a useful way to programmatically configure the same things that can be changed through the web in a control panel.
176
+
You will see many objects in Zope or the ZMI that you can customize through the web.
177
+
If they are well behaving, they can export their configuration via GenericSetup and import it again.
149
178
150
-
Typically you use *GenericSetup* to change workflows or add new content type definitions.
179
+
For example, you can use GenericSetup to change workflows or add new content type definitions.
151
180
152
-
GenericSetup profiles may also be built into Python packages. Every package that is listed on the add-on package list inside a Plone installation has a GS profile that details how it fits into Plone. Packages that are part of Plone itself may have GS profiles, but are excluded from the active/inactive listing.
181
+
GenericSetup profiles may also be built into Python packages.
182
+
Every package that is listed in the Add-ons control panel in Site Setup has a GenericSetup profile that defines how it fits into Plone.
183
+
(Packages that are part of Plone itself may also have GenericSetup profiles, but are not shown in the Add-ons control panel unless they are optional.)
153
184
```
154
185
155
186
Examples of a profile of an add-on in `profile/default/`
@@ -168,7 +199,8 @@ Examples of a profile of an add-on in `profile/default/`
168
199
</metadata>
169
200
```
170
201
171
-
Most settings are stored in a tool called `portal_registry`. Since it has great import/export handlers for GenericSetup it can be configured with {file}`registry/main.xml`:
202
+
Most settings are stored in a tool called `portal_registry`.
203
+
Since it has great import/export handlers for GenericSetup, it can be configured with {file}`registry/main.xml`:
0 commit comments