

After way too long a time I finally get back to the series of posts (check out Part I and Part II) on Entities to present the third in the series - how to actually create an entity. Part of the challenge of writing a post like this is that there are so many different aspects to entities that it is really hard to distill things into a single post that gives you something useful at the end. What we will do will be the equivalent of a “Hello World” for entities. It is not very useful in and of itself but it does get you started and introduces the main concepts.
We are going to create a single entity that has just two fields, an id and some content. For the sake of reference I will call it the PostIt entity. Imagine you wanted to create a simple PostIt system or shoutbox for your Drupal site - this would be part of the way of getting there.
First thing - we need to describe a table to Drupal which will be our “base” table - very much like the Node table, this will be where things start. This description will go into postit.install in a module directory called postit
All we are doing here is telling Drupal to create a table with two fields, one of which is the primary key. The table will be created as soon as the module is enabled. Ok - so we have a starting point. Next up, we need to go tell Drupal that this is the base table of our entity and set up a few things about how it should treat the entity. There is, naturally, a hook for this - aptly called hook_entity_info() and, as with most things Drupal, you construct a huge array with all the configuration information.function postit_schema() { $schema['postit'] = array ( 'description' => 'The main store for our entity', 'fields' => array( 'pid' => array( 'description' => 'Primary key for our table of postit notes', 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, ), 'note' => array( 'description' => 'The actual note', 'type' => 'varchar', 'length' => '255', 'not null' => TRUE ), ), 'primary key' => array('pid'), ); return $schema; }Ok - so let us step through this. We provide a label to have a human readable reference to our entity and define a class, the PostItController class, that will be responsible for our postit. This class will actually subclass the DrupalDefaultEntityController class (which lives in entity.inc) and worries about such things such as caching, querying, attaching to fields, etc. You don’t strictly need to define this class (it will automatically use the default one), but if you did want to override some of the existing functionality this would be the way to do it. The class can go in a separate file called postit.controller.inc with just this code for the time being.function postit_entity_info(){ $postit_info['postit'] = array( 'label' => t('PostIt Note'), 'controller class' => 'PostItController', 'base table' => 'postit', 'uri callback' => 'postit_uri', 'fieldable' => TRUE, 'entity keys' => array( 'id' => 'pid', ), 'static cache' => TRUE, 'bundles' => array( 'postit'=> array( 'label' => 'PostIt', 'admin' => array( 'path' => 'admin/structure/postit/manage', 'access arguments' => array('administer postits'), ), ), ), 'view modes' => array( 'full' => array( 'label' => t('Full PostIt'), 'custom settings' => FALSE, ), ) ); return $postit_info; }We then let Drupal know what the base table will be for our entity and what function should be called to create URIs for this entity. The Entity API will use this function when trying to figure out URIs for entities. The next one is the biggie, our entity is fieldable which means that the Field API can now hook into our entity and we can easily extend it with fields to our hearts content. We then define what the main identifier for our entity is and we turn on caching. We now move on to the bundle part, which is really where we practically stitch together the FieldAPI with our entity. A way to think of bundles is as a type of entity (in this case a postit entity) “bundled” together with fields to forms a particular subtype. For example, different types of nodes are different bundles. The Entity API in Drupal can support multiple bundles but in our case we are just defining one and providing a URL where one can go to manage this specific bundle. Finally, we define view modes - in this case just one. And that is pretty much it. It could be a bit simpler, but it can also get much more complicated. As I mentioned this is enough for “hello entity!”. Let us now move on to provide the bare minimum functionality to be able to enable our entity module, view an entity and attach fields to it. First up, taking care of the URI:class PostItController extends DrupalDefaultEntityController{}Then a couple of functions that will load our entities for us:function postit_uri($postit){ return array( 'path' => 'postit/' . $postit->id, ); }The first function simply takes care of whether it is going to load just one or multiple entities and the second function actually goes ahead and loads the entities calling entity_load(). The code below setups the various pages we will use to view our entities. We have a manage page that just provides an access point and link for the Field API to attach itself to our entity via the UI. If you visit “admin/structure/postit/magage” you should see tabs for adding and editing fields. The other url is where we will view our entity.function postit_load($pid = NULL, $reset = FALSE){ $pids = (isset ($pid) ? array($pid) : array()); $postit = postit_load_multiple($pids, $reset); return $postit ? reset ($postit) : FALSE; } function postit_load_multiple($pids = array(), $conditions = array(), $reset = FALSE){ return entity_load('postit', $pids, $conditions, $reset); }Now, with all these in place you are able to attach fields to the entity but there is no UI to actually create an entity. If you visit admin/structure/postit/manage you should be able to see tabs that enable you add and remove fields to your entity. We will now quickly create a basic UI to add entities so we have just enough to prove everything works together: We will add another path to hook_menu:function postit_menu(){ $items['admin/structure/postit/manage'] = array( 'title' => 'PostIt Admin', 'description' => 'Manage PostIT structure', 'page callback' => 'postit_info', 'access arguments' => array('administer postits'), ); $items['postit/%postit'] = array( 'title callback' => 'postit_page_title', 'title arguments' => array(1), 'page callback' => 'postit_page_view', 'page arguments' => array(1), 'access arguments' => array('view postits'), 'type' => MENU_CALLBACK, ); return $items; } function postit_permission(){ return array( 'administer postits' => array( 'title' => t('Administer postits'), 'restrict access' => TRUE, ), 'view postsits' => array( 'title' => t('View PostIts'), ) ); } function postit_info() { return ('Welcome to the administration page for your Postits!'); } function postit_page_title($postit){ return $postit->pid; } function postit_page_view($postit, $view_mode = 'full'){ $postit->content = array(); // Build fields content. field_attach_prepare_view('postit', array($postit->pid => $postit), $view_mode); entity_prepare_view('postit', array($postit->pid => $postit)); $postit->content += field_attach_view('postit', $postit, $view_mode); return $postit->content; } function postit_field_extra_fields() { $return = array(); $return['postit']['postit'] = array( 'form' => array( 'note' => array( 'label' => t('Note'), 'description' => t('PostIt Note'), ), ), ); return $return; }and create the function that is called back.$items['postit/add'] = array( 'title' => 'Add PostIT!', 'page callback' => 'postit_add', 'access arguments' => array('create postit'), );What we are doing here is creating a form with the note field and then via field_attach_form we are adding any other widgets that are coming via the Field API. The form submission goes through the usual validation steps:function postit_add() { $postit = (object) array ( 'pid' => '', 'type' => 'postit', 'note' => '', ); return drupal_get_form('postit_add_form', $postit); } function postit_add_form($form, &$form_state, $postit) { $form['note'] = array( '#type' => 'textfield', '#title' => t('Note'), '#required' => TRUE, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), ); field_attach_form('postit', $postit, $form, $form_state); return $form; }The pattern here is pretty much “Take care of your own fields and then let the Field API do its own thing for the attached fields. The one function that is missing is the postit_save function which is below:function postit_add_form_validate($form, &$form_state) { $postit_submisttion = (object) $form_state['values']; field_attach_form_validate('postit', $postit_submisttion, $form, $form_state); } function postit_add_form_submit($form, &$form_state) { $postit_submission = (object) $form_state['values']; field_attach_submit('postit', $postit_submission, $form, $form_state); $postit = postit_save($postit_submission); $form_state['redirect'] = "postit/$postit->pid"; }For illustration sake (given that we could do the job without the controller), we delegate the work to our entity controller that has one more function added to it:function postit_save(&$postit) { return entity_get_controller('postit')->save($postit); }public function save($postit) { drupal_write_record('postit', $postit); field_attach_insert('postit', $postit); module_invoke_all('entity_insert', 'postit', $postit); return $postit; }Similar pattern as before, we first save to our own entity table, and then save all the associated fields. Finally, give all the other modules a shout via a hook that an entity has been inserted and we are done.
Visit postit/add you will be able to create the postit and if you’ve attached any fields to it you will see their widgets there as well. Check the db and you will see your postit table getting updated.
There is still a bit to do, such as deleting and editing entities - offering a page to view a list of all entities, etc - but as I said this is a “Hello Entity!” example. Check out the excellent work that is being done with the Entity project for examples of a full blown CRUD controller for entities.
As you can imagine the possibilities with entities are endless and this has only touched the surface. Hopefully, examples will soon start popping up in the wild and patterns and best practices will start emerging on how to create and handle entities.
Here is a link to a module that I submitted as a patch to the Examples project on d.o. - variable names are different but the approach is the same.
For a more comprehensive and realistic example check out the Model Entities project.
How to create a Drupal Entity through code.
Posted via email from adlatitude | Comment »
Essays - Spring 2010
Solitude and Leadership
If you want others to follow, learn to be alone with your thoughts
By William Deresiewicz
The lecture below was delivered to the plebe class at the United States Military Academy at West Point in October 2009.
My title must seem like a contradiction. What can solitude have to do with leadership? Solitude means being alone, and leadership necessitates the presence of others—the people you’re leading. When we think about leadership in American history we are likely to think of Washington, at the head of an army, or Lincoln, at the head of a nation, or King, at the head of a movement—people with multitudes behind them, looking to them for direction. And when we think of solitude, we are apt to think of Thoreau, a man alone in the woods, keeping a journal and communing with nature in silence.
Leadership is what you are here to learn—the qualities of character and mind that will make you fit to command a platoon, and beyond that, perhaps, a company, a battalion, or, if you leave the military, a corporation, a foundation, a department of government. Solitude is what you have the least of here, especially as plebes. You don’t even have privacy, the opportunity simply to be physically alone, never mind solitude, the ability to be alone with your thoughts. And yet I submit to you that solitude is one of the most important necessities of true leadership. This lecture will be an attempt to explain why.
We need to begin by talking about what leadership really means. I just spent 10 years teaching at another institution that, like West Point, liked to talk a lot about leadership, Yale University. A school that some of you might have gone to had you not come here, that some of your friends might be going to. And if not Yale, then Harvard, Stanford, MIT, and so forth. These institutions, like West Point, also see their role as the training of leaders, constantly encourage their students, like West Point, to regard themselves as leaders among their peers and future leaders of society. Indeed, when we look around at the American elite, the people in charge of government, business, academia, and all our other major institutions—senators, judges, CEOs, college presidents, and so forth—we find that they come overwhelmingly either from the Ivy League and its peer institutions or from the service academies, especially West Point.
In Solitude and Leadership, William Deresiewicz argues that leaders need to spend some time alone with their thoughts and ideas so they know why and where they are leading. Delivered as a lecture at West Point, it is worth reading in its entirety.
Posted via email from adlatitude | Comment »
How to change the default MAMP MySQL Password http://t.co/LbZr5w10
When you are changing the default user/password from root/root, you need to do two things. Only the first is documented in the MAMP start page FAQ, but if you don’t do the second then you get an error message when you try to access anything from the MAMP start page.
Open the terminal and type the following:/Applications/MAMP/Library/bin/mysqladmin -u root -p password [NEWPASSWORD]
It will ask for the current password after you hit enter. Once you have entered that, the MySQL password is changed.
/Applications/MAMP/bin/phpMyAdmin-X.X.X/config.inc.php Find the line that reads…$cfg['Servers'][$i]['password'] = 'root';
…and change the value 'root' to your new password, retaining the quotes.
/Applications/MAMP/bin/mamp/index.php Find the line that reads…$link = @mysql_connect(':/Applications/MAMP/tmp/mysql/mysql.sock', 'root', 'root');
…and change the last parameter to your new password.
/Applications/MAMP/bin/stopMysql.sh Replace the -proot with your password. (If you don’t change this one you can have zombie mysqld’s running after you thought you stopped the server)
Posted via email from adlatitude | Comment »
So this past weekend I started working on a bare wordpress theme called NakedCompass. And as part of that project I decided that I also wanted to tie it together with the CSS Framework Compass (and SASS). Now Compass comes bundled with a SASS adaptation of the excellent Blueprint framework. But I personally prefer the 960gs framework, which unfortunately does not come with Compass. And try as I might, I could not seem to find a SASS adaptation of the 960gs framework anywhere on the web. So I created my own.
If you would like to take a look / use it you can see it on GIT at A SASS adaptation of the 960gs framework. I have also embedded it below for your convenience.
Posted via email from adlatitude | Comment »
So this weekend I decided to bring together Paul Irish’s HTML5 Boilerplate and Wordpress. I found a few projects on the web already trying to do this… but none that really met my own requirements. That is they didn’t work with the HTML5 Boilerplate build script, and they didn’t make use of wordpress conventions (such as using wp_enqueue_script). The one that came the closest was by Jay George, who by the way has put together and excellent three video tutorial on how to start modifing your wordpress theme to work with HTML5 Boilerplate.
So I spent the weekend hacking away and came up with NakedCompass. Download, use it, modify it… its GPL licensed. Keep in mind it is a work in progress, so if you have any suggestions I am all ears.
In any case, this is not a tutorial… just some results I would like to share. Below are some screenshots of the the before and after optimization speed for page loads. The results may not seem all that significant… but this is a completely naked theme, so seeing any kind of difference is significant and the difference will only increase as the size of the site grows.
Posted via email from adlatitude | Comment »
I just discoverd Sublime Text and in my opinion it is the best text editor that I have used yet. Lacks some of the code intelligence that Coda offers, and the plugins that are available for TextMate. But makes up for it by letting you split your screen into columns, the 10000 mile view, and many other goodies. It’s free to trial so just go and check it out yourself.
Posted via email from adlatitude | Comment »
The scenario: For a project I am working on I wanted an ajax powered navigation menu that worked exactly like a dropdown select box nav menu… i.e. first click opens the dropdown, next click selects the item (link) you want to go to, the dropdown closes, and the link you just selected is now displayed in the ‘select’ box. Doing this using a select box is pretty easy.
So why not just use the select box? Well… initially I did. But then it hit me. I didn’t know whether or not this method was SEO friendly. My gut said no because the select box value is not a link, and after some searching (‘select box navigation seo’) my initial conclusion seemed to be correct. It is not SEO friendly. So I decided to use a bit of CSS and jQuery / Javascript to mimic the functionality that I wanted but still preserve the links for the spiders.
In a nutshell I used absolute positioning, and hidden overflow for the wrapper container so that only the selected item was visible while the dropdown was closed.
The HTML:
Posted via email from adlatitude | Comment »
Programming Praxis http://post.ly/1tPA1
Today’s problem appears with some regularity at places like Proggit and Stack Overflow and in lists of programming interview questions:
Given a binary tree t and two elements of the tree, m and n, with m<n, find the lowest element of the tree (farthest from the root) that is an ancestor of both m and n.
For example, in the tree shown at right, the lowest common ancestor of 4 and 7 is 6, the lowest common ancestor of 4 and 10 is 8, and the lowest common ancestor of 1 and 4 is 3. It is possible for an element of the tree to be its own ancestor, so the lowest common ancestor of 1 and 3 is 3, and the lowest common ancestor of 3 and 6 is 3.
Your task is to write a function that finds the lowest common ancestor of two elements of a binary tree. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Weekly challenges to keep your programming skills and brain from falling into a stuck-in-the-box trap. Who knows… maybe one of these problems will inspire you.
Posted via email from adlatitude | Comment »
Good read on the decline of Myspace. http://j.mp/glFJeK
Legos at work http://post.ly/1qtZd
Architecture and design by Andrii, Johnny, and myself.
We call it… The Deceptive Cabin… complete with swinging doors, draw bridge, death ray, dune buggy, and dismembered individual. This is one cabin you don’t want to mess with.
Posted via email from adlatitude | Comment »
Posted via email from adlatitude | Comment »
If you are trying to add a stylesheet or javascript file from a wordpress plugin, to the best of my knowledge this is how you do it the right way, although perhaps not the best way… see How a Jedi Master Loads Scripts
To add a stylesheet:
function soompi_itunes_load_stylesheet() { $url = plugins_url('/path/to/file.css', __FILE__); wp_register_style('pick_a_unique_name', $url); wp_enqueue_style( 'pick_a_unique_name'); } add_action('wp_print_styles', 'soompi_itunes_load_stylesheet');You can also get the url like this:
$url = WP_PLUGIN_URL . '/soompi-itunes/_inc/css/itunes.css';
But this may cause problems if connecting over ssl. Don’t ask why, I just read it somewhere.
To add a script:
function soompi_itunes_load_script() { $url = plugins_url('/path/to/file.js', __FILE__); wp_register_script('pick_a_unique_name', $url, array('jquery'), 1.0); wp_enqueue_script( 'pick_a_unique_name'); } add_action('init', 'soompi_itunes_load_script');You will notice this is basically the same code. The only real difference is that you are using [wp_register_script] instead of [wp_enqueue_script].
For more a more detailed explanation see the wp codex
Posted via email from adlatitude | Comment »