Sophie

Sophie

distrib > Mandriva > 9.1 > ppc > by-pkgid > 5fc119ab9a896fc2c0f998627bed1487 > files > 10

zope-docs-2.6.1-5mdk.ppc.rpm

<html>
<head>
<title>Chapter 14: Extending Zope</title>
</head>
<body bgcolor="#FFFFFF">
<h1>Chapter 14: Extending Zope</h1>
<p>  You can extend Zope by creating your own types of objects that are
  customized to your applications needs.  New kinds of objects are
  installed in Zope by <em>Products</em>.  Products are extensions to Zope that
  Zope Corporation and many other third party developers create.  There
  are hundreds of different Products and many serve very specific
  purposes.  A complete library of Products is at the <a href="http://www.zope.org/Products/">Download
  Section</a>. of Zope.org.</p><p>  Products can be developed two ways, <em>through the web</em> using
  ZClasses, and in the Python programming language. Products can even
  be a hybrid of both through the web products and Python code.  This
  chapter discusses building new products through the web, a topic
  which you've already have some brief exposure to in Chapter 11,
  "Searching and Categorizing Content".  Developing a Product entirely
  in Python product programming is the beyond its scope and you should
  visit Zope.org for specific Product developer documentation.</p><p>  This chapter shows 
  you how to:<ul>
<li>Create new Products in Zope</li>
<li>Define ZClasses in Products</li>
<li>Integrating Python with ZClasses</li>
<li>Distribute Products to other Zope users</li>
</ul>
</p><p>  The first step in customizing Zope starts in the next section, where
  you learn how to create new Zope Products.</p><h2>  Creating Zope Products</h2>
<p>    Through the web Products are stored in the <em>Product Management</em>
    folder in the Control Panel.  Click on the <em>Control_Panel</em> in the
    root folder and then click <em>Products</em>.  You are now in the screen
    shown in <a href="#12-1">Figure 12-1</a>.</p><p>    <a name="12-1"></a>
<img src="Figures/12-1.png" alt="Installed Products">
<p><b>Figure 12-1</b> Installed Products</p>
</p><p>    Each blue box represents an installed Product. From this screen,
    you can manage these Products.  Some Products are built into Zope
    by default or have been installed by you or your administrator.
    These products have a <em>closed</em> box icon, as shown in <a href="#12-1">Figure 12-1</a>.
    Closed-box products cannot be managed through the web. You can get
    information about these products by clicking on them, but you
    cannot change them.</p><p>    You can also create your own Products that you <em>can</em> manage
    through the web. Your products let you create new kinds of objects
    in Zope.  These through the web managable product have open-box
    icons.  If you followed the examples in Chapter 11, "Searching and
    Categorizing Content", then you have a <em>News</em> open-box product.</p><p>    Why do you want to create products?  For example, all of the
    various caretakers in the Zoo want an easy way to build simple
    on-line exhibits about the Zoo.  The exhibits must all be in the
    same format and contain similar information structure, and each
    will be specific to a certain animal in the Zoo.</p><p>    To accomplish this, you could build an exhibit for one animal, and
    then copy and paste it for each exhibit, but this would be a
    difficult and manual process.  All of the information and
    properties would have to be changed for each new exhibit.
    Further, there may be thousands of exhibits. </p><p>    To add to this problem, let's say you now want to have information
    on each exhibit that tells whether the animal is endangered or
    not.  You would have to change each exhibit, one by one, to do
    this by using copy and paste.  Clearly, copying and pasting does
    not scale up to a very large zoo, and could be very expensive.</p><p>    You also need to ensure each exhibit is easy to manage.  The
    caretakers of the individual exhibits should be the ones providing
    information, but none of the Zoo caretakers know much about Zope
    or how to create web sites and you certainly don't want to waste
    their time making them learn.  You just want them to type some
    simple information into a form about their topic of interest,
    click submit, and walk away.</p><p>    By creating a Zope product, you can acomplish these goals quickly
    and easily.  You can create easy to manage objects that your
    caretakers can use.  You can define exhibit templates that you can
    change once and effect all of the exhibits.  You can do these
    things by creating Zope Products.</p><h2>  Creating A Simple Product</h2>
<p>    Using Products you can solve the exhibit creation and management
    problems. Let's begin with an example of how to create a simple
    product that will allow you to collect information about
    exhibits and create a customized exhibit. Later in the chapter
    you see more complex and powerful ways to use products.</p><p>    The chief value of a Zope product is that it allows you to
    create objects in a central location and it gives you access to
    your objects through the product add list. This gives you the
    ability to build global services and make them available via a
    standard part of the Zope management interface. In other words a
    Product allows you to customize Zope.</p><p>    Begin by going to the <em>Products</em> folder in the <em>Control Panel</em>.
    To create a new Product, click the <em>Add Product</em> button on the <em>Product
    Management</em> folder.  This will take you to the Product add form.
    Enter the id "ZooExhibit" and click <em>Generate</em>.  You will now
    see your new Product in the <em>Product Management</em> folder.  It
    should be a blue box with an open lid.  The open lid means you
    can click on the Product and manage it through the web.</p><p>    Select the <em>ZooExhibit</em> Product.  This will take you to the Product
    management screen.</p><p>    The management screen for a Product looks and acts just like a Folder
    except for a few differences:<ol>
<li> There is a new view, called <em>Distribution</em>, all the way to the
         right.  This gives you the ability to package and distribute your
         Product.  This is discussed later.</li>
<li> If you select the add list, you will see some new types of objects
         you can add including <em>ZClass</em>, <em>Factory</em>, and <em>Permission</em>.</li>
<li> The folder with a question mark on it is the <em>ZooExhibit</em>
         Product's <em>Help Folder</em>.  This folder can contain <em>Help
         Topics</em> that tell people how to use your Product.</li>
<li> There is also a new view <em>Define Permissions</em> that define
         the permissions associated with this Product.  This is
         advanced and is not necessary for this example.</li>
</ol>
</p><p>    In the <em>Contents</em> View create a DTML Method named <em>hello</em> with
    these contents:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;h2&gt;Hello from the Zoo Exhibit Product&lt;/h2&gt;

      &lt;dtml-var standard_html_footer&gt; </pre>
</p><p>    This method will allow you to test your product. Next create a
    Factory. Select <em>Zope Factory</em> from the product add list. You
    will be taken to a Factory add form as shown in <a href="#12-2">Figure 12-2</a>.</p><p>    <a name="12-2"></a>
<img src="Figures/12-2.png" alt="Adding A Factory">
<p><b>Figure 12-2</b> Adding A Factory</p>
</p><p>    Factories create a bridge from the product add list to your
    Product. Give your Factory an id of <em>myFactory</em>. In the <em>Add
    list name</em> field enter <em>Hello</em> and in the <em>Method</em> selection,
    choose <em>hello</em>. Now click <em>Generate</em>. Now click on the new
    Factory and change the <em>Permission</em> to <em>Add Document, Images,
    and Files</em> and click on <em>Save Changes</em>. This tells Zope that you
    must have the <em>Add Documents, Images, and Files</em> permission to
    use the Factory.  Congratulations, you've just customized the
    Zope management interface. Go to the root folder and click the
    product add list. Notice that it now includes an entry named
    <em>Hello</em>. Choose <em>Hello</em> from the product add list. It calls your
    <em>hello</em> method.</p><p>    One of the most common things to do with methods that you link
    to with Factories is to copy objects into the current Folder. In
    other words your methods can get access to the location from
    which they were called and can then perform operations on that
    Folder including copy objects into it. Just because you can do
    all kinds of crazy things with Factories and Products doesn't
    mean that you should. In general people expect that when they
    select something from the product add list that they will be
    taken to an add form where they specify the id of a new
    object. Then they expect that when they click <em>Add</em> that a new
    object with the id they specified will be created in their
    folder. Let's see how to fulfill these expectations.</p><p>    First create a new Folder named <em>exhibitTemplate</em> in your
    Product. This will serve as a template for exhibits. Also in the
    Product folder create a DTML Method named <em>addForm</em>, and Python
    Script named <em>add</em>. These objects will create new exhibit instances.
    Now go back to your Factory and change it so that the <em>Add list name</em>
    is <em>Zoo Exhibit</em> and the method is <em>addForm</em>.</p><p>    So what's going to happen is that when someone chooses <em>Zoo Exhibit</em>
    from the product add list, the <em>addForm</em> method will run. This method
    should collect information about the id and title of the
    exhibit. When the user clicks <em>Add</em> it should call the <em>add</em> script
    that will copy the <em>exhibitTemplate</em> folder into the calling folder
    and will rename it to have the specified id.  The next step is to
    edit the <em>addForm</em> method to have these contents:<pre>      &lt;dtml-var manage_page_header&gt;

        &lt;h2&gt;Add a Zoo Exhibit&lt;/h2&gt;

        &lt;form action=&quot;add&quot; method=&quot;post&quot;&gt;
        id &lt;input type=&quot;text&quot; name=&quot;id&quot;&gt;&lt;br&gt;
        title &lt;input type=&quot;text&quot; name=&quot;title&quot;&gt;&lt;br&gt;
        &lt;input type=&quot;submit&quot; value=&quot; Add &quot;&gt;
        &lt;/form&gt;

      &lt;dtml-var manage_page_footer&gt;</pre>
</p><p>    Admittedly this is a rather bleak add form. It doesn't collect
    much data and it doesn't tell the user what a Zoo Exhibit is and
    why they'd want to add one. When you create your own web
    applications you'll want to do better than this example.</p><p>    Notice that this method doesn't include the standard HTML headers
    and footers. By convention Zope management screens don't use the
    same headers and footers that your site uses. Instead management
    screens use <code>manage_page_header</code> and <code>manage_page_footer</code>. The
    management view header and footer ensure that management views
    have a common look and feel.</p><p>    Also notice that the action of the form is the <em>add</em> script.  Now
    paste the following body into the <em>add</em> script:<pre>      ## Script (Python) &quot;add&quot;
      ##parameters=id ,title, REQUEST=None
      ##
      &quot;&quot;&quot;
      Copy the exhibit template to the calling folder
      &quot;&quot;&quot;

      # Clone the template, giving it the new ID. This will be placed
      # in the current context (the place the factory was called from).
      exhibit=context.manage_clone(container.exhibitTemplate,id)

      # Change the clone's title
      exhibit.manage_changeProperties(title=title)

      # If we were called through the web, redirect back to the context
      if REQUEST is not None:
          try: u=context.DestinationURL()
          except: u=REQUEST['URL1']
          REQUEST.RESPONSE.redirect(u+'/manage_main?update_menu=1')</pre>
</p><p>    This script clones the <em>exhibitTemplate</em> and copies it to the
    current folder with the specified id. Then it changes the
    <em>title</em> property of the new exhibit. Finally it returns the
    current folder's main management screen by calling
    <em>manage_main</em>.</p><p>    Congratulations, you've now extended Zope by creating a new
    product. You've created a way to copy objects into Zope via the
    product add list. However, this solution still suffers from some
    of the problems we discussed earlier in the chapter. Even though
    you can edit the exhibit template in a centralized place, it's
    still only a template. So if you add a new property to the
    template, it won't affect any of the existing exhibits. To
    change existing exhibits you'll have to modify each one
    manually. </p><p>    ZClasses take you one step farther by allowing you to have one
    central template that defines a new type of object, and when you
    change that template, all of the objects of that type change
    along with it.  This central template is called a ZClass.  In
    the next section, we'll show you how to create ZClasses that
    define a new <em>Exhibit</em> ZClass.</p><h2>  Creating ZClasses</h2>
<p>    ZClasses are tools that help you build new types of objects in
    Zope by defining a <em>class</em>.  A class is like a blueprint for
    objects.  When defining a class, you are defining what an object
    will be like when it is created.  A class can define methods,
    properties, and other attributes.</p><p>    Objects that you create from a certain class are called <em>instances</em>
    of that class.  For example, there is only one <em>Folder</em> class, but
    you many have many Folder instances in your application.</p><p>    Instances have the same methods and properties as their class.  If
    you change the class, then all of the instances reflect that
    change.  Unlike the templates that you created in the last
    section, classes continue to exert control over instances.  Keep
    in mind this only works one way, if you change an instance, no
    changes are made to the class or any other instances.</p><p>    A good real world analogy to ZClasses are word processor templates.
    Most word processors come with a set of predefined templates that you
    can use to create a certain kind of document, like a resume.  There may
    be hundreds of thousands of resumes in the world based on the Microsoft
    Word Resume template, but there is only one template.  Like the Resume
    template is to all those resumes, a ZClass is a template for any number
    of similar Zope objects.</p><p>    ZClasses are classes that you can build through the web using Zope's
    management interface.  Classes can also be written in Python, but
    this is not covered in this book.</p><p>    ZClasses can inherit attributes from other classes.  Inheritance allows
    you to define a new class that is based on another class.  For example,
    say you wanted to create a new kind of document object that had special
    properties you were interested in.  Instead of building all of the
    functionality of a document from scratch, you can just <em>inherit</em> all of
    that functionality from the <em>DTML Document</em> class and add only the new
    information you are interested in.</p><p>    Inheritance also lets you build generalization relationships
    between classes.  For example, you could create a class called
    <code>Animal</code> that contains information that all animals have in
    general.  Then, you could create <em>Reptile</em> and <em>Mammal</em> classes
    that both inherit from <em>Animal</em>.  Taking it even further, you
    could create two additional classes <em>Lizard</em> and <em>Snake</em> that both
    inherit from <em>Reptile</em>, as shown in <a href="#12-3">Figure 12-3</a>.</p><p>    <a name="12-3"></a>
<img src="Figures/12-3.png" alt="Example Class Inheritance">
<p><b>Figure 12-3</b> Example Class Inheritance</p>
</p><p>    ZClasses can inherit from most of the objects you've used in this
    book.  In addition, ZClasses can inherit from other ZClasses defined
    in the same Product.  We will use this technique and others in this
    chapter.</p><p>    Before going on with the next example, you should rename the
    existing <em>ZooExhibit</em> Product in your Zope Products folder to
    something else, like <em>ZooTemplate</em> so that it does not conflict
    with this example. Now, create a new Product in the Product folder
    called <em>ZooExhibit</em>.</p><p>    Select <em>ZClass</em> from the add list of the <em>ZooExhibit</em> Contents
    view and go to the ZClass add form.  This form is complex, and has
    lots of elements.  We'll go through them one by one:<dl>
<dt>      Id</dt>
<dd>This is the name of the class to create.  For this
      example, choose the name <em>ZooExhibit</em>.</dd>
<dt>      Meta Type</dt>
<dd>The Meta Type of an object is a name for the type of
      this object.  This should be something short but descriptive about
      what the object does.  For this example, choose the meta type "Zoo
      Exhibit".</dd>
<dt>      Base Classes</dt>
<dd>Base classes define a sequence of classes that you
      want your class to inherit attributes from.  Your new class can be
      thought of as <em>extending</em> or being <em>derived from</em> the functionality
      of your base classes.  You can choose one or more classes from the
      list on the left, and click the <code>-&gt;</code> button to put them in your base
      class list.  The <code>&lt;-</code> button removes any base classes you select on
      the right.  For this example, don't select any base classes.  Later
      in this chapter, we'll explain some of the more interesting base
      classes, like <em>ObjectManager</em>.</dd>
<dt>      Create constructor objects?</dt>
<dd>You usually want to leave this
      option checked unless you want to take care of creating
      form/action constructor pairs and a Factory object yourself.  If
      you want Zope to do this task for you, leave this checked.
      Checking this box means that this add form will create five
      objects, a Class, a Constructor Form, a Constructor Action, a
      Permission, and a Factory.  For this example, leave this box
      checked.</dd>
<dt>      Include standard Zope persistent object base classes?</dt>
<dd>This
      option should be checked unless you don't want your object to be
      saved in the database.  This is an advanced option and should
      only be used for Pluggable Brains.  For this example, leave this
      box checked.</dd>
</dl>
</p><p>    Now click <em>Add</em>.  This will take you back to the <em>ZooExhibit</em> Product
    and you will see five new objects, as shown in <a href="#12-4">Figure 12-4</a>.</p><p>    <a name="12-4"></a>
<img src="Figures/12-4.png" alt="Product with a ZClass">
<p><b>Figure 12-4</b> Product with a ZClass</p>
</p><p>    The five objects Zope created are all automatically configured to work
    properly, you do not need to change them for now.  Here is a brief
    description of each object that was created:<dl>
<dt>      <em>ZooExhibit</em></dt>
<dd>This is the ZClass itself.  It's icon is a white box
      with two horizontal lines in it.  This is the traditional symbol for
      a <em>class</em>.</dd>
<dt>      <em>ZooExhibit_addForm</em></dt>
<dd>This DTML Method is the constructor form for
      the ZClass.  It is a simple form that accepts an id and title.  You
      can customize this form to accept any kind of input your new object
      requires.  The is very similar to the add form we created in the
      first example.</dd>
<dt>      <em>ZooExhibit_add</em></dt>
<dd>This DTML Method gets called by the
      constructor form, <em>ZooExhibit_addForm</em>.  This method actually
      creates your new object and sets its <em>id</em> and <em>title</em>.  You can
      customize this form to do more advanced changes to your object
      based on input parameters from the <em>ZooExhibit_addForm</em>.  This
      has the same functionality as the Python script we created in
      the previous example.</dd>
<dt>      <em>ZooExhibit_add_permission</em></dt>
<dd>The curious looking stick-person
      carrying the blue box is a <em>Permission</em>.  This defines a
      permission that you can associate with adding new <em>ZooExhibit</em>
      objects.  This lets you protect the ability to add new Zoo
      exhibits.  If you click on this Permission, you can see the name
      of this new permission is "Add ZooExhibits".</dd>
<dt>      <em>ZooExhibit_factory</em></dt>
<dd>The little factory with a smokestack
      icon is a <em>Factory</em> object.  If you click on this object, you
      can change the text that shows up in the add list for this
      object in the <em>Add list name</em> box.  The <em>Method</em> is the method
      that gets called when a user selects the <em>Add list name</em> from
      the add list.  This is usually the constructor form for your
      object, in this case, <em>ZooExhibit_addForm</em>.  You can associate
      the Permission the user must have to add this object, in this
      case, <em>ZooExhibit_add_permission</em>.  You can also specify a
      regular Zope permission instead.</dd>
</dl>
</p><p>    That's it, you've created your first ZClass.  Click on the new ZClass
    and click on its <em>Basic</em> tab.  The <em>Basic</em> view on your ZClass lets
    you change some of the information you specified on the ZClass add
    form.  You cannot change the base classes of a ZClass. As you learned
    earlier in the chapter, these settings include:<dl>
<dt>      meta-type</dt>
<dd>The name of your ZClass as it appears in the
      product add list.</dd>
<dt>      class id</dt>
<dd>A unique identifier for your class. You should
      only change this if you want to use your class definition for
      existing instances of another ZClass. In this case you should
      copy the class id of the old class into your new class.</dd>
<dt>      icon</dt>
<dd>The path to your class's icon image. There is little
      reason to change this. If you want to change your class's
      icon, upload a new file with the <em>Browse</em> button.</dd>
</dl>
</p><p>    At this point, you can start creating new instances of the <em>ZooExhibit</em>
    ZClass.  First though, you probably want a common place where all
    exhibits are defined, so go to your root folder and select <em>Folder</em>
    from the add list and create a new folder with the id "Exhibits".  Now,
    click on the <em>Exhibits</em> folder you just created and pull down the Add
    list.  As you can see, <em>ZooExhibit</em> is now in the add list.</p><p>    Go ahead and select <em>ZooExhibit</em> from the add list and create a
    new Exhibit with the id "FangedRabbits".  After creating the new
    exhibit, select it by clicking on it.</p><p>    As you can see your object already has three views, <em>Undo</em>,
    <em>Ownership</em>, and <em>Security</em>.  You don't have to define these parts of
    your object, Zope does that for you.  In the next section, we'll add
    some more views for you to edit your object.</p><h3>    Creating Views of Your ZClass</h3>
<p>      All Zope objects are divided into logical screens called <em>Views</em>.
      Views are used commonly when you work with Zope objects in the
      management interface, the tabbed screens on all Zope objects are
      views.  Some views like <em>Undo</em>, are standard and come with Zope.</p><p>      Views are defined on the <em>Views</em> view of a ZClass.  Go to your
      <em>ZooExhibit</em> ZClass and click on the <em>Views</em> tab.  The <em>Views</em> view
      looks like <a href="#12-5">Figure 12-5</a>.</p><p>      <a name="12-5"></a>
<img src="Figures/12-5.png" alt="The Views view.">
<p><b>Figure 12-5</b> The Views view.</p>
</p><p>      On this view you can see the three views that come automatically with
      your new object, <em>Undo</em>, <em>Ownership</em>, and <em>Security</em>.  They are
      automatically configured for you as a convenience, since almost all
      objects have these interfaces, but you can change them or remove them
      from here if you really want to (you generally won't).</p><p>      The table of views is broken into three columns, <em>Name</em>, <em>Method</em>,
      and <em>Help Topic</em>.  The <em>Name</em> is the name of the view and is the
      label that gets drawn on the view's tab in the management interface.
      The <em>Method</em> is the method of the class or property sheet that gets
      called to render the view.  The <em>Help Topic</em> is where you associate a
      <em>Help Topic</em> object with this view.  Help Topics are explained more
      later.</p><p>      Views also work with the security system to make sure users only see
      views on an object that they have permission to see.  Security will
      be explained in detail a little further on, but it is good to know at
      this point that views now only divide an object management interfaces
      into logical chunks, but they also control who can see which view.</p><p>      The <em>Method</em> column on the Methods view has select boxes that let you
      choose which method generates which view.  The method associated with
      a view can be either an object in the <em>Methods</em> view, or a Property
      Sheet in the <em>Property Sheets</em> view.</p><h3>    Creating Properties on Your ZClass </h3>
<p>      Properties are collections of variables that your object uses to
      store information.  A Zoo Exhibit object, for example, would need
      properties to contain information about the exhibit, like what animal
      is in the exhibit, a description, and who the caretakers are.</p><p>      Properties for ZClasses work a little differently than properties on
      Zope objects.  In ZClasses, Properties come in named groups called
      <em>Property Sheets</em>.  A Property Sheet is a way of organizing a related
      set of properties together.  Go to your <em>ZooExhibit</em> ZClass and click
      on the <em>Property Sheets</em> tab.  To create a new sheet, click <em>Add
      Common Instance Property Sheet</em>.  This will take you to the Property
      Sheet add form.  Call your new Property Sheet "ExhibitProperties" and
      click <em>Add</em>.</p><p>      Now you can see that your new sheet, <em>ExhibitProperties</em>, has  been
      created in the <em>Property Sheets</em> view of your ZClass.  Click on the
      new sheet to manage it, as shown in <a href="#12-6">Figure 12-6</a>.</p><p>      <a name="12-6"></a>
<img src="Figures/12-6.png" alt="A Property Sheet">
<p><b>Figure 12-6</b> A Property Sheet</p>
</p><p>      As you can see, this sheet looks very much like the <em>Properties</em> view
      on Zope objects.  Here, you can create new properties on this sheet.
      Properties on Property Sheets are exactly like Properties on Zope
      objects, they have a name, a type, and a value.  </p><p>      Create three new properties 
      on this sheet:<dl>
<dt>        <em>animal</em></dt>
<dd>This property should be of type <em>string</em>.  It will hold
        the name of the animal this exhibit features.</dd>
<dt>        <em>description</em></dt>
<dd>This property should be of type <em>text</em>.  It will
        hold the description of the exhibit.</dd>
<dt>        <em>caretakers</em></dt>
<dd>This property should be of type <em>lines</em>.  It will
        hold a list of names for the exhibit caretakers.</dd>
</dl>
</p><p>      Property Sheets have two uses.  As you've seen with this example,
      they are a tool for organizing related sets of properties about your
      objects, second to that, they are used to generate HTML forms and
      actions to edit those set of properties.  The HTML edit forms are
      generated automatically for you, you only need to associate a view
      with a Property Sheet to see the sheet's edit form.  For example,
      return to the ZooExhibit ZClass and click on the <em>Views</em> tab and
      create a new view with the name <em>Edit</em> and associate it with the
      method <em>propertysheets/ExhibitProperties/manage_edit</em>.</p><p>      Since you can use Property Sheets to create editing screens you
      might want to create more than one Property Sheet for your
      class. By using more than one sheet you can control which
      properties are displayed together for editing purposes. You can
      also separate private from public properties on different sheets
      by associating them with different permissions.</p><p>      Now, go back to your <em>Exhibits</em> folder and either look at an existing
      <em>ZooExhibit</em> instance or create a new one.  As you can see, a new
      view called <em>Edit</em> has been added to your object, as shown in Figure
      <a href="#12-7">Figure 12-7</a>.</p><p>      <a name="12-7"></a>
<img src="Figures/12-7.png" alt="A ZooExhibit Edit view">
<p><b>Figure 12-7</b> A ZooExhibit Edit view</p>
</p><p>      This edit form has been generated for you automatically.  You only
      needed to create the Property Sheet, and then associate that sheet
      with a View.  If you add another property to the <em>ExhibitProperties</em>
      Property Sheet, all of your instances will automatically get a new
      updated edit form, because when you change a ZClass, all of the
      instances of that class inherit the change.</p><p>      It is important to understand that changes made to the class are
      reflected by all of the instances, but changes to an instance are
      <em>not</em> reflected in the class or in any other instance.  For example,
      on the <em>Edit</em> view for your <em>ZooExhibit</em> instance (<em>not</em> the class),
      enter "Fanged Rabbit" for the <em>animal</em> property, the description
      "Fanged, carnivorous rabbits plagued early medieval knights.  They
      are known for their sharp, pointy teeth." and two caretakers,
      "Tim" and "Somebody Else".  Now click <em>Save Changes</em>.</p><p>      As you can see, your changes have obviously effected this instance,
      but what happened to the class?  Go back to the <em>ZooExhibit</em> ZClass
      and look at the <em>ExhibitProperties</em> Property Sheet.  Nothing has
      changed!  Changes to instances have no effect on the class.</p><p>      You can also provide default values for properties on a Property
      Sheet.  You could, for example, enter the text "Describe your exhibit
      in this box" in the <em>description</em> property of the <em>ZooExhibit</em>
      ZClass.  Now, go back to your <em>Exhibits</em> folder and create a <em>new</em>
,      <em>ZooExhibit</em> object and click on its <em>Edit</em> view.  Here, you see that
      the value provided in the Property Sheet is the default value for the
      instance.  Remember, if you change this instance, the default value
      of the property in the Property Sheet is <em>not</em> changed.  Default
      values let you set up useful information in the ZClass for properties
      that can later be changed on an instance-by-instance basis.</p><p>      You may want to go back to your ZClass and click on the <em>Views</em>
      tab and change the "Edit" view to be the first view by clicking
      the <em>First</em> button.  Now, when you click on your instances, they
      will show the Edit view  first.</p><h3>    Creating Methods on your ZClass</h3>
<p>      The <em>Methods</em> View of your ZClass lets you define the methods for the
      instances of your ZClass.  Go to your <em>ZooExhibit</em> ZClass and click
      on the <em>Methods</em> tab.  The <em>Methods</em> view looks like <a href="#12-8">Figure 12-8</a>.</p><p>      <a name="12-8"></a>
<img src="Figures/12-8.png" alt="The Methods View">
<p><b>Figure 12-8</b> The Methods View</p>
</p><p>      You can create any kind of Zope object on the <em>Methods</em> view,
      but generally only callable objects (DTML Methods and Scripts,
      for example) are added.</p><p>      Methods are used 
      for several purposes:<dl>
<dt>        Presentation</dt>
<dd>When you associate a view with a method, the
        method is called when a user selects that view on an instance.  For
        example, if you had a DTML Method called <em>showAnimalImages</em>, and a
        view called <em>Images</em>, you could associate the <em>showAnimalImages</em>
        method with the <em>Images</em> view.  Whenever anyone clicked on the
        <em>Images</em> view on an instance of your ZClass, the <em>showAnimalImages</em>
        method would get called.</dd>
<dt>        Logic</dt>
<dd>Methods are not necessarily associated with
        views.  Methods are often created that define how you can work with
        your object.  <p>          For example, consider the <em>isHungry</em> method of the
          <em>ZooExhibit</em> ZClass defined later in this section. It does
          not define a view for a <em>ZooExhibit</em>, it just provide very
          specific information about the <em>ZooExhibit</em>.  Methods in a
          ZClass can call each other just like any other Zope methods,
          so logic methods could be <em>used</em> from a presentation method,
          even though they don't <em>define</em> a view.</p></dd>
<dt>        Shared Objects</dt>
<dd>As was pointed out earlier, you can create
        any kind of object on the <em>Methods</em> view of a ZClass.  All
        instances of your ZClass will <em>share</em> the objects on the
        Methods view.  For example, if you create a <em>Z Gadfly
        Connection</em> in the Methods view of your ZClass, then all
        instances of that class will share the same Gadfly connection.
        Shared objects can be useful to your class's logic or
        presentation methods.</dd>
</dl>
</p><p>      A good example of a presentation method is a DTML Method that
      displays a Zoo Exhibit to your web site viewers.  This is often
      called the <em>public interface</em> to an object and is usually
      associated with the <em>View</em> view found on most Zope objects.</p><p>      Create a new DTML Method on the <em>Methods</em> tab of your <em>ZooExhibit</em>
      ZClass called <em>index_html</em>.  Like all objects named <em>index_html</em>,
      this will be the default representation for the object it is defined
      in, namely, instances of your ZClass.  Put the following DTML in the
      <em>index_html</em> Method you just created:<pre>        &lt;dtml-var standard_html_header&gt;

          &lt;h1&gt;&lt;dtml-var animal&gt;&lt;/h1&gt;

          &lt;p&gt;&lt;dtml-var description&gt;&lt;/p&gt;

          &lt;p&gt;The &lt;dtml-var animal&gt; caretakers are:&lt;br&gt;
            &lt;dtml-in caretakers&gt;
              &lt;dtml-var sequence-item&gt;&lt;br&gt;
            &lt;/dtml-in&gt;
          &lt;/p&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Now, you can visit one of your <em>ZooExhibit</em> instances directly
      through the web, for example,
      <em>http://www.zopezoo.org/Exhibits/FangedRabbits/</em> will show you the
      public interface for the Fanged Rabbit exhibit.</p><p>      You can use Python-based or Perl-based Scripts, and even Z SQL
      Methods to implement logic. Your logic objects can call each other,
      and can be called from your presentation methods. To create the
      <em>isHungry</em> method, first create two new properties in the
      <em>ExhibitProperties</em> property sheet named "last_meal_time" that is of
      the type <em>date</em> and "isDangerous" that is of the type <em>boolean</em>.
      This adds two new fields to your Edit view where you can enter the
      last time the animal was fed and select whether or not the animal is
      dangerous.</p><p>      Here is an example of an implementation of the <em>isHungry</em> method in
      Python:<pre>        ## Script (Python) &quot;isHungry&quot;
        ##
        &quot;&quot;&quot;
        Returns true if the animal hasn't eaten in over 8 hours
        &quot;&quot;&quot;
        from DateTime import DateTime
        if (DateTime().timeTime() 
            - container.last_meal_time.timeTime() &gt;  60 * 60 * 8):
            return 1
        else:
            return 0</pre>
</p><p>      The <code>container</code> of this method refers to the ZClass instance. So
      you can use the <code>container</code> in a ZClass instance in the same way
      as you use <code>self</code> in normal Python methods.</p><p>      You could call this method from your <em>index_html</em> display
      method using this snippet of DTML:<pre>        &lt;dtml-if isHungry&gt;
          &lt;p&gt;&lt;dtml-var animal&gt; is hungry&lt;/p&gt;
        &lt;/dtml-if&gt;</pre>
</p><p>      You can even call a number of logic methods from your display
      methods. For example, you could improve the hunger display like so:<pre>        &lt;dtml-if isHungry&gt;

          &lt;p&gt;&lt;dtml-var animal&gt; is hungry.

          &lt;dtml-if isDangerous&gt;

            &lt;a href=&quot;notify_hunger&quot;&gt;Tell&lt;/a&gt; an authorized
            caretaker.

          &lt;dtml-else&gt;

            &lt;a href=&quot;feed&quot;&gt;Feed&lt;/a&gt; the &lt;dtml-var animal&gt;.

          &lt;/dtml-if&gt;

          &lt;/p&gt;

        &lt;/dtml-if&gt;</pre>
</p><p>      Your display method now calls logic methods to decide what
      actions are appropriate and creates links to those actions.  For
      more information on Properties, see Chapter 3, "Using Basic Zope
      Objects".</p><h3>    <em>ObjectManager</em> ZClasses</h3>
<p>      If you choose <em>ZClasses:ObjectManager</em> as a base class for your
      ZClass then instances of your class will be able to contain
      other Zope objects, just like Folders. Container classes are
      identical to other ZClasses with the exception that they have an
      addition view <em>Subobjects</em>.</p><p>      From this view you can control what kinds of objects your
      instances can contain. For example if you created a FAQ
      container class, you might restrict it to holding Question and
      Answer objects. Select one or more meta-types from the select
      list and click the <em>Change</em> button. The <em>Objects should appear
      in folder lists</em> check box control whether or not instances of
      your container class are shown in the Navigator pane as
      expandable objects.</p><p>      Container ZClasses can be very powerful. A very common pattern
      for web applications is to have two classes that work
      together. One class implements the basic behavior and hold
      data. The other class contains instances of the basic class and
      provides methods to organize and list the contained
      instances. You can model many problems this way, for example a
      ticket manager can contain problem tickets, or a document
      repository can contain documents, or an object router can contain
      routing rules, and so on. Typically the container class will
      provide methods to add, delete, and query or locate contained
      objects.</p><h3>    ZClass Security Controls</h3>
<p>      When building new types of objects, security can play an important
      role.  For example, the following three Roles are needed in your Zoo:<dl>
<dt>        <em>Manager</em></dt>
<dd>This role exists by default in Zope.  This is you, and
        anyone else who you want to be able to completely manage your Zope
        system.</dd>
<dt>        <em>Caretaker</em></dt>
<dd>After you create a <em>ZooExhibit</em> instance, you
        want users with the <em>Caretaker</em> role to be able to edit
        exhibits.  Only users with this role should be able to see the
        <em>Edit</em> view of a <em>ZooExhibit</em> instance.</dd>
<dt>        <em>Anonymous</em></dt>
<dd>This role exists by default in Zope.  People with
        the <em>Anonymous</em> role should be able to view the exhibit, but not
        manage it or change it in any way.</dd>
</dl>
</p><p>      As you learned in Chapter 7, "Users and Security", creating new
      roles is easy, but how can you control who can create and edit
      new <em>ZooExhibit</em> instances?  To do this, you must define some
      security policies on the <em>ZooExhibit</em> ZClass that control access
      to the ZClass and its methods and property sheets.</p><h3>    Controlling access to Methods and Property Sheets</h3>
<p>      By default, Zope tries to be sensible about ZClasses and security.
      You may, however, want to control access to instances of your ZClass
      in special ways.</p><p>      For example, Zoo Caretakers are really only interested in seeing the
      <em>Edit</em> view (and perhaps the <em>Undo</em> view, which we'll show later),
      but definitely not the <em>Security</em> or <em>Ownership</em> views.  You don't
      want Zoo caretakers changing the security settings on your Exhibits;
      you don't even want them to <em>see</em> those aspects of an Exhibit, you
      just want to give them the ability to edit an exhibit and nothing
      else.</p><p>      To do this, you need to create a new <em>Zope Permission</em> object in the
      <em>ZooExhibit</em> Product (<em>not</em> the ZClass, permissions are defined in
      Products only).  To do this, go to the <em>ZooExhibit</em> Product and
      select <em>Zope Permission</em> from the add list.  Give the new permission
      the <em>Id</em> "edit_exhibit_permission" and the <em>Name</em> "Edit Zoo Exhibits"
      and click <em>Generate</em>.</p><p>      Now, select your <em>ZooExhibit</em> ZClass, and click on the <em>Permissions</em>
      tab.  This will take you to the <em>Permissions</em> view as shown in Figure
      <a href="#12-9">Figure 12-9</a>.</p><p>      <a name="12-9"></a>
<img src="Figures/12-9.png" alt="The Permissions view">
<p><b>Figure 12-9</b> The Permissions view</p>
</p><p>      This view shows you what permissions your ZClass uses and lets you
      choose additional permissions to use.  On the right is a list of all
      of the default Zope permissions your ZClass inherits automatically.
      On the left is a multiple select box where you can add new
      permissions to your class.  Select the <em>Edit Zoo Exhibits</em> permission
      in this box and click <em>Save Changes</em>.  This tells your ZClass that it is
      interested in this permission as well as the permissions on the right.</p><p>      Now, click on the <em>Property Sheets</em> tab and select the
      <em>ExhibitProperties</em> Property Sheet.  Click on the <em>Define
      Permissions</em> tab.</p><p>      You want to tell this Property Sheet that only users who have the
      <em>Edit Zoo Exhibits</em> permission you just created can manage the
      properties on the <em>ExhibitProperties</em> sheet.  On this view, pull down
      the select box and choose <em>Edit Zoo Exhibits</em>.  This will map the
      <em>Edit Zoo Exhibits</em> to the <em>Manage Properties</em> permission on the
      sheet.  This list of permissions you can select from comes from the
      ZClass <em>Permissions</em> view you were just on, and because you selected
      the <em>Edit Zoo Exhibits</em> permission on that screen, it shows up on
      this list for you to select.  Notice that all options default to
      <em>disabled</em> which means that the property sheet cannot be edited by
      anyone.</p><p>      Now, you can go back to your <em>Exhibits</em> folder and select the
      <em>Security</em> view.  Here, you can see your new Permission is on the
      left in the list of available permission.  What you want to do now is
      create a new Role called <em>Caretaker</em> and map that new Role to the
      <em>Edit Zoo Exhibits</em> permission.</p><p>      Now, users must have the <em>Caretaker</em> role in order to see or use the
      <em>Edit</em> view on any of your <em>ZooExhibit</em> instances.</p><p>      Access to objects on your ZClass's <em>Methods</em> view are controlled in
      the same way.</p><h3>    Controlling Access to instances of Your ZClass</h3>
<p>      The previous section explained how you can control access to
      instances of your ZClass's Methods and Properties.  Access control is
      controlling who can create new instances of your ZClass. As you saw
      earlier in the chapter, instances are created by Factories. Factories
      are associated with permissions. In the case of the Zoo Exhibit, the
      <em>Add Zoo Exhibits</em> permission controls the ability to create Zoo
      Exhibit instances.</p><p>      Normally only Managers will have the <em>Add Zoo Exhibits</em> permission,
      so only Managers will be able to create new Zoo Exhibits. However,
      like all Zope permissions, you can change which roles have this
      permissions in different locations of your site. It's important to
      realize that this permission is controlled separately from the <em>Edit
      Zoo Exhibits</em> permission. This makes it possible to allow some people
      such as Caretakers to change, but not create Zoo Exhibits.</p><h3>    Providing Context-Sensitive Help for your ZClass</h3>
<p>      On the <em>View</em> screen of your ZClass, you can see that each view
      can be associated with a <em>Help Topic</em>.  This allows you to
      provide a link to a different help topics depending on which
      view the user is looking at.  For example, let's create a Help
      Topic for the <em>Edit</em> view of the <em>ZooExhibit</em> ZClass.</p><p>      First, you need to create an actual help topic object.  This is
      done by going to the <em>ZooExhibit</em> Product which contains the
      <em>ZooExhibit</em> ZClass, and clicking on the <em>Help</em> folder.  The
      icon should look like a folder with a blue question mark on it.</p><p>      Inside this special folder, pull down the add list and select
      <em>Help Topic</em>.  Give this topic the id "ExhibitEditHelp" and the
      title "Help for Editing Exhibits" and click <em>Add</em>.</p><p>      Now you will see the <em>Help</em> folder contains a new help topic
      object called <em>ExhibitEditHelp</em>.  You can click on this object
      and edit it, it works just like a DTML Document.  In this
      document, you should place the help information you want to show
      to your users:<pre>        &lt;dtml-var standard_html_header&gt;

          &lt;h1&gt;Help!&lt;/h1&gt;

          &lt;p&gt;To edit an exhibit, click on either the &lt;b&gt;animal&lt;/b&gt;,
          &lt;b&gt;description&lt;/b&gt;, or &lt;b&gt;caretakers&lt;/b&gt; boxes to edit
          them.&lt;/p&gt;

        &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>      Now that you have created the help topic, you need to associate
      with the <em>Edit</em> view of your ZClass.  To do this, select the
      <em>ZooExhibit</em> ZClass and click on the <em>Views</em> tab.  At the right,
      in the same row as the <em>Edit</em> view is defined, pull down the
      help select box and select <em>ExhibitEditHelp</em> and click <em>Change</em>.
      Now go to one of your ZooExhibit instances, the <em>Edit</em> view now
      has a *Help!* link that you can click to look at your Help
      Topic for this view.</p><p>    In the next section, you'll see how ZClasses can be cobined with
    standard Python classes to extend their functionality into raw Python.</p><h2>  Using Python Base Classes</h2>
<p>    ZClasses give you a web managable interface to design new kinds of
    objects in Zope.  In the beginning of this chapter, we showed you how
    you can select from a list of <em>base classes</em> to subclass your ZClass
    from.  Most of these base classes are actually written in Python, and
    in this section you'll see how you can take your own Python classes and
    include them in that list so that your ZClasses can extend their
    methods.</p><p>    Writing Python base classes is easy, but it involves a few installation
    details. To create a Python base class you need access to the
    filesystem. Create a directory inside your <em>lib/python/Products</em>
    directory named <em>AnimalBase</em>. In this directory create a file named
    <em>Animal.py</em> with these contents:<pre>      class Animal: 
          &quot;&quot;&quot;
          A base class for Animals
          &quot;&quot;&quot; 

          _hungry=0

          def eat(self, food, servings=1):
              &quot;&quot;&quot;
              Eat food
              &quot;&quot;&quot;
              self._hungry=0

          def sleep(self):
              &quot;&quot;&quot;
              Sleep
              &quot;&quot;&quot;
              self._hungry=1

          def hungry(self):
              &quot;&quot;&quot;
              Is the Animal hungry?
              &quot;&quot;&quot;
              return self._hungry</pre>
</p><p>    This class defines a couple related methods and one default
    attribute. Notice that like External Methods, the methods of this
    class can access private attributes.</p><p>    Next you need to register your base class with Zope. Create an
    <em>__init__.py</em> file in the <em>AnimalBase</em> directory with these
    contents:<pre>      from Animal import Animal

      def initialize(context):
          &quot;&quot;&quot;
          Register base class
          &quot;&quot;&quot;
          context.registerBaseClass(Animal)  </pre>
</p><p>    Now you need to restart Zope in order for it find out about your
    base class. After Zope restarts you can verify that your base
    class has been registered in a couple different ways. First go to
    the Products Folder in the Control Panel and look for an
    <em>AnimalBase</em> package. You should see a closed box product. If you
    see broken box, it means that there is something wrong with your
    <em>AnimalBase</em> product.</p><p>    Click on the <em>Traceback</em> view to see a Python traceback showing
    you what problem Zope ran into trying to register your base class.
    Once you resolve any problems that your base class might have
    you'll need to restart Zope again. Continue this process until
    Zope successfully loads your product. Now you can create a new
    ZClass and you should see <em>AnimalBase:Animal</em> as a choice in the
    base classes selection field.</p><p>    To test your new base class create a ZClass that inherits from
    <em>AnimalBase:Animal</em>. Embellish you animal however you wish. Create
    a DTML Method named <em>care</em> with these contents:<pre>      &lt;dtml-var standard_html_header&gt;

      &lt;dtml-if give_food&gt;
        &lt;dtml-call expr=&quot;eat('cookie')&quot;&gt;
      &lt;/dtml-if&gt;

      &lt;dtml-if give_sleep&gt;
        &lt;dtml-call sleep&gt;
      &lt;/dtml-if&gt;

      &lt;dtml-if hungry&gt;
        &lt;p&gt;I am hungry&lt;/p&gt;
      &lt;dtml-else&gt;
        &lt;p&gt;I am not hungry&lt;/p&gt;
      &lt;/dtml-if&gt;

      &lt;form&gt;
      &lt;input type=&quot;submit&quot; value=&quot;Feed&quot; name=&quot;give_food&quot;&gt;
      &lt;input type=&quot;submit&quot; value=&quot;Sleep&quot; name=&quot;give_sleep&quot;&gt;
      &lt;/form&gt;

      &lt;dtml-var standard_html_footer&gt;</pre>
</p><p>    Now create an instance of your animal class and test out its
    <em>care</em> method. The care method lets you feed your animal and give
    it sleep by calling methods defined in its Python base class. Also
    notice how after feeding your animal is not hungry, but if you
    give it a nap it wakes up hungry.</p><p>    As you can see, creating your own Products and ZClasses is an
    involved process, but simple to understand once you grasp the
    basics.  With ZClasses alone, you can create some pretty complex
    web applications right in your web browser.</p><p>    In the next section, you'll see how to create a <em>distribution</em> of
    your Product, so that you can share it with others or deliver it
    to a customer.</p><h2>  Distributing Products</h2>
<p>    Now you have created your own Product that lets you create any number
    of exhibits in Zope.  Suppose you have a buddy at another Zoo who is
    impressed by your new online exhibit system, and wants to get a similar
    system for his Zoo.  </p><p>    Perhaps you even belong to the Zoo keeper's Association of America and
    you want to be able to give your product to anyone interested in an
    exhibit system similar to yours.  Zope lets you distribute your
    Products as one, easy to transport package that other users can
    download from you and install in their Zope system.</p><p>    To distribute your Product, click on the <em>ZooExhibit</em> Product and
    select the <em>Distribution</em> tab.  This will take you to the
    <em>Distribution</em> view.</p><p>    The form on this view lets you control the distribution you want to
    create.  The <em>Version</em> box lets you specify the version for your
    Product distribution.  For every distribution you make, Zope will
    increment this number for you, but you may want to specify it
    yourself.  Just leave it at the default of "1.0" unless you want to
    change it.</p><p>    The next two radio buttons let you select whether or not you want
    others to be able to customize or redistribute your Product.  If you
    want them to be able to customize or redistribute your Product with no
    restrictions, select the <em>Allow Redistribution</em> button.  If you want to
    disallow their ability to redistribute your Product, select the
    <em>Disallow redistribution and allow the user to configure only the
    selected objects:</em> button.  If you disallow redistribution, you can
    choose on an object by object basis what your users can customize in
    your Product.  If you don't want them to be able to change anything,
    then don't select any of the items in this list.  If you want them to
    be able to change the <em>ZooExhibit</em> ZClass, then select only that
    ZClass.  If you want them to be able to change everything (but still
    not be able to redistribute your Product) then select all the objects
    in this list.</p><p>    Now, you can create a distribution of your Product by clicking <em>Create
    a distribution archive</em>.  Zope will now automatically generate a file
    called <em>ZooExhibit-1.0.tar.gz</em>.  This Product can be installed in any
    Zope just like any other Product, by unpacking it into the root
    directory of your Zope installation.</p><p>    Don't forget that when you distribute your Product you'll also
    need to include any files such as External Method files and Python
    base classes that your class relies on. This requirement makes
    distribution more difficult and for this reason folks sometimes
    try to avoid relying on Python files when creating through the web
    Products for distribution.</p></body>
</html>