Apostrophe 1.5: legacy documentation

Still using Apostrophe 1.5? Check out Apostrophe 2 for your future projects.

apostrophe Entities Plugin

We have projects in which many different "entity" types, such as "neighborhoods," "areas of interest" and "persons," may need to be associated with a given page or with each other. You may also wish to associate them with blog posts and events. And these entity types may also have a need for distinct columns. Of course we need a way to manage them all via the admin generator.

apostropheEntitiesPlugin provides a point of departure for this. Add the plugin to your project, then define Doctrine column aggregation subclasses of aEntity in your own schema.yml. The provided aEntityAdmin module automatically knows how to manage all of them, presenting a list of dashboards for them so you can switch among them.

Note that you can also associate a "person" with another "person." In this case both backward and forward references are saved so that the association is naturally visible from either end. If you remove the association from either end, it is broken in both directions. This allows "friend" relationships between objects of the same type, which are otherwise awkward to work with in the admin generator.

Add it to your project's plugins folder via svn externals:

apostropheEntitiesPlugin http://svn.apostrophenow.org/plugins/apostropheEntitiesPlugin/trunk

Be sure to enable it in your ProjectConfiguration.class.php file. It should come after apostrophePlugin and apostropheBlogPlugin but before any plugins you may create that add subclasses to it.

The entities plugin also enhances the blog plugin to allow users to filter blog posts by each type of entity. If you want this functionality, you need to add aEntityBlog to the list of enabled modules in your settings.yml file.

If you have overridden the aBlog/subnavLayout partial, be sure to add this line:

<?php include_slot('a_blog_sidebar_entities') ?>

We suggest adding it before the feeds.

(This line is already present in the latest version of that file in the blog plugin.)

In your project-level schema.yml you will declare subclasses like this (it doesn't make sense to use this plugin without at least one subclass):

Organization:
  inheritance:
    extends: aEntity
    type: column_aggregation
    keyField: type
    keyValue: 'Organization'

Note that Doctrine form classes for models created via inheritance do not automatically offer just the relevant fields for that subclass. However you can fix that by overriding configure() in the form classes for the subclasses. The aEntityForm class gets the ball rolling by making sure the 'type' column cannot be edited directly. More importantly, aEntityForm provides distinct many-to-many widgets to associate each entity class with all other entity classes, including itself.

You can add a manage button conveniently with this code in your _globalProjectButtons partial in the a module:

<?php include_partial('aEntityAdmin/manageButton') ?>

Or just swipe that code as a point of departure.

Since class names are not always reasonable labels, you may wish to configure labels:

all:
  aEntities:
    entities:
      Person:
        labels:
          plural: "People"

If you wish you can make it possible to associate any page with one or more entities, via friendly multiple select widgets for each subclass. Here's how to do that.

First, override the a/extraPageSettings partial to include the provided aEntityAdmin/extraPageSettings partial:

<?php include_partial('aEntityAdmin/extraPageSettings', array('form' => $form)) ?>

Second, override the aPageSettingsForm class at project level to add the association widgets:

class aPageSettingsForm extends BaseaPageSettingsForm
{
  public function configure()
  {
    parent::configure();
    aEntityTools::formConfigure($this, false);
  }

  public function updateDefaultsFromObject()
  {
    parent::updateDefaultsFromObject();
    aEntityTools::formUpdateDefaultsFromObject($this);
  }

  protected function doSave($con = null)
  {
    aEntityTools::formSaveLists($this, $con);
    parent::doSave($con);
  }
}

Note the use of convenience methods from the aEntityTools class to do most of the work.

aEntityTools::formConfigure accepts two arguments. The first argument is the form object. The second is a boolean flag which should always be false when the form is not editing a subclass of aEntity.

The aEntityForm class has a getUseFields method. Your subclasses can override that method, calling the parent version and merging in additional fields to be shown as needed. As for hiding extra columns that aren't relevant for a particular subclass in the list view of the admin generator, you can take advantage of the fact that the subclass is present as a CSS class on the list container to hide the extra columns by default, then show them for specific subclasses. This is a good workaround for the fact that the admin generator generates its list view code once on the first page load of the module.

You can use the aEntityTools:: methods to enhance other form classes to allow associations between those model classes and entities. You will need to define an appropriate additional relationship on the aEntity model, akin to this one. Note that there is a foreignAlias called Entities. it is crucial that the entities be accessible from your model object under that name.

    Pages:
      type: many
      class: aPage
      refClass: aEntityToPage
      local: entity_id
      foreign: page_id
      foreignAlias: Entities

Here is the reference class:

aEntityToPage:
  columns:
    entity_id:
      type: integer
      primary: true
    page_id:
      type: integer
      primary: true
  relations:
    Entity:
      foreignAlias: EntityPages
      class: aEntity
      local: entity_id
      onDelete: CASCADE
    Page:
      foreignAlias: EntityPages
      class: aPage
      local: page_id
      onDelete: CASCADE