Core dev summit API breakout sessions notes

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
You are viewing a wiki page. You are welcome to join the group and then edit it. Be bold!

Additional notes taken from after the session by catch/bangpound/pwolanin:

define a base interface
define an abstract base class
The class has static class methods for CRUD
Instances of the class are the things we work with.

We might have one or more additional classes which implement one or mode additional Interfaces. E.g. for fieldable objects.

We need some generic top-level functions that wrap static class methods.

int entity_create($entity_type, Array $values) // returns object Id. @throws Exception on failure.
NULL entity_update($entity_type, array($object_id => Array $values)) //@throws Exception on failure

Array entity_find($entity_type, Array $conditions) // Returns array of Ids
Array entity_find_revisions($entity_type, $object_id, Array $conditions) // Returns array of revision Ids for one object Id.

Array entity_load_multiple($entity_type, Array $ids) // Returns associative array of $id => Object pairs, omitting any that don't exist.
Object or NULL entity_load($entity_type, int $id) // Convenience wrapper

Array entity_load_revisions($entity_type, Array $rev_ids) // Returns associative array of $rev_id => Object pairs, omitting any that don't exist.

NULL entity_delete_multiple($entity_type, Array $ids)
Array entity_delete_revisions($entity_type, Array $rev_ids) // needs to protect the "current" one. Returns the list of ids marked deleted.

General principles:

Read
2 separate API methods for read:
1) Query - a method that takes conditions, returns only Ids
2) Load - takes one or more Ids and loads the objects

Update

You always create a new revision. The Archive table. The {node} and {node_revision} tables should have the same fields, plus {node_revision} has some extra state columns - like "draft", "deleted", "current". {node_revision} table should have fewer indexes. Need to be able to create an nid when insterting into {node_revisions}.

Entity storage should be pluggable, the main entity 'table' and revision 'table' should be possible to store in different storage engines.

We must be able to drop the {node} table and re-create is from {node_revisions}, even though they may be on different storage engines.

Delete

Needs to be implemented in a potentially GC model, where we simply mark objects in {node_revisions} as "to be deleted". This allows for "undo". We have to immediately delete form {node} however, since we don't want to condition queries on node to be "not deleted".

Preview saves a draft in the {node_revisions} table.

Info on how to call the methods of a class using a variable class name: http://dorkage.net/2009/02/class-names-as-variables-in-php/

Notes from the session itself taken by Andrew Berry :

  • This is a session about "APIs"
    • Example topic: Should menu links be entities, and get all of the same hooks as nodes,comments, etc?
  • Should we have a very standardized API for everything?
    • Resounding YES
  • Consistency makes API easier to learn as there are less patterns to keep in mind
  • How do you shortcut hooks for high-use objects like menu links to ensure performance?
  • node multiload in D7 is a great example
  • We cache objects, but misses can be "very scary"
  • Currently, some entities are not fieldable
  • How do we differentiate between a full entity and a lightweight entity?
  • For D8? One idea:
    • Users are lightweight entities
    • Profiles are full entities
  • What are the barest methods that a entity needs?
    • CRUD? - is that true?
    • Remote data access is read only for example
    • But, it should be the same R api for remote objects
    • R can be very complicated, including relationships, querying across storage engines, combing remote and local query
  • Do remote objects need alter hooks?
    • Load remote art from an API
    • Query by keyword
    • Users need to be able to add ratings and comments which stays in Drupal
  • In the past, Crell has come to the conclusion that search should pull IDs, multiload should load objects
    • Chx agrees especially as data can live in different storage systems
  • Currently, node multiload works well with the caching api and only loads what's needed from the cache
  • The unified entity API needs all objects to be cacheable
  • The data and display caches should always be separate
  • If hook_node_load() goes away, the field API needs to be dead simple to use
  • Right now, much of what we do is the example of what we should not do!
    • Look at the menu tree queries and all of the data it loads
    • Instead, each step could be separated
    • Remember, we came to this realization at the end of the D7 cycle, and we needed to learn from D6 and D7 to get here
  • We could also have a lightweight and full loads instead of objects
    • Along with separate caches for each
    • But, if you have to do a lightweight + full load, you end up at a net loss
  • Some fields might be "attribute" fields
    • Fields that aren't loaded but control business logic etc
  • An entity consists of fields and properties
    • A field instance can be marked as load and cache, or lazy load
    • Lazy load helps dynamic fields as well
  • Entities could be entirely references
  • Currently, you can make a special field type such as a field for very large text that lazy loads
  • What happens when a use case changes, and the same field becomes much larger?
    • If we mark lazy load in config, it can be tuned per use case
  • What if we pushed loading to the rendering layer?
  • Entities need an ID, fields need a delta
  • Does every object need to have a UUID?
    • There are problems in PHP and MySQL to do this properly
  • Every object has "local" data such as strings, ints, etc
    • Many will have "remote" data such as node / user references
  • Have to watch for recursive loading so you know when to switch back to lazy loading
  • Do we want to make node body an entity instead of a field?
    • Crell says it creates more problems then it solves
  • A classed object with methods allows for setting defaults on objects
  • Where do you break the chain of events where you get entities returned instead of primitive types?
  • Or, "string" could be an object all ready

Comments

late vs. early static binding

pwolanin's picture

Something to beware of - Crell pointed out that PHP 5.2 and 5.3 differ in having early vs. late static binding. This means that invoking a method (or referencing a constant) using self:: will potentially give different result in PHP 5.2 and 5.3 if something inherits from your class and its static methods.

static:: vs self::

alex_b's picture

Late static bindings will use the static:: scope qualifier (not self::). So no danger there.

http://php.net/manual/en/language.oop5.late-static-bindings.php