Drupal Planet

Syndicate content
drupal.org - aggregated feeds in category Planet Drupal
Updated: 7 weeks 2 days ago

Matthew Saunders: Day 2 - The Examiner Time Box Marches On

Tue, 12/06/2011 - 22:19

Day 2 - More Planning

Day 2 of this shortened timebox was the second of our Technical Planning days. As I mentioned in my previous post, we have two half days of Technical Architecture/Planning at the beginning of the time box. We continued to review details on the user stories for this box and also tightened our estimates a little bit for remaining stories. We look at whether we need to write code from scratch, we can make use of community code, or enhance community code from the Drupal project.

We colour code our stories - white for not scheduled, yellow for scheduled and committed to, greeen for QA ready, salmon when we need more information, and grey for stories that we defer for future timeboxes. We re-reviewed stories from yesterday for which we needed clarifications. These visual queues make it really easy to scan the Google spreadsheet(s) and see the status of a given story.

Our story spreadsheet header describes the information we're looking to capture for hand off to the development team.

read more

Categories: Drupal

Janez Urevc: How to get client's IP number to Drupal when using Varnish

Tue, 12/06/2011 - 18:50

There are a lot of places, where you need client's IP address in Drupal (or any other CMS/web app of course). The problem arises, when you use a reverse proxy server (like Varnish), since every request to web server will be done by the latter. We will have every single visitor of our website coming from a single IP (reverse proxy), as a result.

Drupal is smart enough to overcome that. Reverse proxy servers can be configured to forward original client IP in a request header (usually X-Forwarded-For). This value can be used on web server to know where our visitory come from. In Drupal we have function ip_address(), which will read and return client's IP. If we take a look at this function's code, we can see that it already has support for situations, where reverse proxy is used. This function will still return Varnish's IP address by default, though.

To make things working as we expected, we have to configure at least two variables in settings.php:

// Tell Drupal that we are behind a reverse proxy server $conf['reverse_proxy'] = TRUE; // List of trusted IPs (IP numbers of our reverse proxies) $conf['reverse_proxy_addresses'] = array( '127.0.0.1', );

That's it. Now ip_address() returns IP number that was sent via request header. There is also a possibility to use custom header name:

// Drupal will look for IP in $_SERVER['HTTP_MY_CUSTOM_HEADER'] $conf['reverse_proxy_header'] = 'HTTP_MY_CUSTOM_HEADER';
Categories: Drupal

Drupal Association News: New membership directory

Tue, 12/06/2011 - 15:47

We improved our individual and organization membership directories. Information is now from your Drupal.org profile. If you are a member, please take a moment to search for your username to check what is listed. If you need to update, there are instructions at the top-right of the page. And thanks again for your support! If you aren't a member, you can join today.

Categories: Drupal

Mediacurrent: An Inside Look at the Omega Theme

Tue, 12/06/2011 - 12:32
The Mobile First Approach

When people say "mobile first" in referring to web design & theming, it's not just a mentality or something people say in a "the way it ought to be" sort of sense. They literally mean, designing the mobile theme first, then adding on CSS for tablets, desktop, and wide desktop themes. In a technical sense, it means that the global.css that contains the basic design elements of the site is loaded no matter what device you are using to view the website. Then, CSS3 Media queries determine what the size of the window is and additional stylesheets will be tacked on; either "narrow", "normal" , or "wide" - depending on the width of the device.  

Categories: Drupal

Matt Butcher: Building a Custom Drupal Image for Vagrant

Tue, 12/06/2011 - 10:15

Not too long ago, I posted a blog entry about 5 reasons for using a virtual machine for Drupal development. At the suggestion of some commentors, I have started looking into using Vagrant to manage my VMs. There is an excellent Drupal Vagrant project that provides a great starting point. This article explains how to begin with that and modify it to suit your own needs.

read more

Categories: Drupal

Acquia: Getting beyond "free" - UK government uptake of open source

Tue, 12/06/2011 - 07:43
Misplaced priorities hampering UK government uptake of open source

According to a computing.co.uk article entitled Open Source: The government's commitment so far, most of the IT technology used in the UK government is still proprietary and comes from single vendors.

Open Source adoption by government agencies in the UK is progressing, but is still being hindered by a focus on "free as in gratis". Decisions based on cost-of-acquisition alone ignore the other real and more important values offered by open source, which are derived from "free as in freedom".

A policy was set out in 2004 to "level the playing field" for open source solutions in the UK government. Open source solutions are in use in a variety of departments there. Drupal powers the UK Cabinet Office website, among others. The open source policy statement was reiterated in 2009, 2010, and in October 2011 a new "Strategic Implementation Plan" (SIP) covered much of the same ground. Change has been slow to come, but things are looking promising.

The 2011 Strategic Implementation Plan includes an Open Source Procurement Toolkit to facilitate and help put into action the UK government's stated policy, "Where appropriate, Government will procure open source solutions."

"Free as in gratis" is not the point

So far, so good, but there's at least one problem. The Strategic Action Plan calls for open source solutions to be considered fairly against proprietary solutions based on "value for money and total cost of ownership".

Psychologically, the "free" in "free and open source software" is a huge trump. Dan Ariely, in the chapter of Predictably Irrational called "The Cost of Zero Cost", discussed the power of FREE! (as he calls it). One of the conclusions he comes to after a series of controlled experiments is that FREE! can blind us, to the point of irrationality, to the importance of other factors.

Proprietary software vendors understand this irrationality and in at least one case, have successfully offered one-time, 100% discounts on their software when threatened with a move to an open source alternative. The power of FREE! (right now!) blinded those involved to the long-term consequences and costs of future license- and upgrade fees, as well as being locked in to proprietary formats, which can force further investment in proprietary solutions.

Simon Phipps, writing on opensource.com says,

"The fact that open source software can be obtained without payment of a license fee is a cruel distraction from the real values."

Jeff Eaton made the same point this year at the Do it With Drupal conference,

"[Open source software] just happens to have a zero price tag, you're still responsible for it."

Both Phipps and Eaton make the point that focusing on a price of zero undermines the real values and strengths of open source solutions like Drupal. Eaton goes on to present better arguments for adopting open source, calling FREE! the worst one on the list.

Focus on the real values of open source

Here are some values that proprietary software cannot offer based on the very definition of open source itself:

  • Use it: You are free to use open source for anything, anywhere, no matter what. In the restaurant business, they say, "You gotta own the bricks." Do you want your government basing its services on something that it has no control over, has to pay for over and over again, that others can arbitrarily turn off, change or charge more for?
  • Study it: You are free to understand what you are getting, no hidden surprises. As Eaton puts it, "The bad dies or the bad gets fixed." Quality and security are common outcomes of transparency.
  • Modify it: You control your destiny. With open source you have the freedom to build what you need when you need it. If a proprietary solution is buggy, it might never be fixed. If it only does 80% of what you need, when do you get the other 20%? Your priorities might not match the proprietary developer's product roadmap.
  • Share it: You are free to reuse the best solutions out there. Improve efficiency by building on the shoulders of giants. If you start with an 80% solution based on the work of the Drupal community and build the very best solution for your organization, you can pass it on to your colleagues, other departments, or the whole world, just like the White House did.
It's getting better all the time

Government agencies and departments in the UK are beginning to focus on the real value propositions offered by open source. For instance, the UK government held consultations in 2011 on adopting open standards and intends to have in place a core set of open standards by June 2012. This is a big step in the right direction. The CIO and senior responsibility officer for open source and open standards of the UK Home Office, Robin Pape, contends that, "Open standards are the real enabler for change." Proprietary solutions are not traditionally focused on these standards–or are actively against them–and Pape concludes, "Open source software is part of the opportunity that arises [from their adoption]."

2012 is looking good for public-sector open source software adoption in the UK.

Tags: open sourceUKgovernmentDrupalvaluefreedomtransparencyacquia drupal planet
Categories: Drupal

Baris Wanschers: Exporting your module configuration using Ctools or with custom code - when to use which method?

Tue, 12/06/2011 - 03:39

When I recently joined Scott Reynen as maintainer of the @font-your-face module (blog post), one of the first tasks on my list was to enable site builders to save their font settings using Features. For those not known with Features; it’s a module that saves database settings (views, content types, variables etc) to code. This enables you to save (various) versions of your site in VCS and then move settings from development/staging/production without ‘clicking’. Features is pluggable: if a module has its own hooks for Features, it settings may be exported as well. A lot of contrib modules already come with Features implementation (Views, Rules, Context, Boxes, etc) and we thought it’d be great if we could add @font-your-face to this list as well.


The Features integration of the @font-your-face module

There are basically two options to make your module exportable: using Ctools or by writing your custom code. Using Ctools is by far the easiest and simplest method to implement, but it comes with some limitations. Using custom code gives you more flexibility, but it involves also a bit more effort.

Exporting configuration using Ctools

Ctools (chaos tools suite) is an API module used by more and more contrib modules. Panels, Views, Rules UI, Boxes, Context; all of them rely on Ctools. It comes with an export API that you can use to export your own module configuration in a standardized way. It involves three simple steps:

  1. Define the data you want to export by expanding your hook_schema() with an ‘export’ part.
  2. Write a load() function
  3. Write a save() function

Stella wrote a great blog post about this method and more details can be found on Drupal.org: http://drupal.org/node/928026

Basically, Ctools export moves your database settings to code and once they are exported, Drupal doesn’t use the database entries anymore. This method works great in most use cases. And the good thing is that it comes with an admin interface where you can enable/disable/revert your custom settings, similar to the interface that comes with Context and Views. But I found two drawbacks that made that I couldn’t use this method for the @font-your-face module:

1. The ‘Create Feature’ interface lists ALL settings, even those that are not enabled

This works fine if you have ten content types, or twenty views. But with @font-your-face you can import several thousands of fonts and then enable just a few of them. As Features shows all configurations independent of their state, the lists of Components became extremely long and slow to use. I couldn’t find a way to filter this list of checkboxes using the default Ctools Export UI.

2. The exported configurations cannot be retrieved using Views

The function that loads all your objects (ctools_export_crud_load_all()) first retrieves all the stored settings from your code and then combines this with the database settings for all settings that have not been exported. The @font-your-face admin interface uses a nifty Views interface to simplify the admin UI. It shows all the imported fonts (which can be a several thousand) in a nice interface with filters, sorts, etc. By exporting fonts using Ctools they were moved out of the database and thus cannot be retrieved by Views anymore.

I’ve posted an issue in the Ctools issue queue to highlight my findings and merlinofchaos confirmed this behaviour. As Scott and I didn’t want to give up the Views admin interface, we needed another method.

Exporting configuration using custom code

It is also possible to write your own hooks for features. By doing so, you can define which configrations to show in the export interface, and how they are loaded. I’ll show the code that I’ve used for the @font-your-face module as this explains better how it works. The steps needed to get this working are:

1. Make your module known to Features using hook_features_api()

Implement hook_features_api() in your .module file (fontyourface.module).

/** * Implements hook_features_api(). */ function fontyourface_features_api() { return array( 'fontyourface' => array( 'name' => '@font-your-face', 'file' => drupal_get_path('module', 'fontyourface') . '/fontyourface.features.inc', 'default_hook' => 'fontyourface_features_default_font', 'feature_source' => TRUE, ), ); } 2. Define which settings you want to list in the export UI using hook_features_export_options()

This hook will alert features of which specific items of this component may be exported. For instances, in this case, we want to make available all the existing items.  If there are no items to be exported, this component will not be made available in the features export page.

/** * @return array * A keyed array of items, suitable for use with a FormAPI select or * checkboxes element. */ function fontyourface_features_export_options() { $fonts = array(); foreach (fontyourface_get_fonts('enabled = 1') as $font) { $fonts[$font->name] = $font->name; } return $fonts; } 3. Use hook_features_export() to add your dependencies to the FEATURENAME.info file

This is a component hook, rather then a module hook, therefore this is the callback from hook_features_api which relates to the specific component we are looking to export.  When a specific instance of the component we are looking to export is selected, this will include the necessary item, plus any dependencies into our export array.

/** * @param array $data * this is the machine name for the component in question * @param array &$export * array of all components to be exported * @param string $module_name * The name of the feature module to be generated. * @return array * The pipe array of further processors that should be called */ function fontyourface_features_export($data, &$export, $module_name = '') { // fontyourface_default_fonts integration is provided by Features. $export['dependencies']['features'] = 'features'; $export['dependencies']['fontyourface'] = 'fontyourface'; // Add dependencies for each font. $fonts = fontyourface_get_fonts('enabled = 1'); foreach ($fonts as $font) { if (in_array($font->name, $data)) { // Make the font provider required $export['dependencies'][$font->provider] = $font->provider; $export['features']['fontyourface'][$font->name] = $font->name; } } return $export; } 4. hook_features_export_render() renders the actual settings to export

This hook will be invoked in order to export Component hook. The hook should be implemented using the name ot the component, not the module, eg. [component]_features_export() rather than [module]_features_export().

/** * Render one or more component objects to code. * * @param string $module_name * The name of the feature module to be exported. * @param array $data * An array of machine name identifiers for the objects to be rendered. * @param array $export * The full export array of the current feature being exported. This is only * passed when hook_features_export_render() is invoked for an actual feature * update or recreate, not during state checks or other operations. * @return array * An associative array of rendered PHP code where the key is the name of the * hook that should wrap the PHP code. The hook should not include the name * of the module, e.g. the key for `hook_example` should simply be `example`. */ function fontyourface_features_export_render($module, $data) { $fonts = fontyourface_get_fonts('enabled = 1'); $code = array(); foreach ($data as $name) { foreach ($fonts as $font) { if ($font->name == $name) { unset($font->fid); // unset the identifier, as this may not be the same on other environments (staging/production/etc) $code[$name] = $font; } } } $code = " return " . features_var_export($code, ' ') . ";"; return array('fontyourface_features_default_font' => $code); } 5. And finally, make sure your module loads it settings from the exported code once a feature gets reverted. /** * Implements hook_features_revert(). */ function fontyourface_features_revert($module) { fontyourface_features_rebuild($module); } /** * Implements hook_features_rebuild(). * * Rebuilds @font-your-face fonts from code defaults. */ function fontyourface_features_rebuild($module) { $saved_fonts = module_invoke($module, 'fontyourface_features_default_font'); foreach ($saved_fonts as $key => $font) { $font = (object) $font; $saved = fontyourface_save_font($font, TRUE); // Here it gets saved in the database -> TRUE overrides existing fonts. } } So, which method to use when?

If your custom module has only a small amount of configurations (like Views, Rules, Context, etc) the Ctools way is a great and standarized way to get you up to speed. It comes with a nice admin UI and the time to implement Features integration in your module using this method can be done within 30 minutes.

If your module has a lot of possible configurations (like hundreds) or if you use Views to list all available configurations – you might be better of without Ctools.

Thoughts? Comments? Please let me know in the comments!

Tags:  Drupal Modules Features Planet Drupal Ctools Views @font-your-face
Categories: Drupal

Drupal 8 Initiatives: WSCCI Status Meeting - 2011-12-06

Tue, 12/06/2011 - 01:21
Start:  2011-12-06 12:00 - 13:00 America/New_York Online meeting (eg. IRC meeting) Organizers:  Crell

It's time for another pow-wow on WSCCI! This week the main topic will be the ongoing reviews and discussions of the Context API. There's been a lot of discussion lately, and I want us to take a moment to consider the feedback to date and see what our next steps are/should be.

If you haven't read the discussion there, please do so before the meeting so we are all on the same page!

AttachmentSize log-2011-12-06.txt24.98 KB Drupal 8 Initiatives
Categories: Drupal

Matthew Saunders: The Life of an Agile Timebox @Examiner

Tue, 12/06/2011 - 00:22

An Introduction to the Next 15 Work Days
I've been writing a lot about process lately. Examiner.com is one of the largest Drupal sites in the wild. It was migrated from Cold Fusion to Drupal - a process that began about two years ago.

The Examiner development experience has moved through a wide variety of styles, tools, and methodologies over the last two years. Through blog posts and presentations, a fair bit of information is being shared about how we operate. When I was in Austin presenting, a fairly significant number of folks asked specific questions about our "Generic Timebox". I wanted to answer all the questions, but ran out of time that afternoon.

For this timebox we are using a compressed time-line. Our normal interval is 20 days - in this case we are shaving off a week and making it 15 days because of the holidays. Still, all the elements that are in our normal period are reflected in this series of days making it pretty much perfect to (hopefully) answer the questions I was being asked.

read more

Categories: Drupal

Janez Urevc: slovenskenovice.si - biggest Slovenian Drupal site

Mon, 12/05/2011 - 17:15

Slovenske novice are Slovenian national daily newspaper with largest circulation on national level. Last week we lunched redesign of it's web variant, which is a news portal with about 200.000 unique visitors and 4.5 million impressions per month. This numbers wil definetely become larger soon, as they have monthly growth between 10 and 15%.

Site was developed on Drupal 7. We extensively used Panels and Views. Search is based on Apache Solr, driven by Search API framework. To achieve performance we used Memcached, Varnish, APC and developed some own cache expiration rules. This is how we achieved performance we needed and flexibility requested by editorial team. Everything is hosted on our own HA LAMP stack.

Just two days after launch we had national elections in Slovenia, which are also a big media event. Our site broke the record in daily visits and everything was working smooth.

Since a custom CMS, which was developed inside company about 10 years ago, was used before, one of the most important aspects of this project was experience for editorial team. They learned how to use Drupal surprisingly fast. There were some minor issues reported, but in general Drupal works really got for them.

Site was developed by core development team:

We also had some themeing help from Iztok Smolič (@Iztok). 

We will publish some more information about project in the following weeks.

Categories: Drupal

Lullabot: Module Monday: Absolute Messages

Mon, 12/05/2011 - 14:00

Drupal's assorted status and warning messages give users and administrators important information about what's happening on a site. They're a bit dull, though, and can easily blend in with the rest of a site's content. In addition,while most Drupal features provide copious hooks for developers to tweak, there's no simple way to hide some messages and show others, alter the text of a given message, and so on.

Absolute Messages fixes that, layering some snappy display options onto Drupal's normal message system and giving developers a set of convenient hooks to manipulate messages while before they're displayed.

The most visible change once you've installed Absolute Messages is the appearance of Drupal's system messages. They appear at the top of the screen, in color-coded boxes with their own 'Dismiss This Message' close boxes. The style is modeled after the popular Stack Overflow site, and it duplicates some of the site's behaviors as well. Long messages can be collapsed to just a few lines, expanding when the user mouses over them, and normal status messages can automatically close themselves after a few seconds.

Behind the scenes, these rules can be configured for each type of message -- Status, Warning, and Error -- ensuring that important notices don't go away while a user isn't looking.

Categories: Drupal

Mearra: Radioactivity 2: basics

Mon, 12/05/2011 - 05:04

With Radioactivity 2 nearly out of its beta form, I thought I'd write a bit about what it is and what you can do with it and most importantly walk you through on how to use it.

Radioactivity 2 allows you to track any fieldable entities; users, nodes, commerce products, etc. It can be used as a simple view counter but also as a popularity or activity meter, e.g. with it you can create a 'most viewed nodes at this moment' list. There is also limited rules which allows you to create an activity meter for basically whatever you want. 

For this tutorial we need to install and enable views, ctools and the radioactivity modules.

After that we need to create three things:

  1. Decay profile
  2. Radioactivity field
  3. View

Before we dwell deeper lets go through some of the terminology and settings.

Terminology
  • Energy: the hotness/popularity/views/etc. of the field.
  • Incident: an event where a value is added to or subtracted from energy.
  • Decay profile: defines whether or not the energy decays and has settings for it.
  • Granularity: how often is the field energy updated - in essence this defines the resolution in which the ordering happens. You can easily visualize this with the graph.
  • Half life: how long does it takes for energy to half. 
  • Cut off: at which point is the energy considered non-existent.
  • Incident storage: where are the incidents stored and how they are processed.
Settings

There are two very important parts on the Radioactivity settings page:

Salt for checksums and the Configuration (assist). To prevent 3rd parties from manipulating the field energies with scripts/bots, you should choose a good random string (a salt) used in calculating the checksums for the ajax callbacks. 

The second important part is to set up the radioactivity configuration file: radioactivity-boostrap.cfg.inc. This file holds all the required settings for the callback script to work without drupal and this is important for high traffic sites; If the file is missing the callback script does a partial drupal bootstrap so that it can function properly. Note that Live and Deferred storage types require drupal to bootstrap while the experimental File storage does not (non-boostrap memcache support is under development).

All that boils down to this: A user navigates to a node, node has a radioactivity field which - when visible - generates an incident with an ajax callback which increments the fields energy. The energy is manipulated with the settings defined in the decay profile (granularity, half-life) over time (cron runs) and it is considered to be zero when energy level is below the cut off level. 

Lets get started.

We will create a setup which tracks article popularity in a 6 hour timeframe so that the articles without views for 6 hours will have half of the initial energy and that it takes 50 views for them to reach the same energy level as a brand new one with 1000 energy.

1. Decay Profile

Navigate to the Radioactivity decay profiles page under Structure (admin/structure/radioactivity). Notice that there are no decay profiles yet, so lets create a decay profile by clicking the Add link at the top.

You are presented with the following form:

The form is filled with default values that should be suitable for most use cases with a good number of daily visitors. For this example we will use the defaults which is a 6 hour half life with 1 minute granularity. Note that finding the correct values for your site may take a few weeks and it usually requires some grooming.

At the moment there are three working storage types available:

  • Live storage - this updates the energy directly to the field, which means that all incidents affect the ordering in real time. Requires bootstrap.
  • Deferred storage - incidents are stored to a separate table and cron is responsible for adding the incidents to the field. Requires bootstrap.
  • File storage - this is an experimental lightweight incident storage which stores incidents to a temporary file. Non-bootstrap.
  • Memcached storage is going to be released soon.

Lets choose the live storage for this profile.

We're done here so save the profile.

2. Radioactivity Field

Next navigate to Content types under Structure (admin/structure/types) and click on manage fields on the Article content type we wish to add Radioactivity to. Create a new Radioactivity field. Once you have clicked save you are taken to the Field settings tab (which is empty). Click on the Edit tab. On this page select the profile we just created (since there is only one profile it is automatically selected) and add a reasonable default value for the energy field; 1000 points should be sufficient if one incident emits 10 points of energy.

Next, go back to the Content types page and click on the manage display link. Here we can configure the way the field works.

We can choose the amount of energy of one view emits or disable it by setting it to 0. We also have an option to display the amount of energy the field holds as a raw value or percentage. Usually this is only needed on admin listing pages, so lets decide not to show anything (Note: at the moment due to field caching these are not updated live; cache clear or a cron run solves the problem).

The final piece missing is a view which is ordered by the field we just created.

3. Views

Go to the Views listing page under Structure (admin/structure/views) and click on Add a new view. We will be listing Content of type Article with no default sorting on a page so choose some title and path for it also. The settings here do not really matter as we are only interested in the sorting order. Click on Continue and edit.

At the bottom left click on the add button to add a new sort criteria. On the following form we have to locate our field and add the field energy as the sorting criteria. Be sure to set the sorting to descending - otherwise you have the most popular articles at the bottom. Click on save and we're done!

After creating articles and viewing them - and of course running cron - the ordering on the listing page we just created should be that of the articles popularity in the wanted time frame defined in the decay profile.

--

That is the most basic use case for Radioactivity both for historical and technical reasons. 

Questions, thoughts?

Categories: Drupal

Yuriy Gerasimov: DrupalCamp Donetsk 2011 wrapup

Sun, 12/04/2011 - 17:13

Last weekends we held great drupal event -- DrupalCamp Donetsk 2011. This is one of the places of next year UEFA EURO 2012 and it was really great place for our meetup.

About 170 attendees have arrived and were around during 20 sessions. It is very interesting that more and more new companies in Ukraine start developing using drupal and shows huge interest in local meetups. We had people from different cities of Ukraine and even several people from Russia and Belarus.

We have had beautiful bar party as well. Rock group in one of the bars were playing couple of drupal songs that made huge success!

You are welcome to read more about figures of the event here http://donetsk.drupal.ua/en/news/finishing-drupalcamp-donetsk-feedback-a...

Codesprint

As I was one of organizers of the codesprint, I would like to share our experience about it. We didn't have super rockstar developers at our codesprint but managed to do very nice job -- rewrite module draggableviews. There are plenty of very good developers in Ukraine but it is a pity that not many people understand importance of the contributing. So we started from ground level of using issues queue and creating patches and finished with workable code. We had several teams (every team not more than 6 people) who were working on different topics: draggableviews, couple views issues, porting api.drupal.ru to drupal 7, setting up development environment (for beginners). In this way we were able to attract new people to contributions but keeping our concentration for the final result.

I would like to thank all our sponsors and hope to see more people comming to Ukraine for drupal events!

Photos are available here:
https://picasaweb.google.com/115447083216533594560/DrupalCamp2011?authke...
https://plus.google.com/u/0/photos/100373468049652530283/albums/56805220...
https://plus.google.com/photos/111053704258459064817/albums/567977011279...
https://plus.google.com/photos/111053704258459064817/albums/567978260531...

Tags: drupal planetAttached files:  DrupalCampDonetsk2011.jpeg DrupalCampDonetsk2011-codesprint.jpeg
Categories: Drupal

Yuriy Gerasimov: CTools plugins system

Sun, 12/04/2011 - 16:03

When we are writing our own module we, as good developers, should allow other people extend/modify some parts of it. Yes we are talking about defining our own module's hooks. But what we can do if we need to "extend" our module in several places but we should be sured that other module that implements one hook should also implement another one? What we should do if we have a lot of such cases and we should take care about consistency of implementations of other modules? Also sometimes we would like user to decide what implementation to run (so we want some kind of administration page where we select what extention to be active).

One of the solutions for such situation is to define ctools plugins as the way to extend our module's functionality. In this article I would like to explain how to do this and how to take care about consistency.

First of all of course we need to have ctools as dependency. But truly to say it should not be a problem as nowadays it is nearly a must dependency for every project.

For the practical example we will take very simple task -- we write a form that calculates different operations with two numbers. Every operation should be implemented as plugin as we need it to do several tasks:

1. Validate input
2. Calculate operation
3. Display nice message with result

So lets see how we can define our "operation" plugin and how we should use it in our code.

To define the plugin we should implement hook_ctools_plugin_type.

<?php /** * Implements hook_ctools_plugin_type(). * * Has plenty options. See ctools/help/plugins-creating.html */ function example_ctools_plugin_type() { return array( 'operation' => array( 'use hooks' => TRUE, ), ); } ?>

This hook has a lot of various options. In order not to rewrite help document I would recommend to look at it when you will decide to create your own plugins.

Now lets see the code that uses plugins (main module).

<?php /** * Form constructor for Calculations demo. */ function example_calculation($form, $form_state) { // Load all plugins type "operation". ctools_include('plugins'); $operations = ctools_get_plugins('example', 'operation'); $operation_options = array();   foreach ($operations as $id => $operation) { $operation_options[$id] = $operation['label']; }   if (empty($operation_options)) { $form['message'] = array( '#markup' => t('Sorry no operation plugins available in the system.'), ); return $form; }   $form['operations'] = array( '#type' => 'checkboxes', '#title' => t('Please choose Operations'), '#options' => $operation_options, );   // Form elements...   return $form; } ?>

Our form has checkboxes of operations that are available in the system, two textfields for numbers and submit button. Every operation plugin has 'label' property that is shown as label of the checkbox.

This is how we validate the form:

<?php /** * Validate handler. */ function example_calculation_validate($form, &$form_state) { $fv = $form_state['values']; $operations = array_filter($fv['operations']);   foreach ($operations as $operation) { if ($instance = _example_get_instance($operation, $fv['number_a'], $fv['number_b'])) { $instance->validate(); } } } ?>

Here I would like to explain a bit more in details. Every plugin defines a class that perform main job for us: validate, calculate and show the message. Every class should inherit abstract class "example_operation" that allows us to ensure that plugin class is consistent.

Here how _example_get_instance() works:

<?php function _example_get_instance($id, $number_a = NULL, $number_b = NULL) { $instances = &drupal_static(__FUNCTION__);   if (!isset($instances[$id])) { ctools_include('plugins'); $plugin = ctools_get_plugins('example', 'operation', $id); $class = ctools_plugin_get_class($plugin, 'handler'); $instances[$id] = new $class($number_a, $number_b);   // Check that plugin class has ingerited proper 'example_operation' class. if (!is_subclass_of($instances[$id], 'example_operation')) { $instances[$id] = NULL; } }   return $instances[$id]; } ?>

So here we explicitly check whether plugin's class is inherited from our example_operation class and if not, we just don't return object.

Now lets take final look at our form processing -- submit handler:

<?php function example_calculation_submit($form, &$form_state) { $fv = $form_state['values']; $operations = array_filter($fv['operations']);   foreach ($operations as $operation) { if ($instance = _example_get_instance($operation, $fv['number_a'], $fv['number_b'])) { drupal_set_message($instance->resultMessage()); } } } ?> This is very nice, but how we should implement plugins in our modules? There are two ways to do that. First is to implement hook_MODULE_PLUGIN. CTools automatically creates this hook for every plugin defined (there is an option to not accept hook implementation of plugins). In our case this is hook_example_operation. <?php function multiple_divide_example_operation() { return array( 'multiple' => array( 'label' => t('Multiple'), 'handler' => array( 'class' => 'example_multiple_operation', ), ), 'divide' => array( 'label' => t('Divide'), 'handler' => array( 'class' => 'example_divide_operation', ), ), ); } ?>

Here we implement two operation plugins: provide label and handler class (we will come back on classes a bit later).

Another way to implement plugin is to define folder where ctools should look for files that are plugin implementations (hook_ctools_plugin_directory):

<?php /** * Implements hook_ctools_plugin_directory(). */ function sum_ctools_plugin_directory($module, $plugin) { if (($module == 'example') && ($plugin == 'operation')) { return 'plugins/operation'; } } ?>

This means that module sum tells ctools to look at plugins/operation folder for plugins implementation. Here is file that will be found:

<?php /** * Operation plugin for Example module. * * Calculate sum of two numbers. */   $plugin = array( 'label' => t('Sum'), 'handler' => array( 'class' => 'example_sum_operation', ), );   class example_sum_operation extends example_operation { public function calculate() { return $this->a + $this->b; } } ?>

So in case of file implementation we should provide $plugin variable as array of properties. Of course best to do it in the beginning of the file.

These two ways to implement plugins are very convenient and used. For example panels uses file based plugins, but feeds module recommends implementation via hook. I would say that if you expect one module to provide a lot of plugin implementations it is better to have them as separate files as hook implementation array will really look too big. But it is up to you how to do this.

Now lets come back to classes. You already see that in case of sum operation class just implements method calculate().

This is how abstract class looks like:

<?php abstract class example_operation { // Numbers we make calculations on. protected $a; protected $b;   /** * Save arguments locally. */ function __construct($a = 0, $b = 0) { $this->a = $a; $this->b = $b; }   /** * Validate arguments. Return error message if validation failed. */ public function validate() {}   /** * Main operation. Calculate operation and return the result. */ public function calculate() {}   /** * Return result string for the operation. */ public function resultMessage() { return t('Result of !operation with arguments !argument_a and !argument_b is !result.', array( '!operation' => get_class($this), '!argument_a' => $this->a, '!argument_b' => $this->b, '!result' => $this->calculate(), )); } } ?>

So in order to provide operation that will work we really just need to inherit this abstract class and have calculate method in place (this is how "sum" operation is implemented).

For divide operation we have also implemented validate and resultMessage methods:

<?php class example_divide_operation extends example_operation { public function validate() { if (empty($this->b)) { form_set_error('number_b', t('Can\'t divide by zero!')); } }   public function calculate() { return $this->a / $this->b; }   public function resultMessage() { return t('!argument_a divided by !argument_b is !result.', array( '!argument_a' => $this->a, '!argument_b' => $this->b, '!result' => $this->calculate(), )); } } ?>

For multiplication operation we implemented only calculate method but haven't inherited class from our base abstract class to ensure it won't be working:

<?php class example_multiple_operation { public function calculate() { return $this->a * $this->b; }   public function resultMessage() { return t('Multiply !argument_a on !argument_b is !result.', array( '!argument_a' => $this->a, '!argument_b' => $this->b, '!result' => $this->calculate(), )); } } ?>

One of the most important thing about defining your own plugins system is documentation. As it can be very hard for other developers to get themself familiar how plugin works and what it should implement in order to work. In this case defining plugins as classes that should inherit some abstract class is quite convenient as we can put our documentation in comments about methods of abstract class.

I am sure that this artificial example can be implemented easier but I hope it made clearer for you how to define your own ctools plugins and use them. A lot of modules use this system and surely you will need to write your plugins implementation for other modules.

Example module is attached.

This article is based on my presentation during DrupalCamp Donetsk 2011. Slides are available on http://www.slideshare.net/ygerasimov/drupal-camp-donetsk-c-tools

Tags: ctoolsdrupal 7drupal planetAttached files:  example_ctools_plugins.tar_.gz example_ctools_form.png example_ctools_result.png example_ctools_validation.png
Categories: Drupal

Aten Design Group: Drupal Webstocks and Drupal 8 Release Date Lottery

Sun, 12/04/2011 - 15:30

About 6 months ago, I made a game for the Drupal community. I announced it in the local Colorado Drupal community and some other random people have somehow found out about it, but it's still pretty small, and I should have extended an invitation to the wider community long ago. Better late then never.

Drupal Webstocks is a virtual stock market game where anyone can invest fake money in Drupal projects, with prices based on the number of sites using each project. When projects get more users, the stock price goes up. When people stop using a project, the stock price goes down. The usage numbers come from Drupal.org, which updates weekly based on actual sites checking in for updates. So the challenge of Drupal Webstocks is to predict which projects people will be using in the future of Drupal. Unlike real stock markets, insider trading is encouraged, so if you think your own project is going to be the next big thing in Drupal, go ahead and buy it. If your project is already widely used, you may not be able to afford it until you earn more money. So far, no one has bought a share of Drupal core.

In addition to projects as stocks, Drupal Webstocks just added another way to get rich with fake money: the Drupal 8 Release Date Lottery. If you ask 10 people in the Drupal community when they think Drupal 8 will be released, you'll get 10 responses of "when it's done," followed by 12 different guesses as to when that might be. The idea of the Drupal 8 Release Date Lottery is to put some fake money on those guesses, with the correct entries winning all the money, just like a real lottery. Right now the prize is small, but as more people enter guesses the prize will go up. There's also a live graph of the most-guessed dates, so we can all see the collective wisdom of the Drupal community around when Drupal 8 will be released.

Drupal Webstocks gives you 250 cash to start, which is far from enough to buy shares of Drupal core or Views, but should be plenty to buy shares of newer projects or a Drupal 8 Release Date Lottery ticket. Happy investing!

Categories: Drupal

Yuriy Gerasimov: Drupal 7 show empty fields

Fri, 12/02/2011 - 16:36

In this note I would like to share solution for quite common task: show node fields titles even if field are empty. By default if the field is empty it is not included in the node. But practically sometimes client would like to see title of the field even if the field value is not set. As this task has made me debugging for a while I hope it will save someone else's time.

So solution is to use hook_field_attach_view_alter(). This hook is invoked after field module added fields renderable arrays to the content of the node.

<?php /** * Implements hook_field_attach_view_alter(). * * Show titles of empty fields. */ function example_field_attach_view_alter(&$output, $context) { // We proceed only on nodes. if ($context['entity_type'] != 'node' || $context['view_mode'] != 'full') { return; }   $node = $context['entity']; // Load all instances of the fields for the node. $instances = _field_invoke_get_instances('node', $node->type, array('default' => TRUE, 'deleted' => FALSE));   foreach ($instances as $field_name => $instance) { // Set content for fields they are empty. if (empty($node->{$field_name})) { $display = field_get_display($instance, 'full', $node); // Do not add field that is hidden in current display. if ($display['type'] == 'hidden') { continue; } // Load field settings. $field = field_info_field($field_name); // Set output for field. $output[$field_name] = array( '#theme' => 'field', '#title' => $instance['label'], '#label_display' => 'above', '#field_type' => $field['type'], '#field_name' => $field_name, '#bundle' => $node->type, '#object' => $node, '#items' => array(), '#entity_type' => 'node', '#weight' => $display['weight'], 0 => array('#markup' => '&nbsp;'), ); } } } ?> Hope you find it useful and please let me know if you know any other nicer way to accomplish this task.Tags: drupal 7drupal planet
Categories: Drupal

Appnovation Technologies: Using Features' component alter hooks to export components with dynamic elements

Fri, 12/02/2011 - 13:08

Note: These comments are based on Drupal 6, although the hooks are also available in Drupal 7.

read more

Categories: Drupal

Jeremy Thorson: 'Advisory' Coder reviews added to PIFT branch tests, and testing enabled for all contrib projects!

Fri, 12/02/2011 - 12:23

Following up on my PIFT 6.x-2.7 Released post, I'd like to take a moment to walk you through another new feature which was introduced with the rollout of the new code.

But before I do, a public service announcement: The 'enable project testing' checkbox has now been enabled for all contrib projects! To enable automatic testing of patches for your contrib project, visit the 'Edit -> Issues' subtab on your project page; the checkbox can be found under the 'testing' fieldset.

Advisory Coder Reviews

Most are already familiar with the Coder module, which can be used to generate an automated report regarding common programming errors and Drupal coding style violations for a given module (or core). So when we talk about 'advisory coder reviews', The 'coder review' part is pretty well understood ... but we're often asked what the 'advisory' piece means.

The answer to that is fairly straight-forward ... in terms of Drupal's automated testing infrastructure, an 'advisory' test is one which can return a pass/fail result which will not be included in the logic when calculating the overall pass/fail result for the patch or branch in question. In other words, we don't want a 'Coder review' failure (and we expect many!) to result in the test bots failing an otherwise successful patch.

For now, we've enabled this feature on branch tests ... but if all goes well, it could be enabled on patch reviews in the future as well.

The first place you will see this feature in action is via the 'Automated Testing' tab on a given module's project page. Instead of the usual "PASSED: [[SimpleTest]]: [MySQL] 33 pass(es)" test result message, we will now start seeing something a little more convoluted for tests from this point forward:

PASSED: [[SimpleTest]]: [MySQL] 33 pass(es); [[Coder]]: [Coder] 1 minor(s), 2 critical(s), and 42 normal(s).

To date, we've generally only had one testing plugin (SimpleTest) and one testing environment (MySQL) active ... but that changes with the introduction of this feature. Incidently, the pattern used here is [[Testing Plugin]]: [Test Environment] Result;.

Detailed Coder Results

So where can you find the detailed Coder results? These are made available through qa.drupal.org. The first step is to click on your 'View Test' link:

The Coder tab can be a little hard to find, but it's in the Details tab, underneath the 'Summary' bar:

Scroll down, and you should find your detailed Coder review results!

Note that Coder is known to raise a few false positives, and we are running it on it's strictest settings ... so don't go beating yourself up trying to achieve a 100% pass result! And if you do run into a Coder false positive, please consider submitting a patch!

Enjoy!

Categories: Drupal

Digett: Forget mobile, go responsive?

Fri, 12/02/2011 - 10:08

I recently attended DrupalCamp Austin and went to several sessions on mobile. It was a little funny how they contradicted each other. One session would talk about how mobile is the way to go then another session would talk about going responsive. I've been on the fence on which I think is the right approach. I've done lots of mobile sites, but I hadn't jumped into the responsive world yet. So for a recent project, I decided to give it a try.

First off, what do I mean?

By mobile, I'm talking about creating a site with a different HTML/CSS markup but serving the same content. When I do mobile, I generally use a tool to determine if the user is on a mobile device and then I serve the different content designed for the mobile device.

read more

Categories: Drupal

Drupalize.Me: The Drupal Community Demystified

Fri, 12/02/2011 - 08:34

Drupal is an open source project with one of the largest group of contributors (nearly 10,000 developers in all). How does anything get done? How do the big decisions get made? What processes exist to make changes happen? How is the community structured? How do new people get a voice and navigate their way through?

In this Do it with Drupal session, Angie "webchick" Byron will discuss some facts and statistics about the Drupal community, as well as provide answers to these and other burning questions regarding how our “do-ocracy” functions, and why it matters to you.

1h 11m
Categories: Drupal