How to clean up old interfaces on zc.relation catalog?

徘徊边缘 提交于 2019-12-02 00:22:50

Just for reference that's how I fixed it:

While still on plone.directives.form 1.0 update your objects so that they do no longer provide the plone.directives.form.schema.Schema interface.

Then re-create the relations:

from z3c.relationfield import RelationValue
from zc.relation.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.component import getUtility
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent

logger = logging.getLogger(LOGGER)
relations_catalog = getUtility(ICatalog)
intids = getUtility(IIntIds)

relations = [rel for rel in relations_catalog.findRelations()]
len_relations = len(relations)
logger.info('Relations needed to update: {0}'.format(len_relations))

for relation in relations:
    # get the object link and the object linked
    object_with_link = relation.from_object
    object_linked_to = relation.to_object

    # remove the broken relation
    object_with_link.reference = None

    # let the catalog remove the old relation
    notify(ObjectModifiedEvent(object_with_link))

    # create a new relation
    object_linked_to_intid = intids.getId(object_linked_to)
    new_relation = RelationValue(object_linked_to_intid)
    object_with_link.reference = new_relation

    # let the catalog know about this new relation
    notify(ObjectModifiedEvent(object_with_link))

After this, stop the instance, run buildout again to update plone.directives.form to version 1.1 and voilà!

The Schema class is now in plone.supermodel.model, not plone.directives.form.schema.

However, the real problem you should try to fix is that the code is for some reason trying to store a schema in the ZODB. Pickling/unpickling Zope interfaces is not supported.

In case someone runs into this type of problem and cannot bring the old package back, here's another approach:

import transaction

from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.User import system

from Testing.makerequest import makerequest

from zope.component.hooks import setSite
from zope.globalrequest import setRequest

from zc.relation.interfaces import ICatalog
from z3c.relationfield.event import _relations
from z3c.relationfield.event import _setRelation
from zope.component import getUtility

app = makerequest(app)
newSecurityManager(None, system)
portal = app.Plone
setSite(portal)
portal.REQUEST['PARENTS'] = [portal]
portal.REQUEST.setVirtualRoot('/')
setRequest(portal.REQUEST)

THRESHOLD = 100

relations_catalog = getUtility(ICatalog)

paths = ['/'.join(r.from_object.getPhysicalPath())
         for r in relations_catalog.findRelations() if r.from_object]

relations_catalog.clear()

counter = 0
for path in paths:
    obj = app.unrestrictedTraverse(path)
    for name, relation in _relations(obj):
        _setRelation(obj, name, relation)
    counter += 1
    if counter % THRESHOLD == 0:
        transaction.savepoint()
transaction.commit()

One more option, I developed a package called collective.diversion that is designed to ease the pain of pickling errors when moving a class. Neither of the above scripts worked for me, however using collective.diversion did.

Adding the package to the buildout and including the following ZCML caused the items to be loaded, and they'll be persisted back in the correct place on write, so reindexing the catalogue should be sufficient.

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:diversion="http://namespaces.plone.org/diversion">

  <diversion:class
      old="plone.directives.form.schema.Schema"
      new="plone.supermodel.model.Schema"
      />

</configure>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!