SlideShare a Scribd company logo
1 of 55
Download to read offline
Code-driven Development:
Using Features Effectively in D6 and D7




       Antonio De Marco       Andrea Pescetti
         antonio@nuvole.org    andrea@nuvole.org
Code         Settings
             Content

Filesystem   Database
Code
              Content
Settings

 Filesystem   Database
How can multiple developers work
 together on the same project?
Sharing database dumps?
Major drawbacks


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


• Code can be versioned
• Conflicts can be solved
• Content and settings are separated
• Easy to push changes to production
Features: storing configuration in code
feature_news.info
core = "6.x"
dependencies[] = "context"
dependencies[] = "features"
dependencies[] = "imagecache"
dependencies[] = "imagefield"
description = "Publish news."
features[content][] = "news-field_news_image"
features[context][] = "feature_news_list"
features[ctools][] = "context:context:3"
features[ctools][] = "strongarm:strongarm:1"
features[imagecache][] = "news-badge"
features[imagecache][] = "news-m"
features[imagecache][] = "news-s"
features[node][] = "news"
...
name = "Feature News"
package = "Features"
project = "feature_news"
version = "6.x-1.0-dev"
From DB to code and vice versa


  $ # 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 a feature?


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


  1. remove it from the .info file
  2. $ drush features-update feature_name
Project bootstrap
project.make
project.profile
project.make



core = "6.x"

; Contrib
projects[features][version] = "1.0"
projects[features][subdir] = "contrib"

projects[views][version] = "2.11"
projects[views][subdir] = "contrib"

projects[inline][version] = "1.0"
projects[inline][subdir] = "contrib"

...
project.profile

/**
  * Implementation of hook_profile_details().
  */
function project_profile_details() {
   return array(
      'name' => 'Project',
      'description' => 'Project Description’,
   );
}

/**
 * Implementation of hook_profile_modules().
 */
function project_profile_modules() {

  $modules = array(
    'cck',
    'views',
    'features',
    'feature_controller',
    ...
Use the controller feature
to keep track of development
Enable/disable other features, store sitewide
   configuration, share changes, etc...
Code-driven workflow
Controller Feature Workflow
Developer A




                                                                                        Time
Developer B




                                                                                        Time




              Start: both Developers run installation, Controller Feature is enabled.
Controller Feature Workflow
Developer A




                                                            Time
Developer B




                                                            Time



              Developer A enables Rules module,
              Developer B does other work on the project.
Features are modules.
Modules can be updated via hook_update_N()
hook_update_N()

/**
  * Enabling Rules module
  */
function feature_controller_update_6001() {
   $return = array();
   $modules = array('rules');
   drupal_install_modules($modules);
   $return[] = array('success' => TRUE, 'query' => 'Enabling Rules module');
   return $return;
}




                   feature_controller.install
Controller Feature Workflow

              6001
Developer A




                                                        Time
Developer B




                                                        Time



               DevA$ svn ci -m “Enable Rules module.”
               Developer A commits his changes.
Controller Feature Workflow

              6001
Developer A




                                                                   Time
Developer B




                                                                   Time



                     DevB$ svn up && dr updatedb -y && dr cc all
                     Developer B updates his local copy
                     and wants to remove a user role.
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;
}


                     feature_controller.install
Controller Feature Workflow

              6001
Developer A




                                                                    Time
Developer B




                     6002

                                                                    Time



                      DevB$ svn ci -m “Removed contributor role.”
                      Developer B commits his changes.
Controller Feature Workflow

              6001
Developer A




                                                                           Time
Developer B




                     6002

                                                                           Time



                            Click. Click. Click.
                            DevB$ patch -p0 < inline.patch
                            Click. Click. Click.
                            Developer B adds an OpenID account for admin
                            and patches the Inline module.
hook_update_N()

/**
  * Adding Nuvole OpenID to admin account
  */
function feature_controller_update_6003() {
   $return = array();
   $uid = 1;
   $claimed_id = 'http://admin.myopenid.com/';
   $return[] = update_sql("DELETE FROM {authmap} WHERE authname = '$claimed_id'");
   $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module)
                           VALUES($uid, '$claimed_id', 'openid')");
   return $return;
}


                     feature_controller.install
project.make


...

projects[inline][type] = "module"
projects[inline][download][type] = "cvs"
projects[inline][download][module] = "contributions/modules/inline"
projects[inline][download][revision] = "HEAD:2010-03-06"
projects[inline][subdir] = "contrib"

...

;
; Patches
;
projects[inline][patch][] = "http://drupal.org/files/issues/inline.patch"
Controller Feature Workflow

              6001
Developer A




                                                                            Time
Developer B




                     6002   6003

                                                                            Time



                             DevB$ svn ci -m “Add OpenID for admin. Patching Inline”
                             Developer B commits his changes.
Controller Feature Workflow

              6001
Developer A




                                                                                       Time
Developer B




                     6002   6003

                                                                                       Time
                                   Developer C




                                                                                       Time

                                                 DevC$ svn co http://svn.nuvole.org/project
                                                 Developer C joins.
hook_update_N() is not enough.
 Structural updates go in hook_install() too
Controller Feature Workflow

              6001
Developer A




                                                 Time
Developer B




                     6002   6003

                                                 Time
                                   Developer C




                                                 Time


feature_controller_install()
hook_install()

/**
 * Implementation of hook_install()
 */
function feature_controller_install() {
  $return = array();

    $modules = array('rules');
    drupal_install_modules($modules);
    $return[] = array('success' => TRUE, 'query' => 'Enable Rules module.');

    $uid = 1;
    $claimed_id = 'http://nuvole.myopenid.com/';
    $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module)
                            VALUES($uid, '$claimed_id', 'openid')");
    return $return;
}

                    feature_controller.install
Controller Feature Workflow

              6001
Developer A




                                                                                     Time
Developer B




                     6002   6003

                                                                                     Time
                                   Developer C




                                                                                     Time

                                                 Click. Click. Click.
                                                 Developer C installs the project.
Controller Feature Workflow

              6001
Developer A




                                                                                     Time
Developer B




                     6002   6003

                                                                                     Time
                                   Developer C




                                                                                     Time

                                          Click. Click. Click.
                                          Developer C creates and enables a new feature.
hook_update_N()

/**
  * Enabling News feature
  */
function feature_controller_update_6004() {
   $return = array();
   $modules = array('feature_news');
   features_install_modules($modules);
   $return[] = array('success' => TRUE, 'query' => 'Enabling News');
   return $return;
}




                   feature_controller.install
/**
 * Implementation of hook_install()
 */
function feature_controller_install() {
  $return = array();

    $modules = array('rules');
    drupal_install_modules($modules);
    $return[] = array('success' => TRUE, 'query' => 'Enable Rules module.');

    $uid = 1;
    $claimed_id = 'http://nuvole.myopenid.com/';
    $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module)
                            VALUES($uid, '$claimed_id', 'openid')");

    $modules = array('feature_news');
    features_install_modules($modules);
    $return[] = array('success' => TRUE, 'query' => 'Enabling News');

    return $return;
}

                feature_controller.install
Controller Feature Workflow

              6001
Developer A




                                                                                    Time
Developer B




                     6002   6003

                                                                                    Time
                                   Developer C




                                                 6004

                                                                                    Time

                                                  DevC$ svn ci -m “News Feature.”
                                                  Developer C commits his changes.
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
Features Boundaries
Package functionalities in a logical way
Features Inheritance
 Re-use and extend features
Drupal 7
Installation profiles are like modules
            project.info
           project.install
           project.profile
project.info



name = Project
description = Project Description.
core = 7.x

dependencies[] = "context"
dependencies[] = "features"
dependencies[] = "feature_controller"
...
files[] = project.profile
project.install

/**
  * Enabling Rules module
  */
function project_update_6001() {
   $return = array();
   $modules = array('rules');
   drupal_install_modules($modules);
   $return[] = array('success' => TRUE, 'query' => 'Enabling Rules module');
   return $return;
}


/**
  * Removing contributor role
  */
function project_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;
}
project.profile


/**
 * Implementation of hook_install_tasks()
 */
function project_install_tasks($install_state) {

    ...

}

/**
 * Implementation of hook_form_FORM_ID_alter()
 */
function project_form_install_configure_form_alter(&$form, $form_state) {

    ...

}
http://chicago2011.drupal.org/training/
See also:


Installation Profiles As A Development Tool
              by Florian Loretan


http://bxl2011.drupaldays.org/node/280
Thank You.

 http://nuvole.org
   @nuvoleweb

More Related Content

What's hot

EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5Rob Tweed
 
Salesforce Developer eXperience (SFDX)
Salesforce Developer eXperience (SFDX)Salesforce Developer eXperience (SFDX)
Salesforce Developer eXperience (SFDX)Bohdan Dovhań
 
SFDX - Spring 2019 Update
SFDX - Spring 2019 UpdateSFDX - Spring 2019 Update
SFDX - Spring 2019 UpdateBohdan Dovhań
 
React & Redux for noobs
React & Redux for noobsReact & Redux for noobs
React & Redux for noobs[T]echdencias
 
Training in Android with Maven
Training in Android with MavenTraining in Android with Maven
Training in Android with MavenArcadian Learning
 

What's hot (6)

EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
 
Salesforce Developer eXperience (SFDX)
Salesforce Developer eXperience (SFDX)Salesforce Developer eXperience (SFDX)
Salesforce Developer eXperience (SFDX)
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
SFDX - Spring 2019 Update
SFDX - Spring 2019 UpdateSFDX - Spring 2019 Update
SFDX - Spring 2019 Update
 
React & Redux for noobs
React & Redux for noobsReact & Redux for noobs
React & Redux for noobs
 
Training in Android with Maven
Training in Android with MavenTraining in Android with Maven
Training in Android with Maven
 

Similar to Code driven development: using Features effectively in Drupal 6 and 7

Baking docker using chef
Baking docker using chefBaking docker using chef
Baking docker using chefMukta Aphale
 
Baking Docker Using Chef - ChefConf 2015
Baking Docker Using Chef - ChefConf 2015Baking Docker Using Chef - ChefConf 2015
Baking Docker Using Chef - ChefConf 2015Chef
 
Lightning talk: 12 Factor Containers
Lightning talk: 12 Factor ContainersLightning talk: 12 Factor Containers
Lightning talk: 12 Factor ContainersMukhtar Haji
 
Openshift operator insight
Openshift operator insightOpenshift operator insight
Openshift operator insightRyan ZhangCheng
 
Front end development with Angular JS
Front end development with Angular JSFront end development with Angular JS
Front end development with Angular JSBipin
 
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...Docker, Inc.
 
Spring Boot Loves K8s
Spring Boot Loves K8sSpring Boot Loves K8s
Spring Boot Loves K8sVMware Tanzu
 
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...Sencha
 
Creating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuCreating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuJoe Kutner
 
How to Dockerize your Sitecore module
How to Dockerize your Sitecore moduleHow to Dockerize your Sitecore module
How to Dockerize your Sitecore moduleMihály Árvai
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentNuvole
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containersinside-BigData.com
 
Angular1x and Angular 2 for Beginners
Angular1x and Angular 2 for BeginnersAngular1x and Angular 2 for Beginners
Angular1x and Angular 2 for BeginnersOswald Campesato
 
Tech Talk: DevOps at LeanIX @ Startup Camp Berlin
Tech Talk: DevOps at LeanIX @ Startup Camp BerlinTech Talk: DevOps at LeanIX @ Startup Camp Berlin
Tech Talk: DevOps at LeanIX @ Startup Camp BerlinLeanIX GmbH
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-senseBen Lin
 
How to create an Angular builder
How to create an Angular builderHow to create an Angular builder
How to create an Angular builderMaurizio Vitale
 
Introducing Pebble SDK 2.0
Introducing Pebble SDK 2.0Introducing Pebble SDK 2.0
Introducing Pebble SDK 2.0Cherie Williams
 

Similar to Code driven development: using Features effectively in Drupal 6 and 7 (20)

Baking docker using chef
Baking docker using chefBaking docker using chef
Baking docker using chef
 
Baking Docker Using Chef - ChefConf 2015
Baking Docker Using Chef - ChefConf 2015Baking Docker Using Chef - ChefConf 2015
Baking Docker Using Chef - ChefConf 2015
 
Lightning talk: 12 Factor Containers
Lightning talk: 12 Factor ContainersLightning talk: 12 Factor Containers
Lightning talk: 12 Factor Containers
 
Openshift operator insight
Openshift operator insightOpenshift operator insight
Openshift operator insight
 
Front end development with Angular JS
Front end development with Angular JSFront end development with Angular JS
Front end development with Angular JS
 
Codegnitorppt
CodegnitorpptCodegnitorppt
Codegnitorppt
 
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
Build, Publish, Deploy and Test Docker images and containers with Jenkins Wor...
 
Spring Boot Loves K8s
Spring Boot Loves K8sSpring Boot Loves K8s
Spring Boot Loves K8s
 
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...
SenchaCon 2016: Enterprise Applications, Role Based Access Controls (RBAC) an...
 
Creating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on HerokuCreating Scalable JVM/Java Apps on Heroku
Creating Scalable JVM/Java Apps on Heroku
 
How to Dockerize your Sitecore module
How to Dockerize your Sitecore moduleHow to Dockerize your Sitecore module
How to Dockerize your Sitecore module
 
First Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven Development
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containers
 
Angular1x and Angular 2 for Beginners
Angular1x and Angular 2 for BeginnersAngular1x and Angular 2 for Beginners
Angular1x and Angular 2 for Beginners
 
Tech Talk: DevOps at LeanIX @ Startup Camp Berlin
Tech Talk: DevOps at LeanIX @ Startup Camp BerlinTech Talk: DevOps at LeanIX @ Startup Camp Berlin
Tech Talk: DevOps at LeanIX @ Startup Camp Berlin
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-sense
 
DevRock #01 What's new ASP.net 5
DevRock #01 What's new ASP.net 5DevRock #01 What's new ASP.net 5
DevRock #01 What's new ASP.net 5
 
How to create an Angular builder
How to create an Angular builderHow to create an Angular builder
How to create an Angular builder
 
Introducing Pebble SDK 2.0
Introducing Pebble SDK 2.0Introducing Pebble SDK 2.0
Introducing Pebble SDK 2.0
 
Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0Announcing Pebble SDK 2.0
Announcing Pebble SDK 2.0
 

More from Nuvole

The OpenEuropa Initiative
The OpenEuropa InitiativeThe OpenEuropa Initiative
The OpenEuropa InitiativeNuvole
 
CMI 2.0 session at Drupal DevDays in Cluj-Napoca
CMI 2.0 session at Drupal DevDays in Cluj-NapocaCMI 2.0 session at Drupal DevDays in Cluj-Napoca
CMI 2.0 session at Drupal DevDays in Cluj-NapocaNuvole
 
Advanced Configuration Management with Config Split et al.
Advanced Configuration Management with Config Split et al.Advanced Configuration Management with Config Split et al.
Advanced Configuration Management with Config Split et al.Nuvole
 
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...Nuvole
 
Drupal 8 Configuration Management with Features
Drupal 8 Configuration Management with FeaturesDrupal 8 Configuration Management with Features
Drupal 8 Configuration Management with FeaturesNuvole
 
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)Nuvole
 
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)Nuvole
 
Automating Drupal Development: Makefiles, features and beyond
Automating Drupal Development: Makefiles, features and beyondAutomating Drupal Development: Makefiles, features and beyond
Automating Drupal Development: Makefiles, features and beyondNuvole
 
Building and Maintaining a Distribution in Drupal 7 with Features
Building and Maintaining a  Distribution in Drupal 7 with FeaturesBuilding and Maintaining a  Distribution in Drupal 7 with Features
Building and Maintaining a Distribution in Drupal 7 with FeaturesNuvole
 
Remote Collaboration and Institutional Intranets with Drupal and Open Atrium
Remote Collaboration and Institutional Intranets with Drupal and Open AtriumRemote Collaboration and Institutional Intranets with Drupal and Open Atrium
Remote Collaboration and Institutional Intranets with Drupal and Open AtriumNuvole
 
Public Works Monitoring
Public Works MonitoringPublic Works Monitoring
Public Works MonitoringNuvole
 
Extending and Customizing Open Atrium
Extending and Customizing Open AtriumExtending and Customizing Open Atrium
Extending and Customizing Open AtriumNuvole
 

More from Nuvole (12)

The OpenEuropa Initiative
The OpenEuropa InitiativeThe OpenEuropa Initiative
The OpenEuropa Initiative
 
CMI 2.0 session at Drupal DevDays in Cluj-Napoca
CMI 2.0 session at Drupal DevDays in Cluj-NapocaCMI 2.0 session at Drupal DevDays in Cluj-Napoca
CMI 2.0 session at Drupal DevDays in Cluj-Napoca
 
Advanced Configuration Management with Config Split et al.
Advanced Configuration Management with Config Split et al.Advanced Configuration Management with Config Split et al.
Advanced Configuration Management with Config Split et al.
 
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
Introducing the UI Patterns module: use atomic UI components everywhere in Dr...
 
Drupal 8 Configuration Management with Features
Drupal 8 Configuration Management with FeaturesDrupal 8 Configuration Management with Features
Drupal 8 Configuration Management with Features
 
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
Configuration Management in Drupal 8: A preview (DrupalCamp Alpe Adria 2014)
 
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
Configuration Management in Drupal 8: A preview (DrupalDays Milano 2014)
 
Automating Drupal Development: Makefiles, features and beyond
Automating Drupal Development: Makefiles, features and beyondAutomating Drupal Development: Makefiles, features and beyond
Automating Drupal Development: Makefiles, features and beyond
 
Building and Maintaining a Distribution in Drupal 7 with Features
Building and Maintaining a  Distribution in Drupal 7 with FeaturesBuilding and Maintaining a  Distribution in Drupal 7 with Features
Building and Maintaining a Distribution in Drupal 7 with Features
 
Remote Collaboration and Institutional Intranets with Drupal and Open Atrium
Remote Collaboration and Institutional Intranets with Drupal and Open AtriumRemote Collaboration and Institutional Intranets with Drupal and Open Atrium
Remote Collaboration and Institutional Intranets with Drupal and Open Atrium
 
Public Works Monitoring
Public Works MonitoringPublic Works Monitoring
Public Works Monitoring
 
Extending and Customizing Open Atrium
Extending and Customizing Open AtriumExtending and Customizing Open Atrium
Extending and Customizing Open Atrium
 

Code driven development: using Features effectively in Drupal 6 and 7

  • 1. Code-driven Development: Using Features Effectively in D6 and D7 Antonio De Marco Andrea Pescetti antonio@nuvole.org andrea@nuvole.org
  • 2. Code Settings Content Filesystem Database
  • 3. Code Content Settings Filesystem Database
  • 4. How can multiple developers work together on the same project?
  • 6.
  • 7. Major drawbacks • Not ideal for a distributed team • Makes it difficult to push settings to production • Content and settings are mixed in one db dump • Easy to lose control
  • 9. Major benefits • Code can be versioned • Conflicts can be solved • Content and settings are separated • Easy to push changes to production
  • 11. feature_news.info core = "6.x" dependencies[] = "context" dependencies[] = "features" dependencies[] = "imagecache" dependencies[] = "imagefield" description = "Publish news." features[content][] = "news-field_news_image" features[context][] = "feature_news_list" features[ctools][] = "context:context:3" features[ctools][] = "strongarm:strongarm:1" features[imagecache][] = "news-badge" features[imagecache][] = "news-m" features[imagecache][] = "news-s" features[node][] = "news" ... name = "Feature News" package = "Features" project = "feature_news" version = "6.x-1.0-dev"
  • 12. From DB to code and vice versa $ # Dump your changes into code. $ drush features-update feature_name $ # Restore your changes into the db. $ drush features-revert feature_name
  • 13. Want to add a component to a feature? 1. add it to the .info file 2. $ drush features-update feature_name
  • 14. Want to remove a component from a feature? 1. remove it from the .info file 2. $ drush features-update feature_name
  • 17. project.make core = "6.x" ; Contrib projects[features][version] = "1.0" projects[features][subdir] = "contrib" projects[views][version] = "2.11" projects[views][subdir] = "contrib" projects[inline][version] = "1.0" projects[inline][subdir] = "contrib" ...
  • 18. project.profile /** * Implementation of hook_profile_details(). */ function project_profile_details() { return array( 'name' => 'Project', 'description' => 'Project Description’, ); } /** * Implementation of hook_profile_modules(). */ function project_profile_modules() { $modules = array( 'cck', 'views', 'features', 'feature_controller', ...
  • 19. Use the controller feature to keep track of development Enable/disable other features, store sitewide configuration, share changes, etc...
  • 21. Controller Feature Workflow Developer A Time Developer B Time Start: both Developers run installation, Controller Feature is enabled.
  • 22. Controller Feature Workflow Developer A Time Developer B Time Developer A enables Rules module, Developer B does other work on the project.
  • 23. Features are modules. Modules can be updated via hook_update_N()
  • 24. hook_update_N() /** * Enabling Rules module */ function feature_controller_update_6001() { $return = array(); $modules = array('rules'); drupal_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enabling Rules module'); return $return; } feature_controller.install
  • 25. Controller Feature Workflow 6001 Developer A Time Developer B Time DevA$ svn ci -m “Enable Rules module.” Developer A commits his changes.
  • 26. Controller Feature Workflow 6001 Developer A Time Developer B Time DevB$ svn up && dr updatedb -y && dr cc all Developer B updates his local copy and wants to remove a user role.
  • 27. 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; } feature_controller.install
  • 28. Controller Feature Workflow 6001 Developer A Time Developer B 6002 Time DevB$ svn ci -m “Removed contributor role.” Developer B commits his changes.
  • 29. Controller Feature Workflow 6001 Developer A Time Developer B 6002 Time Click. Click. Click. DevB$ patch -p0 < inline.patch Click. Click. Click. Developer B adds an OpenID account for admin and patches the Inline module.
  • 30. hook_update_N() /** * Adding Nuvole OpenID to admin account */ function feature_controller_update_6003() { $return = array(); $uid = 1; $claimed_id = 'http://admin.myopenid.com/'; $return[] = update_sql("DELETE FROM {authmap} WHERE authname = '$claimed_id'"); $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module) VALUES($uid, '$claimed_id', 'openid')"); return $return; } feature_controller.install
  • 31. project.make ... projects[inline][type] = "module" projects[inline][download][type] = "cvs" projects[inline][download][module] = "contributions/modules/inline" projects[inline][download][revision] = "HEAD:2010-03-06" projects[inline][subdir] = "contrib" ... ; ; Patches ; projects[inline][patch][] = "http://drupal.org/files/issues/inline.patch"
  • 32. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time DevB$ svn ci -m “Add OpenID for admin. Patching Inline” Developer B commits his changes.
  • 33. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time Developer C Time DevC$ svn co http://svn.nuvole.org/project Developer C joins.
  • 34. hook_update_N() is not enough. Structural updates go in hook_install() too
  • 35. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time Developer C Time feature_controller_install()
  • 36. hook_install() /** * Implementation of hook_install() */ function feature_controller_install() { $return = array(); $modules = array('rules'); drupal_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enable Rules module.'); $uid = 1; $claimed_id = 'http://nuvole.myopenid.com/'; $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module) VALUES($uid, '$claimed_id', 'openid')"); return $return; } feature_controller.install
  • 37. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time Developer C Time Click. Click. Click. Developer C installs the project.
  • 38. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time Developer C Time Click. Click. Click. Developer C creates and enables a new feature.
  • 39. hook_update_N() /** * Enabling News feature */ function feature_controller_update_6004() { $return = array(); $modules = array('feature_news'); features_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enabling News'); return $return; } feature_controller.install
  • 40. /** * Implementation of hook_install() */ function feature_controller_install() { $return = array(); $modules = array('rules'); drupal_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enable Rules module.'); $uid = 1; $claimed_id = 'http://nuvole.myopenid.com/'; $return[] = update_sql("INSERT INTO {authmap}(uid, authname, module) VALUES($uid, '$claimed_id', 'openid')"); $modules = array('feature_news'); features_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enabling News'); return $return; } feature_controller.install
  • 41. Controller Feature Workflow 6001 Developer A Time Developer B 6002 6003 Time Developer C 6004 Time DevC$ svn ci -m “News Feature.” Developer C commits his changes.
  • 42. Code conventions for a better world.
  • 43.
  • 44. 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
  • 45. Content type namespace # News (news) CCK Fields field_news_pictures field_news_links Imagecache Presets news-s news-m news-l news-portrait
  • 47. Features Inheritance Re-use and extend features
  • 49. Installation profiles are like modules project.info project.install project.profile
  • 50. project.info name = Project description = Project Description. core = 7.x dependencies[] = "context" dependencies[] = "features" dependencies[] = "feature_controller" ... files[] = project.profile
  • 51. project.install /** * Enabling Rules module */ function project_update_6001() { $return = array(); $modules = array('rules'); drupal_install_modules($modules); $return[] = array('success' => TRUE, 'query' => 'Enabling Rules module'); return $return; } /** * Removing contributor role */ function project_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; }
  • 52. project.profile /** * Implementation of hook_install_tasks() */ function project_install_tasks($install_state) { ... } /** * Implementation of hook_form_FORM_ID_alter() */ function project_form_install_configure_form_alter(&$form, $form_state) { ... }
  • 54. See also: Installation Profiles As A Development Tool by Florian Loretan http://bxl2011.drupaldays.org/node/280