1480
Handlers are subscription adapter factories that don't produce
1481
anything. They do all of their work when called. Handlers are
1482
typically used to handle events. Handlers are also known as event
1483
subscribers or event subscription adapters.
1480
Los manejadores son factorias de adaptadores de subscripción que
1481
no producen nada. Realizan todo su trabajo cuando son llamados.
1482
Los manejadores se utilizan normalmente para tratar eventos. Los
1483
manejadores también se conocen como subscriptores de eventos o
1484
incluso como adaptadores de subscripción de eventos.
1485
Event subscribers are different from other subscription adapters in
1486
that the caller of event subscribers doesn't expect to interact with
1487
them in any direct way. For example, an event publisher doesn't
1488
expect to get any return value. Because subscribers don't need to
1489
provide an API to their callers, it is more natural to define them
1490
with functions, rather than classes. For example, in a
1491
document-management system, we might want to record creation times for
1486
Los subscriptores de eventos son distintos a los adaptadores de
1487
subscripción en cuanto a que el que llama a los subscriptores de
1488
eventos no espera interactuar con ellos de manera directa. Por
1489
ejemplo, un publicador de eventos no espera recibir ningún valor
1490
de retorno. Ya que los subscriptores no necesitan ofrecer una API
1491
a los que los llaman, es más natural definirlos con funciones,
1492
en vez de con clases. Por ejemplo, en un sistema de gestión
1493
documental, podemos querer registrar tiempos de creación para los
1494
1496
>>> import datetime
1496
>>> def documentCreated(event):
1497
... event.doc.created = datetime.datetime.utcnow()
1499
In this example, we have a function that takes an event and performs
1500
some processing. It doesn't actually return anything. This is a
1501
special case of a subscription adapter that adapts an event to
1502
nothing. All of the work is done when the adapter "factory" is
1503
called. We call subscribers that don't actually create anything
1504
"handlers". There are special APIs for registering and calling them.
1506
To register the subscriber above, we define a document-created event::
1498
>>> def documentoCreado(evento):
1499
... evento.doc.creado = datetime.datetime.utcnow()
1501
En este ejemplo, tenemos una función que recibe un evento y realiza
1502
un procesamiento. Realmente no devuelve nada. Este es un caso especial
1503
de un adaptador de subscripción que adapta un evento a nada. Todo el
1504
trabajo se realiza cuando la "fábrica" del adaptador es invocada.
1505
Llamamos "manejadores" a los subscriptores que no crean nada. Hay
1506
APIs especiales para registrarlos y llamarlos.
1508
Para registrar el subscriptor anterior definimos un evento de
1509
creación de documento::
1508
1511
>>> from zope.interface import Interface
1509
1512
>>> from zope.interface import Attribute
1510
1513
>>> from zope.interface import implements
1512
>>> class IDocumentCreated(Interface):
1515
>>> class IDocumentoCreado(Interface):
1514
... doc = Attribute("The document that was created")
1517
... doc = Attribute("El documento que se creó")
1516
>>> class DocumentCreated(object):
1519
>>> class DocumentoCreado(object):
1518
... implements(IDocumentCreated)
1521
... implements(IDocumentoCreado)
1520
1523
... def __init__(self, doc):
1521
1524
... self.doc = doc
1523
We'll also change our handler definition to:
1526
También cambiamos nuestra definición del manejador a::
1525
>>> def documentCreated(event):
1526
... event.doc.created = datetime.datetime.utcnow()
1528
>>> def documentoCreado(evento):
1529
... evento.doc.creado = datetime.datetime.utcnow()
1528
1531
>>> from zope.component import adapter
1530
>>> @adapter(IDocumentCreated)
1531
... def documentCreated(event):
1532
... event.doc.created = datetime.datetime.utcnow()
1534
This marks the handler as an adapter of `IDocumentCreated` events.
1536
Now we'll register the handler::
1533
>>> @adapter(IDocumentoCreado)
1534
... def documentoCreado(evento):
1535
... evento.doc.creado = datetime.datetime.utcnow()
1537
Esto marca al manejador como un adaptador para los eventos
1540
Ahora registraremos el manejador::
1538
1542
>>> from zope.component import getGlobalSiteManager
1539
1543
>>> gsm = getGlobalSiteManager()
1541
>>> gsm.registerHandler(documentCreated)
1545
>>> gsm.registerHandler(documentoCreado)
1543
Now, if we can create an event and use the `handle` function to call
1544
handlers registered for the event::
1547
Ahora, podemos crear un evento y usar la función `handle` para
1548
llamar a los manejadores registrados para el evento::
1546
1550
>>> from zope.component import handle
1548
>>> handle(DocumentCreated(doc))
1549
>>> doc.created.__class__.__name__
1552
>>> handle(DocumentoCreado(doc))
1553
>>> doc.creado.__class__.__name__
1553
1557
Uso de la ZCA en Zope
1554
1558
---------------------
1556
Zope Component Architecture is used in both Zope 3 and Zope 2. This
1557
chapter go through ZCA usage in Zope.
1560
La Arquitectura de Componentes de Zope se usa tanto en Zope 3 como en
1561
Zope 2. En este capítulo veremos el uso de la ZCA en Zope.
1563
The Zope Configuration Markup Language (ZCML) is an XML based
1564
configuration system for registration of components. So, instead of
1565
using Python API for registration, you can use ZCML. But to use ZCML,
1566
unfortunately, you will be required to install more dependency
1567
El Lenguaje de Marcado de Configuración de Zope (ZCML) es un sistema
1568
de configuración basado en XML para registrar componentes. Así, en
1569
lugar de usar la API Python para los registros, puedes usar ZCML.
1570
Pero para usar ZCML, desafortunadamente, necesitas instalar más
1571
paquetes de dependencias.
1569
To install these packages::
1573
Para instalar estos paquetes::
1571
1575
$ easy_install "zope.component [zcml]"
1573
To register an adapter::
1575
<configure xmlns="http://namespaces.zope.org/zope">
1578
factory=".company.EmployeeSalary"
1579
provides=".interfaces.ISalary"
1580
for=".interfaces.IEmployee"
1583
The `provides` and `for` attributes are optional, provided you have
1584
declared it in the implementation::
1586
<configure xmlns="http://namespaces.zope.org/zope">
1589
factory=".company.EmployeeSalary"
1592
If you want to register the component as named adapter, you can give a
1596
<configure xmlns="http://namespaces.zope.org/zope">
1599
factory=".company.EmployeeSalary"
1603
Utilities are also registered similarly.
1605
To register an utility::
1607
<configure xmlns="http://namespaces.zope.org/zope">
1610
component=".database.connection"
1611
provides=".interfaces.IConnection"
1614
The `provides` attribute is optional, provided you have declared it in
1615
the implementation::
1617
<configure xmlns="http://namespaces.zope.org/zope">
1620
component=".database.connection"
1623
If you want to register the component as named adapter, you can give a
1627
<configure xmlns="http://namespaces.zope.org/zope">
1630
component=".database.connection"
1631
name="Database Connection"
1634
Instead of directly using the component, you can also give a factory::
1636
<configure xmlns="http://namespaces.zope.org/zope">
1639
factory=".database.Connection"
1577
Para registrar un adaptador::
1579
<configure xmlns="http://namespaces.zope.org/zope">
1582
factory=".empresa.SalarioEmpleado"
1583
provides=".interfaces.ISalario"
1584
for=".interfaces.IEmpleado"
1587
Los atributos `provides` y `for` son opcionales, siempre que los hayas
1588
declarado en la implementación::
1590
<configure xmlns="http://namespaces.zope.org/zope">
1593
factory=".empresa.SalarioEmpleado"
1596
Si quieres registrar el componente como un adaptador con nombre,
1597
puedes darle un atributo `name`::
1600
<configure xmlns="http://namespaces.zope.org/zope">
1603
factory=".empresa.SalarioEmpleado"
1607
Las utilidades se registran de forma similar.
1609
Para registrar una utilidad::
1611
<configure xmlns="http://namespaces.zope.org/zope">
1614
component=".basedatos.conexion"
1615
provides=".interfaces.IConexion"
1618
El atributo `provides` es opcional, siempre que lo hayas declarado
1619
en la implementación::
1621
<configure xmlns="http://namespaces.zope.org/zope">
1624
component=".basedatos.conexion"
1627
Si quieres registrar el componente como una utilidad con nombre,
1628
puedes darle un atributo `name`::
1631
<configure xmlns="http://namespaces.zope.org/zope">
1634
component=".basedatos.conexion"
1635
name="Conexión de Base de Datos"
1638
En vez de usar directamente el componente, también puedes dar una
1641
<configure xmlns="http://namespaces.zope.org/zope">
1644
factory=".basedatos.Conexion"
1646
When you register components using Python API (``register*`` methods),
1647
the last registered component will replace previously registered
1648
component, if both are registered with same type of arguments. For
1649
example, consider this example::
1651
Cuando registras componentes usando la API de Python (métodos
1652
``register*``), el último componente registrado sustituirá el
1653
componente registrado anteriormente, si los dos se registran con
1654
los mismos tipos de argumentos. Por ejemplo, imagina este ejemplo::
1651
1656
>>> from zope.interface import Attribute
1652
1657
>>> from zope.interface import Interface
1691
1696
>>> getAdapter(a, IP) #doctest: +ELLIPSIS
1692
1697
<AP object at ...>
1694
If you register another adapter, the existing one will be replaced:
1699
Si registras otro adaptador, el ya hay será sustituido::
1696
1701
>>> gsm.registerAdapter(AP2)
1698
1703
>>> getAdapter(a, IP) #doctest: +ELLIPSIS
1699
1704
<AP2 object at ...>
1701
But when registering components using ZCML, the second registration
1702
will raise a conflict error. This is a hint for you, otherwise there
1703
is a chance for overriding registration by mistake. This may lead to
1704
hard to track bugs in your system. So, using ZCML is a win for the
1706
Pero cuando se registran componente usando ZCML, el segundo registro
1707
causará un error de conflicto. Esto es una ayuda para tí, si no,
1708
cabría la posibilidad de que sustituyas los registros por error. Esto
1709
podría hacer que sea dificil de encontrar errores en tu sistema. Así,
1710
usar ZCML es un avance para la aplicación.
1707
Sometimes you will be required to override existing registration.
1708
ZCML provides ``includeOverrides`` directive for this. Using this,
1709
you can write your overrides in a separate file::
1712
A veces es necesario sustituir registros existentes. ZCML ofrece una
1713
directiva ``includeOverrides`` para esto. Usándola, puedes escribir
1714
sustituciones en un fichero aparte::
1711
1716
<includeOverrides file="overrides.zcml" />
1717
Location: `zope.app.container.contained.NameChooser`
1719
This is an adapter for choosing a unique name for an object inside a
1722
The registration of adapter is like this::
1719
NameChooser (Elejidor de nombres)
1720
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1722
Situación: `zope.app.container.contained.NameChooser`
1724
Este es un adaptador para elejir un nombre único para un objeto dentro
1727
El registro del adaptador es así::
1725
1730
provides=".interfaces.INameChooser"