[Zope-CMF] upgrade to 1.3 leaves docs without portal_type

Tres Seaver tseaver@zope.com
14 Aug 2002 08:26:32 -0400


On Tue, 2002-08-13 at 09:20, george donnelly wrote:

> I found a post by Chris M on this (see below)
> < http://aspn.activestate.com/ASPN/Mail/Message/1315527 >
> 
> ... and I appreciate the tip but i wonder if someone would elaborate on how
> to turn this info into a solution. tia.
> 
> 
> "Evidently CMF 1.2 used to automatically set an object's portal_type
> to its meta_type if it didn't exist.  This no longer happens in 1.3.
> So you need to explicitly declare a portal_type on these objects.
> The simplest way to do this is "portal_type = meta_type = 'Type'"


Here is the ExternalMethod I used to fix this problem on the dogbowl:

#----------- Cut here ---------------------
$ cat Extensions/fix_portal_type.py 
def fix_portal_type( self, reportOnly=1 ): #[default_no_action]
    """
        Update old content which had no 'portal_type' attribute.
    """
    typeless_wonders = [ 'Content w/o portal_type', '' ] #[log lists]
    clueless_wonders = [ 'Content w/o Products!', '' ]

    for brain in self.portal_catalog(): #[brains_sequence]

        if not brain.portal_type: #[brains_as_cache]

            path = brain.getPath() #[catalog_rid]

            if brain.Type:
                typeless_wonders.append( '%-50s (%-15s, %-15s)'
                                       % ( path
                                         , brain.Type
                                         , brain.meta_type
                                         ) )
                if not reportOnly:

                    content = brain.getObject() #[wake_up_time]

                    try:
                        fixer = content._setPortalTypeName
                    except AttributeError:  #[compatibility_sux]
                        content.portal_type = brain.Type
                        typeless_wonders[-1] += ' !!'
                    else:
                        fixer( brain.Type )

                    content.reindexObject() #[keep_catalog_in_sync]

            else: #[broken_object]

                tokens = path.split( '/' ) #[find_parent]
                parent, clueless = tokens[ :-1 ], tokens[ -1 ]
                clueless_wonders.append( '%-50s: %s'
                                       % ( '/'.join( parent )
                                         , clueless ) )

                if not reportOnly:

                    parent = self.restrictedTraverse( parent )
                    parent._delOb( clueless )
                    self.portal_catalog.uncatalog_object( path )#[redux]

    summary = []
    summary.extend( typeless_wonders )
    summary.append( '' )
    summary.append( '' )
    summary.extend( clueless_wonders )
    return '\n'.join( summary )
#----------- Cut here ---------------------

Notes:

  default_no_action -- By default, the method is just a report, and
    changes nothing;  it can therefore be used to check that you
    actually have a problem.

  log_lists -- Stash logging in a Python list, and concatenate at the
    end (much cheaper than building up a string;  also permits
    some clever hacking).

  brains_sequence -- a catalog query returns a sequence of brains;  in
    this case, with no criteria, it returns a brain for *every* object
    the catalog knows about.  Brains hold cached attributes from the
    catalog's "metadata schema" table, and provide access to the
    underlying object via 'getObject'.  Note as well that you need
    to reindex everything after adding 'portal_type', or nobody will
    have a real value in the catalog!

  catalog_rid -- the object's physical path serves as its "record ID"
    within the catalog;  stash it for use later.

  wake_up_time -- 'getObject' actually un-ghostifies the object from
    the ZODB, which is *much* more expensive than accessing the brain.

  compatibility_sux -- on the dogbowl, at least, there were a couple of
    objects which didn't have the '_setPortalTypeName' method, so work
    around it.

  keep_catalog_in_sync -- must reindex manually, as '_setPortalTypeName'
    might not.

  broken_object -- if it doesn't have 'portal_type' or 'Type', then it
    is a "Broken" object (on the dogbowl, this was content whose
    product was no longer there);  it should be removed from the ZODB.

  find_parent -- use traversal to get the broken object's parent.

  redux -- since the object is broken, it's 'manage_beforeDelete' won't
    fire, so we need to remove it ourselves using the path as RID.

Tres.
-- 
===============================================================
Tres Seaver                                tseaver@zope.com
Zope Corporation      "Zope Dealers"       http://www.zope.com