About the Rules Ecosystem @drupalcon Copenhagen!

For anyone interested, here are the slides of the session. I'll also add the link to the video here, once it is available.

Metadata, what for? - Introducing Entity Metadata!

Drupal 7 modules working with entities often face the same problems:

  • How to create/save/delete an entity?
  • How to get referenced entities?
  • Which properties are there and how can they be accessed or modified?

This is, what Entity Metadata tries to solve for Drupal 7. It collects metadata from modules, such that it knows how this things can be done and provides API functions for that purpose. There are API functions for full entity CRUD, for determining access, as well as data wrappers that simplify dealing with entity properties.

Metadata for data properties, why that?

You might think, we have fields. Yes we have, but not everything is a field. There are also entity properties, like the node title and author, the term hierarchy and lots of others. Entity metadata collects information about all that available properties - regardless whether they are fields or not - and makes them accessible the same way. For that you have to provide property info via a hook, e.g. this is the info the module provides for books:

Drupalcon San Francisco

DrupalCon San Francisco was an amazing DrupalCon - about 3000 attendees!!! I had really great luck to be there at all, we passed the volcano ash by one day! Sadly lots of European Drupalistas had not so much luck :(

I really enjoyed the conference, in particular the core developer summit & the code sprints. Gladly the lightning talk I submitted for the core developer summit was selected, so I gave a short talk about Drupal's data APIs - Why inhomogeneous APIs suck - clearly entities are the way to go!

Using Git to deploy code changes..

Wouldn't it be nice have your changes up and running at a development site just by pushing it there with git push dev? Well with Git that's pretty easy to achieve.

First create a new Git repository on the remote if you haven't yet:

mkdir www
cd www
git init

Then push your code to this repository initially and then check it out:

git checkout your-branch

So now we need to make Git automatically checking out the latest code once you pushed it in. For that create the script ".git/hooks/post-receive":

#!/bin/sh
cd ..
export GIT_DIR=".git"
git checkout -f

And don't forget to make the file executable.

Now as the code is automatically updated, we need to disable the usual warning when one pushes to a remote repository with a checkout:

git config receive.denycurrentbranch ignore

That's it. Simple and useful, not? :)
Credits go to http://toroid.org/ams/git-website-howto, which I used to come up with this.

About using git to maintain a drupal module...

Some months ago I gave git a first try for developing some stacked core patches. I quickly get used to it and to its nice features (german). Luckily its SVN integration is really nice and simple to use so GIT is even a fine replacement for the usual SVN client. Unfortunately for CVS things are much worse.. :( Poor cvs!

First tries..

I decided to don't go back to CVS for maintaining drupal modules. First I tried using the public GIT mirror of the whole drupal CVS from the French drupal community, however I quickly noted that it was broken for the rules module, so I tried to set up my on mirror. I started using Sam Boyer's scripts, however I had some misc small troubles with them, but more important those scripts copy the whole drupal CVS - but I didn't like to waste ~6 gigs of disk space and the time to sync all the unneeded stuff. So I ended writing my own script based on the instructions in the drupal handbook for maintaining a module with git and Sam's script. After some weeks going back and forth I finally ended up with something useful, so here are my experiences:

What is it about?

Currently I've set the script up to export the drupal CVS of some of my modules to GIT - its automatically pushing to my github account, which is quite convenient. It syncs only the really needed modules using rsync - which is an important step as its greatly speeding up cvsps when exporting from CVS. The nice thing is that it doesn't overwrite any changes not yet in CVS, so I can use the same git repository on github to develop new stuff and export to CVS later on.

Are entities drupal's new nodes?

With drupal 7 the concept of an entity gets introduced in drupal, thus nodes, comments, users, terms - all these are drupal's entities. Most important the also new field API is able to support any entity! So how will this affect the drupal landscape?

Rules session @Drupalcon Paris

Better late as never, so here are the slides from the rules presentation at the drupalcon. I'm also attaching the two features which were built with rules during the presention:

I'm on vacation...

from oct 5th till 27th - thus don't expect any responses from me during that time!

Benchmarking Extendable Object Faces

I've started with crell's results when benchmarking magic.

Introducing the concept of Extendable Object Faces (API)

Preliminary Warning:
"If you're afraid of classes and objects in PHP, run away now." - jpetso.

Update: For simplicity the API has been changed so that all faces are incorporated, thus modules have to care about naming collisions theirself. Also in the meantime file inclusions support has been added.

While figuring out a object oriented design for the rules engine I recognized the need for a possibility to allow modules extend objects in various places. Thus I developed a generic concept which does just that: Allowing modules to extend objects. I called the concept "Extendable Object Faces", which basically implements the Facade pattern in a modular way.

So let's have a closer look at that. A module that wants to extend an object may only do so on top of a defined interface, preventing uncontrolled growing objects. Thus one can write some code, define an interface for it and attach it to potential any extendable object out there. Then other modules have an easy way to test whether some object has a functionality in place by checking for the availability of a certain interface.
To use that functionality the caller has to use the right "Face" of the object - corresponding to a certain interface. This approach using different "Object Faces" make sure there can't be conflicting method names, so modules don't need to prefix their methods with the module's name which would result in ugly and not readable code.

I've already implemented an initial version of the Extendable Object Faces API. As of now you can:

  • Extend an object by providing an Extender Class
  • Extend an object simply by some functions, each implementing a method
  • Override any dynamically added method by providing functions or an Extender Class

So apart from "allowing modules to extend an object", this also allows one to:

  • Easily lazy load huge parts of an objects implementation, invisible for the caller.
  • Allow modules to dynamically alter an implementation by using overriding.

Hence such an Extended Object can also serve as a clean abstraction for module provided callbacks!

Enough talk, let's show how it works:

<?php
interface FacesTestInterface {
  function
isWorking($prefix);
}

/**
* Extendable Class
*/
class FacesTestElement extends FacesExtendable {
 
//Your code here..
}
?>

This code provides the class for the Extendable Object and already defines an interface, which modules may implement. So let's extend it with an Extender Class.

<?php
/**
* Extender Class
*/
class FacesTestExtender extends FacesExtender implements FacesTestInterface {

  function
isWorking($prefix) {
    return
$prefix . $this->object->name;
  }
}
?>

That's it. Now you can use the face!

<?php
    $element
= new FacesTestElement();
   
$element->name = 'test';
   
$element->extendByClass(array('FacesTestInterface'), 'FacesTestExtender');
   
// Now use it.
   
print $element->face('FacesTestInterface')->isWorking('Name:');
   
// This prints "Name:test".
?>

As you see, one has to use the face to be able to use the added method - so potential name collisions are avoided. However the Extendable Class can define so called incorporated faces, which are built in the Extendable Object as soon as a module provides an implementation:
<?php
/**
* New extendable Class
*/
class FacesTestElement extends FacesExtendable {
  public function
getIncorporatedFaces() {
    return array(
'FacesTestInterface');
  }
}
?>

So you can use it that way, once extended:
<?php
   
print $element->isWorking('Name:');
?>

You can find more examples in the simpletests I've written. Also checkout the benchmarks I've run.

So what's missing? Basically the implementation is complete and working fine. Though feedback and suggestions are very welcome! However currently the code doesn't deal with including code where the implementation can reside (lazy loading), though for drupal 7 that is already solved by the code registry (just add one call to drupal_function_exists()). For drupal 6 I think about adding the possibility to specify include files per added interface.

Dreaming...

If we would have an object oriented "Data API" in drupal core, this could serve as a way to let modules extend those objects. So instead of writing node-centric code code could would be written in a generic way - attachable to potentially each of those data objects (users, comments, terms). Having such generic code would allow us to finally end the "Everything should be a node" debate. Apart from that this would help us to easily lazy load big chunks of code, just exploiting the code registry!

Syndicate content

Back to top