SlideShare a Scribd company logo
DROPS THAT GROW THE WEB.




First Steps in Code Driven Development
          A 100% database-free development workflow.




                   Antonio De Marco
                      antonio@nuvole.org
Database Driven Development
First Steps in Drupal Code Driven Development
Major pitfalls


• Not ideal for a distributed team
• Makes difficult to push settings to production
• Content and settings are mixed in one db dump
• Easy to lose control
Power to code
Major benefit


• Code can be versioned
• Conflicts can be solved
• Content and settings are separated
• Easy to push updates to production
What the Features module is all about?
Have you noticed that your features don't
 necessarily depend from the Features
               module?
Features is a “hook_default()” generator.


  CCK:           hook_content_default_fields()
  Contexts:      hook_context_default_contexts()
  Fieldgroups:   hook_fieldgroup_default_groups()
  Filters:       hook_filter_default_formats()
  Imagecache:    hook_imagecache_default_presets()
  Menu:          hook_menu_default_items()
  Node type:     hook_node_info()
  Permissions:   hook_user_default_permissions()
  Views:         hook_views_default_views()
/**
 * Helper to implementation of hook_views_default_views().
 */
function _atrium_views_default_views() {
  $views = array();

 // Exported view: atrium_book_current
 $view = new view;
 $view->name = 'atrium_book_current';
 $view->description = 'Atrium: book: helper';
 $view->tag = 'atrium';
 ...
/**
 * Helper to implementation of hook_content_default_fields().
 */
function _atrium_blog_content_default_fields() {
  $fields = array();

  // Exported field: field_referenced_book_page
  $fields[] = array(
    'field_name' => 'field_referenced_book_page',
    'type_name' => 'blog',
    'display_settings' => array(
   ...
Hook helpers are then called from within your feature’s hooks.

/**
  * Implementation of hook_content_default_fields().
  */
function atrium_blog_content_default_fields() {
   module_load_include('inc', 'atrium_blog', 'atrium_blog.defaults');
   $args = func_get_args();
   return call_user_func_array('_atrium_blog_content_default_fields', $args);
}

/**
  * Implementation of hook_views_default_views().
  */
function atrium_views_default_views() {
   module_load_include('inc', 'atrium', 'atrium.features.views');
   $args = func_get_args();
   return call_user_func_array('_atrium_views_default_views', $args);
}
What about the rest?
Do your tables use strings as primary keys?
Do your tables use strings as primary keys?


        Yes?
Do your tables use strings as primary keys?


        Yes? Really?
Do your tables use strings as primary keys?


        Yes? Really? Great! Then...
Meet CTools Export plugin
a.k.a. Get magic by altering your module's schema
An example: Strongarm and variables export.
/**
  * Implementation of hook_schema_alter().
  * Makes the variables table usable by ctools' export.inc.
  */
function strongarm_schema_alter(&$schema) {
   $schema['variable']['export'] = array(
      'key' => 'name',
      'identifier' => 'strongarm',
      'default hook' => 'strongarm',
      'api' => array(
         'owner' => 'strongarm',
         'api' => 'strongarm',
         'minimum_version' => 1,
         'current_version' => 1,
      ),
   );
   $schema['variable']['fields']['value']['serialize'] = TRUE;
}
In your .info file add:

features[variable][] = "theme_default"
First Steps in Drupal Code Driven Development
And you will get:
And you will get:

/**
 * Helper to implementation of hook_strongarm().
 */
function _your_module_strongarm() {
  $export = array();
  $strongarm = new stdClass;
  $strongarm->disabled = FALSE;
  $strongarm->api_version = 1;
  $strongarm->name = 'theme_default';
  $strongarm->value = 'ginkgo';

    $export['theme_default'] = $strongarm;
    return $export;
}
Features keeps track of DB changes.
$ # Dump your changes into code.
$ drush features-update feature_name

$ # Restore your changes into the db.
$ drush features-revert feature_name
Want to add a component to the a feature?
Want to add a component to the a feature?


    1. add it to your feature_name.info
    2. $ drush features-update feature_name
Want to remove a component to the a feature?
Want to remove a component to the a feature?


      1. remove it from your feature_name.info
      2. $ drush features-update feature_name
Code conventions for a better world.
Feature namespace
# Feature News (feature_news)

Views                feature_news_blocks
                     feature_news_list
                     feature_news_node
                     feature_news_taxonomy

Contexts             feature_news_front
                     feature_news_list

Openlayers Presets   feature_news_small_map
                     feature_news_big_map
Content type namespace
# News (news)

CCK Fields           field_news_pictures
                     field_news_links

Imagecache Presets   news-s
                     news-m
                     news-l
                     news-portrait
Tip:


 Never share fields across several content types unless
        you have really good reasons to do so.

If you do so you will make your features hardly re-usable.
Meet your friends hook_install() and hook_update_N()
The Controller Feature
 a.k.a. a feature to rule them all
Create Menus

/**
 * Implementation of hook_install()
 */
function feature_controller_install() {

    db_query("INSERT INTO {menu_custom} (menu_name, title, description)
              VALUES ('%s', '%s', '%s')",
              'menu-content',
              'Content',
              'Manage your site content.');

}
Create Menu Items
/**
 * Implementation of hook_install()
 */
function feature_controller_install() {

    $item['link_title'] = t('Home');
    $item['link_path'] = '<front>';
    $item['menu_name'] = 'primary-links';
    $item['weight'] = -10;
    menu_link_save($item);

}
Do all kind of dirty things...

/**
 * Implementation of hook_install()
 */
function feature_controller_install() {

    // Add OpenID to admin user
    db_query("INSERT INTO {authmap} (uid, authname, module)
              VALUES(1, 'http://nuvole.myopenid.com/', 'openid')");

    // Weight feature_controller to come after other modules -- in particular, admin.
    db_query("UPDATE {system}
              SET weight = 1
              WHERE name = 'feature_controller' AND type = 'module'");
}
hook_update_N()
/**
  * Disabling comment module
  */
function feature_controller_update_6001() {
   $return = array();
   $modules = array('comment');
   module_disable($modules);
   $return[] = array('success' => TRUE,
                      'query' => 'Disabling modules: '.
                      implode(', ', $modules));
   return $return;
}
hook_update_N()
/**
  * Removing contributor role
  */
function feature_controller_update_6002() {
   $return = array();
   $role_name = 'contributor';
   $result = db_query("SELECT rid FROM {role} WHERE name='%s'", $role_name);
   while ($role = db_fetch_object($result)) {
     $rid = $role->rid;
     $return[] = update_sql("DELETE FROM {role} WHERE rid = '$rid'");
     $return[] = update_sql("DELETE FROM {users_roles} WHERE rid = '$rid'");
   }
   return $return;
}
hook_install()

/**
 * Implementation of hook_install()
 */
function feature_controller_install() {

    feature_controller_update_6001();
    feature_controller_update_6002();

}
Features architecture: what goes where.
Views



GROUP BY Arguments, Filters.
Context

      Same context different reactions.



feature_controller_frontpage: News block, Events block




                   That’s bad...
Context

Different contexts share the same conditions.


        feature_news_frontpage: News block
      feature_events_frontpage: Events block



                  That’s Good!
Extending features

    Are we ready?
  Does it make sense?
DROPS THAT GROW THE WEB.




Thank You.
 http://nuvole.org
   @nuvoleweb
   #codepower

More Related Content

What's hot (20)

PPTX
Amp Up Your Admin
Amanda Giles
 
PDF
Angular Promises and Advanced Routing
Alexe Bogdan
 
ZIP
Drupal Development (Part 2)
Jeff Eaton
 
PDF
Virtual Madness @ Etsy
Nishan Subedi
 
PDF
How I started to love design patterns
Samuel ROZE
 
PDF
Drupal Step-by-Step: How We Built Our Training Site, Part 1
Acquia
 
PDF
Silex meets SOAP & REST
Hugo Hamon
 
PDF
Introduction to CQRS and Event Sourcing
Samuel ROZE
 
PDF
Django Class-based views (Slovenian)
Luka Zakrajšek
 
PDF
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
allilevine
 
PPTX
Bacbkone js
Артём Курапов
 
PPTX
Routing in Drupal 8
kgoel1
 
PDF
Your Entity, Your Code
Marco Vito Moscaritolo
 
PDF
Decoupling the Ulabox.com monolith. From CRUD to DDD
Aleix Vergés
 
PPTX
Goodbye hook_menu() - Routing and Menus in Drupal 8
Exove
 
PDF
201104 iphone navigation-based apps
Javier Gonzalez-Sanchez
 
ODP
Drupal 8 Routing
Yuriy Gerasimov
 
PDF
Doctrine For Beginners
Jonathan Wage
 
PDF
Drupal is Stupid (But I Love It Anyway)
brockboland
 
PDF
The Origin of Lithium
Nate Abele
 
Amp Up Your Admin
Amanda Giles
 
Angular Promises and Advanced Routing
Alexe Bogdan
 
Drupal Development (Part 2)
Jeff Eaton
 
Virtual Madness @ Etsy
Nishan Subedi
 
How I started to love design patterns
Samuel ROZE
 
Drupal Step-by-Step: How We Built Our Training Site, Part 1
Acquia
 
Silex meets SOAP & REST
Hugo Hamon
 
Introduction to CQRS and Event Sourcing
Samuel ROZE
 
Django Class-based views (Slovenian)
Luka Zakrajšek
 
WordCamp Montreal 2015: Combining Custom Post Types, Fields, and Meta Boxes t...
allilevine
 
Routing in Drupal 8
kgoel1
 
Your Entity, Your Code
Marco Vito Moscaritolo
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Aleix Vergés
 
Goodbye hook_menu() - Routing and Menus in Drupal 8
Exove
 
201104 iphone navigation-based apps
Javier Gonzalez-Sanchez
 
Drupal 8 Routing
Yuriy Gerasimov
 
Doctrine For Beginners
Jonathan Wage
 
Drupal is Stupid (But I Love It Anyway)
brockboland
 
The Origin of Lithium
Nate Abele
 

Similar to First Steps in Drupal Code Driven Development (20)

PPTX
Extend sdk
Harsha Nagaraj
 
PDF
Symfony2 - from the trenches
Lukas Smith
 
PPTX
AngularJs-training
Pratchaya Suputsopon
 
PDF
Empowering users: modifying the admin experience
Beth Soderberg
 
PPTX
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 
PPTX
Debugging in drupal 8
Allie Jones
 
PDF
ZF2 for the ZF1 Developer
Gary Hockin
 
PDF
Web applications with Catalyst
svilen.ivanov
 
PDF
Symfony2 from the Trenches
Jonathan Wage
 
PPTX
Using the Features API
cgmonroe
 
PDF
前端MVC 豆瓣说
Ting Lv
 
PDF
Building Large jQuery Applications
Rebecca Murphey
 
PDF
Writing Maintainable JavaScript
Andrew Dupont
 
ODP
Zend Framework 1.9 Setup & Using Zend_Tool
Gordon Forsythe
 
PPTX
Magento Live Australia 2016: Request Flow
Vrann Tulika
 
PDF
The state of hooking into Drupal - DrupalCon Dublin
Nida Ismail Shah
 
PDF
"Angular.js Concepts in Depth" by Aleksandar Simović
JS Belgrade
 
PPTX
AngularJS Architecture
Eyal Vardi
 
PPTX
AngularJS Internal
Eyal Vardi
 
PDF
Introduction to angular js
Marco Vito Moscaritolo
 
Extend sdk
Harsha Nagaraj
 
Symfony2 - from the trenches
Lukas Smith
 
AngularJs-training
Pratchaya Suputsopon
 
Empowering users: modifying the admin experience
Beth Soderberg
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
arcware
 
Debugging in drupal 8
Allie Jones
 
ZF2 for the ZF1 Developer
Gary Hockin
 
Web applications with Catalyst
svilen.ivanov
 
Symfony2 from the Trenches
Jonathan Wage
 
Using the Features API
cgmonroe
 
前端MVC 豆瓣说
Ting Lv
 
Building Large jQuery Applications
Rebecca Murphey
 
Writing Maintainable JavaScript
Andrew Dupont
 
Zend Framework 1.9 Setup & Using Zend_Tool
Gordon Forsythe
 
Magento Live Australia 2016: Request Flow
Vrann Tulika
 
The state of hooking into Drupal - DrupalCon Dublin
Nida Ismail Shah
 
"Angular.js Concepts in Depth" by Aleksandar Simović
JS Belgrade
 
AngularJS Architecture
Eyal Vardi
 
AngularJS Internal
Eyal Vardi
 
Introduction to angular js
Marco Vito Moscaritolo
 
Ad

More from Nuvole (14)

PDF
The OpenEuropa Initiative
Nuvole
 
PDF
CMI 2.0 session at Drupal DevDays in Cluj-Napoca
Nuvole
 
PDF
Advanced Configuration Management with Config Split et al.
Nuvole
 
PDF
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Nuvole
 
PDF
Drupal 8 Configuration Management with Features
Nuvole
 
PDF
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Nuvole
 
PDF
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Nuvole
 
KEY
Automating Drupal Development: Makefiles, features and beyond
Nuvole
 
PDF
Building and Maintaining a Distribution in Drupal 7 with Features
Nuvole
 
KEY
Remote Collaboration and Institutional Intranets with Drupal and Open Atrium
Nuvole
 
KEY
Public Works Monitoring
Nuvole
 
PDF
Extending and Customizing Open Atrium
Nuvole
 
PDF
Code driven development: using Features effectively in Drupal 6 and 7
Nuvole
 
PDF
Features based development workflow
Nuvole
 
The OpenEuropa Initiative
Nuvole
 
CMI 2.0 session at Drupal DevDays in Cluj-Napoca
Nuvole
 
Advanced Configuration Management with Config Split et al.
Nuvole
 
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Nuvole
 
Drupal 8 Configuration Management with Features
Nuvole
 
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Nuvole
 
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Nuvole
 
Automating Drupal Development: Makefiles, features and beyond
Nuvole
 
Building and Maintaining a Distribution in Drupal 7 with Features
Nuvole
 
Remote Collaboration and Institutional Intranets with Drupal and Open Atrium
Nuvole
 
Public Works Monitoring
Nuvole
 
Extending and Customizing Open Atrium
Nuvole
 
Code driven development: using Features effectively in Drupal 6 and 7
Nuvole
 
Features based development workflow
Nuvole
 
Ad

Recently uploaded (20)

PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PDF
Biography of Daniel Podor.pdf
Daniel Podor
 
PDF
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Biography of Daniel Podor.pdf
Daniel Podor
 
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 

First Steps in Drupal Code Driven Development

  • 1. DROPS THAT GROW THE WEB. First Steps in Code Driven Development A 100% database-free development workflow. Antonio De Marco [email protected]
  • 4. Major pitfalls • Not ideal for a distributed team • Makes difficult to push settings to production • Content and settings are mixed in one db dump • Easy to lose control
  • 6. Major benefit • Code can be versioned • Conflicts can be solved • Content and settings are separated • Easy to push updates to production
  • 7. What the Features module is all about?
  • 8. Have you noticed that your features don't necessarily depend from the Features module?
  • 9. Features is a “hook_default()” generator. CCK: hook_content_default_fields() Contexts: hook_context_default_contexts() Fieldgroups: hook_fieldgroup_default_groups() Filters: hook_filter_default_formats() Imagecache: hook_imagecache_default_presets() Menu: hook_menu_default_items() Node type: hook_node_info() Permissions: hook_user_default_permissions() Views: hook_views_default_views()
  • 10. /** * Helper to implementation of hook_views_default_views(). */ function _atrium_views_default_views() { $views = array(); // Exported view: atrium_book_current $view = new view; $view->name = 'atrium_book_current'; $view->description = 'Atrium: book: helper'; $view->tag = 'atrium'; ...
  • 11. /** * Helper to implementation of hook_content_default_fields(). */ function _atrium_blog_content_default_fields() { $fields = array(); // Exported field: field_referenced_book_page $fields[] = array( 'field_name' => 'field_referenced_book_page', 'type_name' => 'blog', 'display_settings' => array( ...
  • 12. Hook helpers are then called from within your feature’s hooks. /** * Implementation of hook_content_default_fields(). */ function atrium_blog_content_default_fields() { module_load_include('inc', 'atrium_blog', 'atrium_blog.defaults'); $args = func_get_args(); return call_user_func_array('_atrium_blog_content_default_fields', $args); } /** * Implementation of hook_views_default_views(). */ function atrium_views_default_views() { module_load_include('inc', 'atrium', 'atrium.features.views'); $args = func_get_args(); return call_user_func_array('_atrium_views_default_views', $args); }
  • 13. What about the rest?
  • 14. Do your tables use strings as primary keys?
  • 15. Do your tables use strings as primary keys? Yes?
  • 16. Do your tables use strings as primary keys? Yes? Really?
  • 17. Do your tables use strings as primary keys? Yes? Really? Great! Then...
  • 18. Meet CTools Export plugin a.k.a. Get magic by altering your module's schema
  • 19. An example: Strongarm and variables export.
  • 20. /** * Implementation of hook_schema_alter(). * Makes the variables table usable by ctools' export.inc. */ function strongarm_schema_alter(&$schema) { $schema['variable']['export'] = array( 'key' => 'name', 'identifier' => 'strongarm', 'default hook' => 'strongarm', 'api' => array( 'owner' => 'strongarm', 'api' => 'strongarm', 'minimum_version' => 1, 'current_version' => 1, ), ); $schema['variable']['fields']['value']['serialize'] = TRUE; }
  • 21. In your .info file add: features[variable][] = "theme_default"
  • 23. And you will get:
  • 24. And you will get: /** * Helper to implementation of hook_strongarm(). */ function _your_module_strongarm() { $export = array(); $strongarm = new stdClass; $strongarm->disabled = FALSE; $strongarm->api_version = 1; $strongarm->name = 'theme_default'; $strongarm->value = 'ginkgo'; $export['theme_default'] = $strongarm; return $export; }
  • 25. Features keeps track of DB changes.
  • 26. $ # Dump your changes into code. $ drush features-update feature_name $ # Restore your changes into the db. $ drush features-revert feature_name
  • 27. Want to add a component to the a feature?
  • 28. Want to add a component to the a feature? 1. add it to your feature_name.info 2. $ drush features-update feature_name
  • 29. Want to remove a component to the a feature?
  • 30. Want to remove a component to the a feature? 1. remove it from your feature_name.info 2. $ drush features-update feature_name
  • 31. Code conventions for a better world.
  • 32. Feature namespace # Feature News (feature_news) Views feature_news_blocks feature_news_list feature_news_node feature_news_taxonomy Contexts feature_news_front feature_news_list Openlayers Presets feature_news_small_map feature_news_big_map
  • 33. Content type namespace # News (news) CCK Fields field_news_pictures field_news_links Imagecache Presets news-s news-m news-l news-portrait
  • 34. Tip: Never share fields across several content types unless you have really good reasons to do so. If you do so you will make your features hardly re-usable.
  • 35. Meet your friends hook_install() and hook_update_N()
  • 36. The Controller Feature a.k.a. a feature to rule them all
  • 37. Create Menus /** * Implementation of hook_install() */ function feature_controller_install() { db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", 'menu-content', 'Content', 'Manage your site content.'); }
  • 38. Create Menu Items /** * Implementation of hook_install() */ function feature_controller_install() { $item['link_title'] = t('Home'); $item['link_path'] = '<front>'; $item['menu_name'] = 'primary-links'; $item['weight'] = -10; menu_link_save($item); }
  • 39. Do all kind of dirty things... /** * Implementation of hook_install() */ function feature_controller_install() { // Add OpenID to admin user db_query("INSERT INTO {authmap} (uid, authname, module) VALUES(1, 'http://nuvole.myopenid.com/', 'openid')"); // Weight feature_controller to come after other modules -- in particular, admin. db_query("UPDATE {system} SET weight = 1 WHERE name = 'feature_controller' AND type = 'module'"); }
  • 40. hook_update_N() /** * Disabling comment module */ function feature_controller_update_6001() { $return = array(); $modules = array('comment'); module_disable($modules); $return[] = array('success' => TRUE, 'query' => 'Disabling modules: '. implode(', ', $modules)); return $return; }
  • 41. hook_update_N() /** * Removing contributor role */ function feature_controller_update_6002() { $return = array(); $role_name = 'contributor'; $result = db_query("SELECT rid FROM {role} WHERE name='%s'", $role_name); while ($role = db_fetch_object($result)) { $rid = $role->rid; $return[] = update_sql("DELETE FROM {role} WHERE rid = '$rid'"); $return[] = update_sql("DELETE FROM {users_roles} WHERE rid = '$rid'"); } return $return; }
  • 42. hook_install() /** * Implementation of hook_install() */ function feature_controller_install() { feature_controller_update_6001(); feature_controller_update_6002(); }
  • 45. Context Same context different reactions. feature_controller_frontpage: News block, Events block That’s bad...
  • 46. Context Different contexts share the same conditions. feature_news_frontpage: News block feature_events_frontpage: Events block That’s Good!
  • 47. Extending features Are we ready? Does it make sense?
  • 48. DROPS THAT GROW THE WEB. Thank You. http://nuvole.org @nuvoleweb #codepower