Хэндлеры ZCML директив.txt
2008-01-11 18:59Директивы ZCML пишутся в двух случаях: - Сравнительно редко, директива пишется для того, чтобы добавить какие-то принципиально новые возможности конфигурации; - Значительно чаще, директива ZCML пишется для того, чтобы стандартизовать некоторую, часто повторяющуюся, последовательность кодирования и настроек. список полей), handler -- обработчик директивы. import ICommonFormInformation class IAnnotationEditDirective(ICommonFormInformation): """Create form for annotation object """ Очевидно, это обычный интерфейс, порожденный от ICommonFormInformation, в который не было добавлено ни одного своего поля. ...
Хендлеры ZCML-директив:
Любая ZCML директива состоит из двух частей: схемы директивы, определяющей сколько и каких параметров может быть передано в директиву, и хендлера (обработчика) директивы, т.е. того самого программного кода, который выполнит то, что предписывается директивой.

Директивы ZCML пишутся в двух случаях:
- Сравнительно редко, директива пишется для того, чтобы добавить какие-то принципиально новые возможности конфигурации;
- Значительно чаще, директива ZCML пишется для того, чтобы стандартизовать некоторую, часто повторяющуюся, последовательность кодирования и настроек.
В последнем случае, директива, фактически, является оберткой вокруг нескольких других директив zcml. Таким образом, нужно помнить, что если приходится выполнять какие-то действия по программированию и настройке очень часто, то имеет смысл подумать о том, чтобы сделать специальную директиву zcml.
Чтобы привести пример такой директивы, попробуем написать директиву, выполняющую создание вида для аннотации объекта (см. zcmlannotation).
Такой вид может быть создан при помощи специальной директивы form, которая потребует создать класс для доступа к данным (noteannotable.browser.edit.Edit). Как нетрудно заметить, этот класс легко параметризуется, т.е. можно написать специальную фабрику, создающую такой класс, вот ее текст:
# Фабрика класса для доступа к данным
from zope.schema import getFieldNames
def editfactory (schema) :
class Edit(object) :
def getData(self, *kv, **kw) :
self.na = schema(self.context)
return [(x, getattr(self.na, x)) for x in getFieldNames(schema)]
def setData(self,d,**kw) :
for x in getFieldNames(schema) :
setattr(self.na, x, d[x])
return True
return Edit
Функция editfactory порождает класс, обеспечивающий доступ к данным через любую указанную схему.
Теперь займемся декларацией директивы. Создадим файл meta.zcml, в котором опишем директиву:
<configure
xmlns="http://namespaces.zope.org/meta">
<directives namespace="http://namespaces.zope.org/browser">
<complexDirective
name="annotationedit"
schema=".metadirectives.IAnnotationEditDirective"
handler=".metaconfigure.AnnotationEditDirective">
<subdirective
name="widget"
schema="zope.app.form.browser.metadirectives.IWidgetSubdirective"
/>
</complexDirective>
</directives>
</configure>
Сразу заметим, что это практически копия аналогичного файла, взятого из декларации директивы form (которая будет перекрыта, как уже было сказано выше). Здесь в декларации complexDirective указаны:
- name
- имя директивы,
- schema
- схема директивы (т.е. список полей),
- handler
- обработчик директивы.
Описание для subdirective аналогично, хотя к нам не имеет отношения - это адаптированная версия для директивы form. При чуть большем везении можно было бы использовать простую директиву (определяется декларацией directive), которая имела бы те же поля.
Посмотрим на описание схемы директивы:
# Схема метадирективы
from zope.app.form.browser.metadirectives import ICommonFormInformation
class IAnnotationEditDirective(ICommonFormInformation):
"""Create form for annotation object """
Очевидно, это обычный интерфейс, порожденный от ICommonFormInformation, в который не было добавлено ни одного своего поля. В принципе, можно было вообще использовать ICommonFormInformation.
Ну и, наконец, обработчик директивы:
# Обработчик директивы ZCML
from zope.app.form.browser.metaconfigure import FormDirective
from factory import editfactory
class AnnotationEditDirective(FormDirective):
"""Create form for annotation object """
def __init__(self, _context, schema, **kwargs):
super(AnnotationEditDirective, self) \
.__init__(_context,
class_=editfactory(schema),
schema=schema,**kwargs)
Все, что здесь делается, это перекрывается обработчик директивы form и автоматически сгенерированный класс для доступа к данным принудительно вставляется в его параметры.
Посмотрим как используется данная директива: в каталоге zcmlannotation.demo, лежит файл configure.zcml декларирующий при помощи этой директивы вид Annotation Auto:
<configure
xmlns="http://namespaces.zope.org/browser">
<annotationedit
schema="noteannotation.interfaces.INoteAnnotation"
for="noteannotation.interfaces.INoteAnnotable"
label="Annotation Auto"
name="annotation_auto.html"
permission="zope.ManageContent"
menu="zmi_views" title="Annotation Auto"
/>
</configure>
Не слишком отличается от старого варианта, но специальный класс писать уже не пришлось. Можно доработать данную директиву, так, чтобы автоматически генерировался адаптер NoteAnnotableAdapter.
Благодаря тому, что использовалось перекрытие над существующими директивами, не была замечена одна особенность: обработчик директивы должен проверять свои параметры до выполнения всех директив, и только потом делать собственно выполнение. В случае разработанной директивы annotationedit это не понадобилось, так как это сделали перекрытые суперклассы. До тех пор, пока директивы не разрабатываются с нуля, про эту особенность можно забыть, хотя вообще говоря, для ее реализации существует специальная техника.



