在Plone站点中透明镜像Plone内容
项目描述
- 日期:
- 2008-01-17
- 修订版:
- 57037
摘要
此软件包提供了一种方法,可以将Plone内容实例透明地镜像到一个或多个位置。为此,我们基本上需要
在遍历中定位要镜像的内容
将定位的对象插入到遍历上下文的获取链中
为此,我们将实现Zope 3遍历机制的适配器,在此适配器中查找要镜像的内容,并将对象插入到适配上下文的获取链中。
注意事项,限制
由于我们以这种方式添加了镜像对象,Plone最终会多次重新索引对象(例如,如果在一个镜像路径上编辑对象)。这有以下后果
- 搜索 – 在搜索中,对象被列出两次,因为它
在目录中两次。在我看来,这没关系,因为这正是我们想要的,我们希望对象出现在两个地方。
- 编辑 – KSS编辑和普通编辑的镜像内容按预期工作。在
编辑时,内容将被重新索引。查看同一对象(在另一路径上可见)的用户将在页面重新加载时看到更改。这里没有什么不同寻常的。
- 删除、重命名 – 这里变得复杂。因为对象在
两次,类似 folder_listing 这样的功能会在对象不再存在的情况下在镜像路径上显示对象。我们做的只是镜像,而不是复制。我将尝试使用事件订阅者来处理这种情况。
- UID目录 – 由于对象可能被编目多次,UID
目录将包含UID多次。此外,UID目录中额外条目的目录大脑在执行getObject()时将返回None。我对这一点的确切含义尚不清楚,这很可能是UID目录中的一个错误(为什么它最初要插入UID两次?)
基本设置
此doctest所需的一些导入
>>> from zope import interface >>> from zope import component >>> from zope.app.testing import ztapi >>> from zope.publisher.browser import TestRequest
定位内容
为了定位内容,我们提供了一个接口
>>> from inquant.contentmirror.base.interfaces import IMirrorContentLocator
现在我们可以定义一个适配器,该适配器能够从其他地方定位内容
>>> class TestLocator(object): ... def __init__(self, context): ... self.context = context ... def locate( self, name): ... return self.source.get(name)
所以基本上这个适配器只需为给定名称返回一个对象。让我们试试。我们需要为此设置一些plone内容
>>> _ = self.folder.invokeFactory("Folder", "src") >>> _ = self.folder.src.invokeFactory("Document", "doc", title="Muha") >>> _ = self.folder.invokeFactory("Folder", "target")
现在我们可以提供适配器
>>> from Products.ATContentTypes.content.folder import ATFolder >>> ztapi.provideAdapter(ATFolder, ... IMirrorContentLocator, TestLocator)
并查找适配器
>>> locator = IMirrorContentLocator(self.folder.target) >>> locator.source = self.folder.src
现在我们可以通过名称获取内容
>>> locator.locate("doc") <ATDocument at /plone/Members/test_user_1_/src/doc>
好吧,这成功了。
插入(镜像)内容
基本上我们所做的就是从要镜像的内容中剥离其acquisition上下文,并将其插入目标上下文的acquisition链中。让我们试试
>>> from Acquisition import aq_inner, aq_base, aq_chain >>> obj = self.folder.src.doc >>> aq_chain(obj) [<ATDocument at /plone/Members/test_user_1_/src/doc>, <ATFolder at /plone/Members/test_user_1_/src>, ...
我们看到,obj有一个正常的acquisition链,正如我们所期望的那样。接下来,我们将伪造acquisition链,使得obj_mirrored将看起来位于目标文件夹下方
>>> obj_mirrored = aq_base(obj).__of__(self.folder.target) >>> aq_chain(obj_mirrored) [<ATDocument at /plone/Members/test_user_1_/target/doc>, <ATFolder at /plone/Members/test_user_1_/target>, ...
太棒了。
遍历
现在我们只需提供一个方法来挂钩到Plone的对象遍历机制,并修改它,以便我们可以返回镜像对象。我们将提供的遍历器使用的是IPublishTraverse接口,这是Zope 3的方式
>>> from zope.publisher.interfaces import IPublishTraverse
Zope 2过去使用__bobo_traverse__来遍历对象。如今,遍历是通过提供一个适配器到IPublishTraverse来完成的。默认遍历器是DefaultPublishTraverse,它定义在Zope 2发布者中
>>> from ZPublisher.BaseRequest import DefaultPublishTraverse
此适配器最终会调用__bobo_traverse__。因此,不再需要覆盖__bobo_traverse__了。太好了。
我们为镜像内容提供的特殊适配器将执行以下操作
尝试将遍历的上下文适配到IMirrorContentLocator,并定位当前遍历名称的内容
从定位的内容对象中剥离acquisition链,并将其插入遍历上下文的acquisition链中,并返回它
好吧,让我们试试。
首先,我们需要创建一个IPublishTraverse适配器。请注意,这是一个多适配器,它将一个接口和一个IHTTPRequest适配到IPublishTraverse
>>> class MirrorTraverse(object): ... def __init__(self,context,request): ... self.context = context ... self.request = request ... self.locator = IMirrorContentLocator(context) ... def publishTraverse(self, request, name): ... obj = locator.locate(name) ... return aq_base(aq_inner(obj)).__of__(self.context)
现在,我们想要提供适配器。虽然我们不希望覆盖默认行为。这就是我们定义一个标记接口来适配到IMirrorContentProvider的原因。我们提供适配器
>>> from inquant.contentmirror.base.interfaces import IMirrorContentProvider >>> from zope.publisher.interfaces.http import IHTTPRequest >>> ztapi.provideAdapter( ... (IMirrorContentProvider,IHTTPRequest), ... IPublishTraverse, ... MirrorTraverse)
现在我们应该能够遍历。但是,我们需要一个测试请求来调用适配器
>>> request = TestRequest() >>> IHTTPRequest.providedBy(request) True
查询ZCA以获取适配器
>>> traverser = component.getMultiAdapter( ... (self.folder.target, request), IPublishTraverse ) Traceback (most recent call last): ... ComponentLookupError: ...
哎呀!啊,我们需要首先提供IMirrorContentProvider
>>> interface.alsoProvides(self.folder.target, IMirrorContentProvider) >>> IMirrorContentProvider.providedBy(self.folder.target) True
再试一次
>>> traverser = component.queryMultiAdapter( ... (self.folder.target, request), IPublishTraverse )
啊哈!
不幸的是,为了这个测试,我们需要手动修补源。实际上,定位适配器当然会自己确定源。
>>> traverser.locator.source = self.folder.src
现在尝试遍历
>>> traverser.publishTraverse(request, "doc") <ATDocument at /plone/Members/test_user_1_/target/doc>
太好了!请注意,返回的对象似乎来自目标文件夹,但实际上位于src文件夹。
清理
删除适配器
>>> gsm = component.getGlobalSiteManager() >>> gsm.unregisterAdapter( ... MirrorTraverse, ... (IMirrorContentProvider,IHTTPRequest), ... IPublishTraverse) True >>> gsm.unregisterAdapter(TestLocator, (ATFolder,), ... IMirrorContentLocator) True
链接
Plone是一个CMS。
vim: set ft=rst tw=75 nocin nosi ai sw=4 ts=4 expandtab:
项目详情
下载文件
为您的平台下载文件。如果您不确定要选择哪个,请了解更多关于安装包的信息。
源分发
构建的发行版
inquant.contentmirror.base-0.3.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | ef886ae7dcc20bb06cfc424909995b0996acece804b4ddf27fc6c0714db50e57 |
|
MD5 | 68eb8c437e3da3ce728c427582357b1c |
|
BLAKE2b-256 | 3a6e2da66538ed7891af65b5fe475d2c4665ee33e6d8f417ec95ab044d8f194c |
inquant.contentmirror.base-0.3-py2.4.egg 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 74e46c1fa17f8482f63643fc2cfcf888082f8ba49c5db444a3ff71b21552407f |
|
MD5 | 99b83ec376376c0f0c773b946a6d8a5d |
|
BLAKE2b-256 | a44b4ae1a2b8984873cc030228b8fee99560f8171c5e589a311058ca968d2bd7 |