<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0" xml:base="http://www.cameronandwilding.com/blog">
  <channel>
    <title>The Cameron &amp; Wilding Blog</title>
    <link>http://www.cameronandwilding.com/blog</link>
    <description />
    <language>en</language>
          <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CameronandWilding" /><feedburner:info uri="cameronandwilding" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
    <title>Drupal Process Event Jan 27 - 29</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/w-vUZvgc2g8/drupal-process-event-jan-27-29</link>
    <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;I was fortunate enough to be one of the 60 attendees from 40 of Europe's key Drupal companies to descend on the Microsoft offices in Amsterdam. A long but fruitful weekend was spent discussing process, project management, marketing, sales, QA, testing and much more. Heading out on Friday I was exited by the prospect of working with some of the biggest and best Drupal companies in the world and I wasn't disappointed. The level of expertise and the open sharing of lessons learned, current issues and future plans was truly wonderful. I had hoped to come back with a few improvements we could implement to continue our constant desire for quality and best practice. I came back with that and much more.&lt;/p&gt;
&lt;p&gt;With organisations from 2 to 55 people it allowed for everyone to be able to help with support and advice on matters central to companies at different growth stages. My favorite talk was around knowledge management and knowledge sharing so it seemed apt to do a short write up noting some of our practices. Within Cameron and Wilding we use a number of methods to allow the knowledge we are building up to be shared around the organisation. These include:&lt;br /&gt;
Our intranet and wiki where everything from project documents and write ups of lessons learned on challenging technical issues to links to interesting articles are stored. This is very much self managed by the whole team and each individual takes the time to update anything they feel may be valuable for other team members in the future.&lt;br /&gt;
Every Friday we carry out a 'show and tell' session at the end of the day with the whole team. This may be anything from tricks and tips with Google mail to Apache solr search within a project we have recently worked on. Following a short presentation it then naturally moves into Q and A and open discussion.&lt;br /&gt;
Code reviews do not just act as a quality control method but also help the team to share and develop their skills. In addition it means we also have multiple teams members that know each individual project and can work on them when required.&lt;br /&gt;
Project debriefs which we carry out after completion of all major projects. These allow us to ensure we are constantly improving from project to project and creating the best possible results. And finally for any external training providers we have come in, most recently for html5 and automated training processes, we carry out write ups, post training reviews of the training quality and practice the newly learned skills as soon as possible.&lt;br /&gt;
During the session Jan Depping from Microsoft told us a little about their knowledge management and knowledge sharing. Their knowledge sharing system monitors tweets, email discussions and other methods of communication to record key topics, projects and people. This then allows their team to not only search a database of knowledge developed and stored for that specific purpose but to carry out searches for information that traditionally would have been trapped in silos of email, twitter and other accounts.&lt;br /&gt;
It is truly wonderful that the level of community support within the developer community also transfers to business. The combined skills and knowledge of the community really shone through and confirmed what we already knew - Drupal is truly great.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/amsterdam" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Amsterdam&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/process" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Process&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/business" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;business&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/quality" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Quality&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/w-vUZvgc2g8" height="1" width="1"/&gt;</description>
     <pubDate>Mon, 30 Jan 2012 11:52:27 +0000</pubDate>
 <dc:creator>Ben</dc:creator>
 <guid isPermaLink="false">2507 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/ben/drupal-process-event-jan-27-29#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/ben/drupal-process-event-jan-27-29</feedburner:origLink></item>
  <item>
    <title>Synchronising drupal users information with civicrm</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/0BfbK6KD5KY/synchronising-drupal-users-information-civicrm</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/sync.jpeg" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Recently we have been working in a civicrm project and we thought it could be very useful to develop a module which helps us to reflect automatically any change made in an user account, in his related civicrm contact.&lt;/p&gt;
&lt;p&gt;Civicrm offers an user's synchronisation functionality out of the box but it only checks drupal users without existing related civicrm contact and it creates the respective civicrm contacts. But we wanted something else: if for example we change the email address in an user account, the email address will have to change inmediately in the civicrm contact related to that drupal user.&lt;/p&gt;
&lt;p&gt;For this purpose we need to use hook_user and hook_nodeapi because we don't wish to control changes in the basic account information, we want to control changes in some profile fields. . In our example we will show code inside a hook_user and we will do active use of the v3 civicrm API&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;
	The&lt;strong&gt; first step&lt;/strong&gt; is to initialize civicrm to include the api:&lt;/div&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;if ( ! &lt;/span&gt;&lt;span style="color: #0000BB"&gt;civicrm_initialize&lt;/span&gt;&lt;span style="color: #007700"&gt;( ) ) {&lt;br /&gt;            return;&lt;br /&gt;}
&lt;p&gt;global &lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$civicrm_root&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;require_once &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$civicrm_root &lt;/span&gt;&lt;span style="color: #007700"&gt;. &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'/api/api.php'&lt;/span&gt;&lt;span style="color: #007700"&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div&gt;
	The &lt;strong&gt;second step&lt;/strong&gt; is check if the drupal user (whose information we are trying to change) has a related civicrm contact, we use the civicrm api in relation with the UFMatch table, which stores the correspondence between drupal users uids and their related civicrm contacts ids:&lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;$uf_params &lt;/span&gt;&lt;span style="color: #007700"&gt;= array(&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'uf_id' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$account&lt;/span&gt;&lt;span style="color: #007700"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;uid&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'version' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;3&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'sequential' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;        );
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$UFMatch &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;civicrm_api&lt;/span&gt;&lt;span style="color: #007700"&gt;( &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'UFMatch'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Get'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$uf_params &lt;/span&gt;&lt;span style="color: #007700"&gt;);
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact_id &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$UFMatch&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'values'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact_id'&lt;/span&gt;&lt;span style="color: #007700"&gt;];
&lt;p&gt;if(&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact_id &lt;/span&gt;&lt;span style="color: #007700"&gt;!= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;NULL&lt;/span&gt;&lt;span style="color: #007700"&gt;){ ...&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The way to use civicrm api calling to the civicrm_api function where the first argument is the table we can use for our query, the second argument is the kind of operation we wish (Get, Create, Delete...) and the third argument is an array containing information about the query (in our case, the user uid whose related civi contact id we want to get, the version of the api we are using and a flag to indicate we have the results in sequential format). More useful information about using the civicrm api can be found here: &lt;a href="http://wiki.civicrm.org/confluence/display/CRMDOC40/CiviCRM+Public+APIs"&gt;http://wiki.civicrm.org/confluence/display/CRMDOC40/CiviCRM+Public+APIs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After calling the civicrm api, we will have the results in the variable $UFMatch which structure will be:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;array( [&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"values"&lt;/span&gt;&lt;span style="color: #007700"&gt;] =&amp;gt; array( [&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;] =&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;array_with_row_1_info&lt;br /&gt;                                       &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;] =&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;array_with_row_2_info&lt;/span&gt;&lt;span style="color: #007700"&gt;...&lt;br /&gt;                                    )&lt;br /&gt;        )&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div&gt;
	In our case we will have only one row returned so we can find the civi contact id related to the drupal user in  $UFMatch['values'][0]['contact_id']. If the drupal user doesn't exist $UFMatch['values'][0]['contact_id'] will be NULL.&lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div&gt;
	 &lt;/div&gt;
&lt;div&gt;
	The &lt;strong&gt;third step&lt;/strong&gt;, if the drupal user has a related contact in civicrm, is compare the account info which changes we want to control. We are going to use for example, the user's email.&lt;/div&gt;
&lt;p&gt;So first we see what's the email value in the related civicrm contact. For that we use again the civicrm api to make a query against the contacts table:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;$contact_params &lt;/span&gt;&lt;span style="color: #007700"&gt;= array(&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact_id' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact_id&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'version' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;3&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'sequential' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;);
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;civicrm_api&lt;/span&gt;&lt;span style="color: #007700"&gt;( &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Get'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact_params &lt;/span&gt;&lt;span style="color: #007700"&gt;);
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$civi_email &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact&lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'values'&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;][&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'email'&lt;/span&gt;&lt;span style="color: #007700"&gt;];&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;And after that we compare it with the drupal user's email to check for any possible change:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;$drupal_email &lt;/span&gt;&lt;span style="color: #007700"&gt;= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$account &lt;/span&gt;&lt;span style="color: #007700"&gt;-&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;mail&lt;/span&gt;&lt;span style="color: #007700"&gt;;
&lt;p&gt;if (&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;$civi_email &lt;/span&gt;&lt;span style="color: #007700"&gt;!= &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$drupal_email&lt;/span&gt;&lt;span style="color: #007700"&gt;) {...&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;If they are different then this information was updated in the user's account info so it will have to be changed in his related contact info, using again the civicrm api:&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;$update_params &lt;/span&gt;&lt;span style="color: #007700"&gt;= array(&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact_id' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$contact_id&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'email' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$drupal_email&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'version' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;3&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;);
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;civicrm_api&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'contact'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'create'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$update_params&lt;/span&gt;&lt;span style="color: #007700"&gt;);
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;civicrm_api&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'UFMatch'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'create'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #0000BB"&gt;$update_params&lt;/span&gt;&lt;span style="color: #007700"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;In civicrm api v3 some tables don't have defined the "update" operation, in that case we can use the operation "create" so if we provide a row id in our query array and that id exists, then the information will be updated for the row with that id.&lt;/p&gt;
&lt;p&gt;If we check our query array ($update_params), we can see we are saying to the drupal api that we want to change the email of the civi contact with id $contact_id to the email of the related drupal user ($drupal_email).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;As you can see, civicrm api is a very powerful tool, very easy to use inside any of your drupal modules to cross information between the cms and the crm.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/civicrm" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;civicrm&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/0BfbK6KD5KY" height="1" width="1"/&gt;</description>
     <pubDate>Mon, 09 Jan 2012 15:34:02 +0000</pubDate>
 <dc:creator>José</dc:creator>
 <guid isPermaLink="false">2505 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/jos%C3%A9/synchronising-drupal-users-information-civicrm#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/jos%C3%A9/synchronising-drupal-users-information-civicrm</feedburner:origLink></item>
  <item>
    <title>Bulk import tickets into CodeBaseHQ from CSV file</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/68begwU4pnU/bulk-import-tickets-codebasehq-csv-file</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/codebase.png" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Here at C&amp;amp;W we've used &lt;a href="http://codebasehq.com"&gt;CodeBaseHQ&lt;/a&gt; since day one for task tracking, time tracking, bug tracking and hosted version control. It's a great product, they've recently released their v4 version of the app which is even nicer to use.&lt;/p&gt;
&lt;p&gt;During project kickoff we will typically create a specification in a spreadsheet which details each feature as a user story or task description. As a result, there is typically a very boring task of copying and pasting the tasks into CBHQ so we can track them.&lt;/p&gt;
&lt;p&gt;My weekend project this weekend was to use the &lt;a href="http://support.atechmedia.com/codebase/docs/api-documentation"&gt;CBHQ API&lt;/a&gt; to import the tickets from a CSV file. The results of this are in the zip at the bottom of the post. The whole thing works really well. I have some plans to create something a bit more interactive allowing you to select the project from a drop down (populated form the API). However, if you stick with the CSV format, and don't mind editing the php script, this will do the job nicely.&lt;/p&gt;
&lt;p&gt;The script works by converting the CSV into an multi-dimensional array and then this is converted into a series of XML objects which are posted to the API URL.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PHP array&lt;/strong&gt;&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php &lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #0000BB"&gt;0&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;      array(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;7&lt;/span&gt;&lt;span style="color: #007700"&gt;) {&lt;br /&gt;        [&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"summary"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;14&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"my test task 1"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"status-id"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"1"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"reporter-id"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;4&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"123"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"assignee-id"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;5&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"123"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"priority-id"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"1"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"ticket-type"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;4&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"task"&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"milestone-id"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;5&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"24342"&lt;br /&gt;            &lt;/span&gt;&lt;span style="color: #007700"&gt;[&lt;/span&gt;&lt;span style="color: #DD0000"&gt;"estimated-time"&lt;/span&gt;&lt;span style="color: #007700"&gt;]=&amp;gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000BB"&gt;string&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #0000BB"&gt;2&lt;/span&gt;&lt;span style="color: #007700"&gt;) &lt;/span&gt;&lt;span style="color: #DD0000"&gt;"33"&lt;br /&gt;      &lt;/span&gt;&lt;span style="color: #007700"&gt;}    &lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;XML&lt;/strong&gt;&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php &lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;ticket&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;summary&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;my test task 2&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;summary&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;status&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;status&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;reporter&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;123&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;reporter&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;assignee&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;123&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;assignee&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;priority&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;1&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;priority&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;ticket&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;type&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;Task&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;ticket&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;type&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;milestone&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;24342&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;milestone&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;id&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;estimated&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;time&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;163&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;estimated&lt;/span&gt;&lt;span style="color: #007700"&gt;-&lt;/span&gt;&lt;span style="color: #0000BB"&gt;time&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #0000BB"&gt;ticket&lt;/span&gt;&lt;span style="color: #007700"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;It's worth noting CBHQ have a rate limit of 80 posts per hour and each ticket needs to be done as a seperate post, so if you have hundreds of tickets to import you might want to contact CBHQ to up your limit.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;table class="sticky-enabled"&gt;
 &lt;thead&gt;&lt;tr&gt;&lt;th&gt;Attachment&lt;/th&gt;&lt;th&gt;Size&lt;/th&gt; &lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
 &lt;tr class="odd"&gt;&lt;td&gt;&lt;span class="file"&gt;&lt;img class="file-icon" alt="" title="application/zip" src="/modules/file/icons/package-x-generic.png" /&gt; &lt;a href="http://www.cameronandwilding.com/sites/default/files/cbhq_importer_0.zip" type="application/zip; length=21977"&gt;cbhq_importer.zip&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;21.46 KB&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/codebase" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;codebase&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/xml" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;XML&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/68begwU4pnU" height="1" width="1"/&gt;</description>
     <pubDate>Sun, 20 Nov 2011 21:20:41 +0000</pubDate>
 <dc:creator>Neil</dc:creator>
 <guid isPermaLink="false">2504 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/neil/bulk-import-tickets-codebasehq-csv-file#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/neil/bulk-import-tickets-codebasehq-csv-file</feedburner:origLink></item>
  <item>
    <title>Getting started with custom profiles, distributions and make files on Drupal 7</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/kylZkXUq8fI/getting-started-custom-profiles-distributions-and-make-files-drupal-7</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/select-installation-profile_1.png" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;I've spent some time recently building a Cameron &amp;amp; Wilding Drupal 7 installation profile. Whenever we set up a new site from scratch, be it for testing or development on a new project, we always end up installing a host of useful modules: Devel, Views, CTools and Features, to name just a few of them. I was inspired by Antonio and Andrea's great &lt;a href="http://london2011.drupal.org/conference/sessions/building-and-maintaining-distribution-drupal-7-features" title="http://london2011.drupal.org/conference/sessions/building-and-maintaining-distribution-drupal-7-features"&gt;presentation&lt;/a&gt; at DrupalCon London last month. They go into detail about maintaining a Drupal distribution with the Features module. This helps you keep all your configuration in code and means you can do really quick, clean deployments.&lt;/p&gt;
&lt;p&gt;I'll let you look at the DrupalCon presentation to discover the full potential that this method holds, because in this post I'm going to look at creating a basic install profile with a Drush make file, a git repository and a minimum of coding. I've also borrowed from the documentation for &lt;a href="http://drupal.org/node/1022020" title="How to Write a Drupal 7 Installation Profile"&gt;Drupal 7 Install Profiles&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the great things about Drush makefiles is that it's possible to put together a complicated module or profile with just a single Drush command. This has been especially useful in the office because I can share the C&amp;amp;W installation profile with the rest of the team just by emailing them a single make file which they run to install Drupal. The installation profile itself is still a work in progress and we're deciding exactly which modules to include in it. It will no doubt evolve over time, so for the purposes of this post we'll use an example profile (that I've put in a Git repository on &lt;a href="http://www.github.com" title="github"&gt;github&lt;/a&gt;) and I'll explain how to customise it for yourself. Wondering &lt;a href="http://sixrevisions.com/web-development/introductory-guide-to-git-version-control-system/"&gt;why you should use Git?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The new installation profile will provide an additional installation option when you set up your Drupal 7 site. When we've finished, you should be able to choose from a list of options like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.cameronandwilding.com/sites/default/files/select-installation-profile_0.png" alt="Select installation profile screenshot" /&gt;&lt;/p&gt;
&lt;p&gt;So, here's the contents of the makefile:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; core = 7.x&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;api = 2 &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[drupal][version] = "7.8" &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[candw][type] = "profile" &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[candw][download][type] = "git"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[candw][download][url] = "https://github.com/edwardcrompton/candw.git"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[candw][download][branch] = "master"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Yep, it's just 7 lines. In fact this is going to be the first of two makefiles that we'll use, but this is the one that we'll run with drush to build the site. Essentially, the make file contains two things: The version of Drupal core that we're going to use and a reference to the github repository where I've put my installation profile files. You can find more details on the structure of a Drush &lt;a href="http://drupal.org/node/1006620" title="Drush Make theory for happy profile development"&gt;makefile&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;You should be able to run this makefile with &lt;a href="http://drupal.org/project/drush"&gt;Drush&lt;/a&gt;. To do so, you'll need to install Drush (but you've already seen the light and started using Drush, right?) and &lt;a href="http://drupal.org/project/drush_make" title="Drush Make"&gt;Drush Make&lt;/a&gt;. There are various tutorials for installing both these things, so I won't go into that here. It's worth noting though that although the current version of Drush Make at the time of writing is 6.x-2.3, it also works with Drupal 7.&lt;/p&gt;
&lt;p&gt;I'm going to assume in this example that you're doing your Drupal installation on some kind of Linux server. I'm using Ubuntu 10.04 here.&lt;/p&gt;
&lt;p&gt;To run the makefile, save the example above as &lt;em&gt;candw-stub.make&lt;/em&gt;. We'll put our Drupal installation in a folder called candwexample in our web document root (on Ubuntu this is at /var/www). Change director to your web root and then run this command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; drush make candw-stub.make candwexample &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You should see something like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; Project information for drupal retrieved. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;drupal downloaded from http://ftp.drupal.org/files/projects/drupal-7.8.tar.gz. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;candw cloned from git@github.com:edwardcrompton/candw.git. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Found makefile: candw.make &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Project information for views retrieved. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Project information for ctools retrieved. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;views downloaded from http://ftp.drupal.org/files/projects/views-7.x-3.0-rc1.tar.gz. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ctools downloaded from http://ftp.drupal.org/files/projects/ctools-7.x-1.0-rc1.tar.gz. &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;high_contrast cloned from http://git.drupal.org/sandbox/acontia/1281604.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will download everything you need for your new Drupal 7 site. You'll notice that we've downloaded Views, CTools and another module called high_contrast. This is a module my colleague Pablo built the other day and I thought I'd use it as a good example of how a custom module can be fetched from a Git repository. The module is in a sandbox on drupal.org, but could just as easily be in a repository on github or elsewhere.&lt;/p&gt;
&lt;p&gt;Let's take a look at the structure of the Drupal filesystem that we've just set up. The installation profiles in Drupal 7 are contained in the profiles folder and each one contains any modules that it requires. If you look in the profiles directory inside the candwexample module you'll notice that the Views and CTools modules are downloaded to the path candwexample/profiles/candw/modules/contrib. If you poke about a bit further you will discover that our custom high_contract module has also been downloaded to candwexample/profiles/candw/modules/custom/high_contrast.&lt;/p&gt;
&lt;p&gt;But how did Drush know to download these extra modules? Views and CTools are not part of Drupal 7 core and we didn't mention them in our makefile. Neither did we make any reference to the high_contrast module. Well, look back at one of the lines that drush outputted when you ran the makefile:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; Found makefile: candw.make &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Drush has cloned the profile that we pointed it to on github and it has found another make file in there, which it has also run. Let's have a closer look at the files in the &lt;a href="https://github.com/edwardcrompton/candw" title="github profile repository"&gt;git repository&lt;/a&gt;. Drush will keep running makefiles recursively for any of the stuff that it downloads or clones from a repository as a result of the first make file we ran from the command line. In this example we will only come across two makefiles: The first 'stub' (candw-stub.make) that we just ran and the second (candw.make) that is in our custom profile. The stub makefile is kept as simple as possible and it does not change very often. Because it does not change very often we don't need to keep it under version control.&lt;/p&gt;
&lt;p&gt;The make file in the profile is part of our git repository and it will change whenever we decide to add or remove a module from our custom Drupal profile or we want to change the version of a module we're using. In this example the profile is in a repository on &lt;a href="https://github.com" title="Github"&gt;github&lt;/a&gt;. Github is free to sign up for and I'd recommend that you set up an account and put your own custom installation profile in a repository there. As long as you change your makefile to include the path to your repository Drush should always be able to find your installation profile wherever you are installing Drupal.&lt;/p&gt;
&lt;p&gt;This is what the makefile in our profile looks like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; core = 7.x &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;api = 2 &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;; Contrib &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[views][subdir] = "contrib"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[views][version] = "3.0-rc1"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[ctools][subdir] = "contrib"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[ctools][version] = "1.0-rc1"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;; Custom&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[high_contrast][type] = "module"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[high_contrast][download][type] = "git"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[high_contrast][download][url] = "http://git.drupal.org/sandbox/acontia/1281604.git"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;projects[high_contrast][subdir] = "custom" &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In this makefile we're providing details of the three modules we want to download so that they can be used in our profile. Each line in the makefile here (as with the first makefile) is of the format project[name_of_module][some_parameter]. For example, project[views][version] = "3.0-rc1" tells Drush to get the 7.x-3.0-rc1 version of the Views module and projects[views][subdir] = "contrib" tells Drush to download it to a path at candwexample/profiles/candw/modules/contrib. (Without this line it would by default download to candwexample/profiles/candw/modules). Because Views and CTools are contributed modules Drush knows where to download them from automatically.&lt;/p&gt;
&lt;p&gt;As you can see, there are extra parameters for our custom high_contrast module. Amongst other things Drush needs to know the location of the repository to get it from and the type of that repository (Git on drupal.org in this case, but it could also be an svn repository).&lt;/p&gt;
&lt;p&gt;Drupal.org has full documentation on the makefile &lt;a href="http://drupal.org/project/drush_make" title="Drush Make"&gt;format&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The other really important file in the repository (&lt;a href="https://github.com/edwardcrompton/candw"&gt;https://github.com/edwardcrompton/candw&lt;/a&gt;) is candw.info. This sets the modules on which the profile depends. It is very similar to the .info file you find in every Drupal module. You might think that the modules your profile is dependent on will always be the same as the modules that we've specified in our makefile, right? Not necessarily - the modules listed as dependancies in the candw.info file will be automatically enabled when the installation profile is run. You may not immediately want to enable all the modules that you have downloaded with the Drush makefile, so these would not be included the .info file. Additionally, there may be optional core modules that you want to enable but which you don't need to explicitly mention in your Drush makefile because they are included as part of Drupal core. We will include these in the .info file.&lt;/p&gt;
&lt;p&gt;This is what the candw.info file looks like in our example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; name = C&amp;amp;amp;W Blog&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;description = Install as a Cameron &amp;amp;amp; Wilding blog site.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;version = 1.0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;core = 7.x&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;;Standard install core modules&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = block&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = color&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = comment&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = contextual&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = dashboard&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = help&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = image&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = list&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = menu&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = number&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = options&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = taxonomy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = dblog&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = search&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = shortcut&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = toolbar&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = overlay&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = field_ui&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = file&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = rdf &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;;Contrib modules for C&amp;amp;amp;W &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dependencies[] = views&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;;Custom modules for C&amp;amp;amp;W&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; &lt;code&gt;dependencies[] = high_contrast &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The first four lines specify some general details about our profile: The name and description of the installation profile as well as the version of the module and the version of Drupal core we will be using. The name and description will show up when you run your custom Drupal installation profile when installing Drupal.&lt;/p&gt;
&lt;p&gt;The 20 or so lines under the 'Standard install core modules' heading is a list of the core modules that we want to enable. These are the modules that Drupal enables by default when you do a standard installation. The last two lines in the file tell Drush to enable Views and our high_contrast module. You'll notice that CTools is not listed as a dependancy. This is because it is a dependancy of Views so it will automatically be enabled when Views is enabled.&lt;/p&gt;
&lt;p&gt;Apart from the README.txt file in the github repository, there are two other files that we haven't yet looked at: candw.install and candw.profile. These are very similar to the   mymodule.install file and mymodule.module file that you find in a Drupal module. candw.profile can contain PHP code that will dictate the behaviour of your install profile. You can use it to set variables, create user roles and also add extra steps to your Drupal installation process. For the purposes of this example install profile we are going to leave the candw.profile file blank. (I did say this would be a simple example!) There are a few really &lt;a href="http://drupal.org/node/1022020"&gt;useful hooks&lt;/a&gt; that you can put in this file.&lt;/p&gt;
&lt;p&gt;In the candw.install file we'll just place a single hook with a few lines of code:&lt;/p&gt;
&lt;pre&gt;/**
 * Implements hook_install().
 *
 * Perform actions to set up the site for this profile.
 * We'll just call the install method from the standard install here. 
 * Everything else we do will be on top of that.
 */

function candw_install() {
        include_once DRUPAL_ROOT . '/profiles/standard/standard.install';
        standard_install();
}
&lt;/pre&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Hook_install runs when the installation profile is installed. You'll know all about this hook if you've ever done any module development. In a module it's where you do all your initial configuration and a profile is no different. We're going to cheat a bit here and use some code that's already in Drupal core - we'll simply call the hook_install from the standard Drupal installation. This does some of the stuff that you take for granted when you install Drupal. Amongst many other things it sets up some basic blocks (for example login and search) and content types (Basic Page and Article).&lt;/p&gt;
&lt;p&gt;Now we have a working Drupal 7 install profile which can be extended to include any number of custom or contributed modules. Do take a look at the DrupalCon presentation I mentioned at the start to see how powerful these basic concepts become when you start incorporating Features modules as part of your install profile. Using Features you can create install profiles that contain all your configuration so you can set up Views, new content types or taxonomy vocabularies to name only a few of the possibilities.&lt;/p&gt;
&lt;p&gt;If you've run your Drush makefile in your document root to download to a folder called candwexample you should now be able to navigate to &lt;a href="http://localhost/candwexample"&gt;http://localhost/candwexample&lt;/a&gt; and choose your new custom installation profile from the list as shown in the screenshot at the top of this post.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/distribution" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;distribution&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/drupal7" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Drupal7&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/install" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;install&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/installation" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;installation&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/profile" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;profile&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/kylZkXUq8fI" height="1" width="1"/&gt;</description>
     <pubDate>Thu, 13 Oct 2011 15:41:59 +0000</pubDate>
 <dc:creator>Ed</dc:creator>
 <guid isPermaLink="false">2500 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/ed/getting-started-custom-profiles-distributions-and-make-files-drupal-7#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/ed/getting-started-custom-profiles-distributions-and-make-files-drupal-7</feedburner:origLink></item>
  <item>
    <title>Doxygen and best practices</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/H6VsYHvIO8s/doxygen-and-best-practices</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/Picture%204_1.png" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;h3&gt;
	So what is doxygen?&lt;/h3&gt;
&lt;p&gt;Pulled from Wikipedia, the official definition.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;"&lt;strong&gt;Doxygen&lt;/strong&gt; is a &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Documentation_generator" title="Documentation generator"&gt;&lt;em&gt;documentation generator&lt;/em&gt;&lt;/a&gt;&lt;em&gt; for the &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Programming_language" title="Programming language"&gt;&lt;em&gt;programming languages&lt;/em&gt;&lt;/a&gt;&lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29" title="C (programming language)"&gt;&lt;em&gt;C&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B" title="C++"&gt;&lt;em&gt;C++&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/C_Sharp_%28programming_language%29" title="C Sharp (programming language)"&gt;&lt;em&gt;C#&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Fortran" title="Fortran"&gt;&lt;em&gt;Fortran&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Java_%28programming_language%29" title="Java (programming language)"&gt;&lt;em&gt;Java&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Objective-C" title="Objective-C"&gt;&lt;em&gt;Objective-C&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/PHP" title="PHP"&gt;&lt;em&gt;PHP&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Python_%28programming_language%29" title="Python (programming language)"&gt;&lt;em&gt;Python&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Interface_description_language" title="Interface description language"&gt;&lt;em&gt;IDL&lt;/em&gt;&lt;/a&gt;&lt;em&gt; (&lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture" title="Common Object Request Broker Architecture"&gt;&lt;em&gt;CORBA&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and Microsoft flavors), &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/VHDL" title="VHDL"&gt;&lt;em&gt;VHDL&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, and to some extent &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/D_%28programming_language%29" title="D (programming language)"&gt;&lt;em&gt;D&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. It runs on most &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Unix-like" title="Unix-like"&gt;&lt;em&gt;Unix-like&lt;/em&gt;&lt;/a&gt;&lt;em&gt; systems, &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Mac_OS_X" title="Mac OS X"&gt;&lt;em&gt;Mac OS X&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and &lt;/em&gt;&lt;a href="http://en.wikipedia.org/wiki/Microsoft_Windows" title="Microsoft Windows"&gt;&lt;em&gt;Windows&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first version of Doxygen borrowed some code from an old version of DOC++; later, the Doxygen code was rewritten by Dimitri van Heesch.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Doxygen is a tool for writing software reference documentation. The documentation is written within code, and is thus relatively easy to keep up to date. Doxygen can cross reference documentation and code, so that the reader of a document can easily refer to the actual code."&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;More useful reading &lt;a href="http://www.stack.nl/%7Edimitri/doxygen/" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ok, sounds all good but why do we need to use it? Having been a PHP programmer for a couple of years now and on the drupal platform for a period of time I have seen my share my fair share of badly written code. I have been guilty of it myself at times, just understanding the code you have written or just out of pure lazyness perhaps? Things include not commenting lines of code, declaring variables, bit of a developers nightmare when you are picking up someone elses code! Having watched an excellent talk at &lt;a href="http://london2011.drupal.org/" target="_blank"&gt;Drupalcon London&lt;/a&gt; this &lt;a href="http://london2011.drupal.org/conference/sessions/code-stinks" target="_blank"&gt;talk&lt;/a&gt; got me thinking about best practices.&lt;/p&gt;
&lt;p&gt;So how does doxygen come into all this? Well the way I see it, it's a useful way of reading well documented code in a reference. So if I were to look into a whole codebase of a project and wanted to find a useful custom function I wrote or even a hook for something then I would know where to look. Doxygen also provides us a useful base for writing good quality code whether it's procedural stuff or in OO.&lt;/p&gt;
&lt;h3&gt;
	What is the syntax/best practices to use?&lt;/h3&gt;
&lt;p&gt;In this case it all comes down to the quality of code you write. As a guide, follow this documentation here or go to &lt;a href="http://www.cisst.org/resources/software/cis/doxygen-documentation.html"&gt;http://www.cisst.org/resources/software/cis/doxygen-documentation.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The basics:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Use doxygen commenting in the &lt;strong&gt;.h&lt;/strong&gt; (include) files of your code&lt;/li&gt;
&lt;li&gt;
		Use the &lt;strong&gt;&lt;code&gt;/*!&lt;/code&gt;&lt;/strong&gt; sequence to indicate the start documentation blocks and &lt;strong&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/strong&gt; to indicate the end of commenting. The same rules apply when ever you start a documentation block you must close it and be careful not to place source code within these documentation blocks. If one text line is sufficent for documentation use &lt;strong&gt;&lt;code&gt;//!&lt;/code&gt;&lt;/strong&gt;. Inbetween the start of a documentation block, the use of asterisks is optional at the beginning of each line.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Classes for OO:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Use the &lt;code&gt;/*!&lt;/code&gt;before the declaration of a class to provide some descriptive information about the class.&lt;/li&gt;
&lt;li&gt;
		Use the &lt;code&gt;\brief&lt;/code&gt;tag to provide a short one line &lt;em&gt;brief&lt;/em&gt; description of the class.&lt;/li&gt;
&lt;li&gt;
		Use the &lt;code&gt; \sa &lt;/code&gt;(See Also) keyword to link to related variables, methods, or classes. This is the equivalent command to &lt;code&gt;\see &lt;/code&gt;tag. The command sets the next section to trigger a link to anything that might possibly be a keyword and also in the html document creates the phrase "&lt;strong&gt;See Also:&lt;/strong&gt;" followed by the linked parameters.&lt;/li&gt;
&lt;li&gt;
		Use the &lt;code&gt; \ingroup &lt;/code&gt;to specify which group this class's documentation should be grouped under. Refer to the section on Grouping below.&lt;/li&gt;
&lt;/ul&gt;&lt;pre&gt;
/*! \brief classB: A normal class
  \ingroup common
  This class likes bob.
  This class is part of the group common.
  This class inherits class A  
  \sa classA 
 */
class classB: public classA{
...

&lt;strong&gt;File listing:&lt;/strong&gt;&lt;/pre&gt;&lt;p&gt;At the top of every .h file (except for template and inline files) after the &lt;strong&gt;cvs header&lt;/strong&gt;, one should place a &lt;code&gt;\file&lt;/code&gt;tag to label the file. The syntax actually takes in a filename as a parameter and can use the &lt;code&gt;\brief&lt;/code&gt;but for our purposes this is not required&lt;br /&gt;
	for example one should use:&lt;/p&gt;
&lt;pre&gt;
 
/*! 
  \file 
  \brief
  \ingroup tracking 
 */
&lt;/pre&gt;&lt;p&gt;For the erc libraries, the requirement is the use of &lt;code&gt;\file&lt;/code&gt;without any arguments, &lt;code&gt;\brief&lt;/code&gt;to give a short blurb on the purpose/contents of the file and a &lt;code&gt;\ingroup&lt;/code&gt;with the group to which the file belongs to in order to link this file's documentation to the group. The \file listing must be used or else documentation for the #define's and the typedefs will not be used.&lt;/p&gt;
&lt;pre&gt;
/**
 * Summary here; one sentence on one line (should not, but can exceed 80 chars).
 *
 * A more detailed description goes here.
 *
 * A blank line forms a paragraph. There should be no trailing white-space
 * anywhere.
 *
 * @param $first
 *   "@param" is a Doxygen directive to describe a function parameter. Like some
 *   other directives, it takes a term/summary on the same line and a
 *   description (this text) indented by 2 spaces on the next line. All
 *   descriptive text should wrap at 80 chars, without going over.
 *   Newlines are NOT supported within directives; if a newline would be before
 *   this text, it would be appended to the general description above.
 * @param $second
 *   There should be no newline between multiple directives (of the same type).
 * @param $third
 *   (optional) TRUE if Third should be done. Defaults to FALSE.
 *   Only optional parameters are explicitly stated as such. The description
 *   should clarify the default value if omitted.
 *
 * @return
 *   "@return" is a different Doxygen directive to describe the return value of
 *   a function, if there is any.
 */&lt;/pre&gt;&lt;p&gt;A typical documentation block&lt;/p&gt;
&lt;p&gt;/**&lt;br /&gt;
	 * My example connectors function example checking to see if a and b exist the doing some stuff.&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;
	 * @param $name&lt;br /&gt;
	 *   The name of the string being passed in and called at module level when returned.&lt;/p&gt;
&lt;p&gt;*/&lt;/p&gt;
&lt;p&gt;function connectors($name) {&lt;/p&gt;
&lt;p&gt;  // Check connector_one matches to A or connector_two matches to B&lt;/p&gt;
&lt;p&gt;  if ((connector_one == 'A') || (connector_two == 'B')) {&lt;/p&gt;
&lt;p&gt;    // Variable name of string&lt;/p&gt;
&lt;p&gt;   $name  = 'example-name';&lt;/p&gt;
&lt;p&gt;  }&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Doxygen would pick this up as a function call and the developer picking this up would quickly identify why it's there and what it's doing.&lt;/p&gt;
&lt;p&gt;So by doing Drupal development work for the past few years I thought a full proof module to help me achieve this clean coding practice is the &lt;a href="http://drupal.org/project/coder" target="_blank"&gt;coder&lt;/a&gt; module.&lt;/p&gt;
&lt;p&gt;Two benefits:-&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		If you are pushed for time and need to have well documented code, run this through as a project (will update this in a bit to reflect how to achieve this) and coder will automatically tidy it up for you.&lt;/li&gt;
&lt;li&gt;
		Or if you are like me and want to figure it why the hell your code is poor work through each bug and it will help you improve in the longrun.&lt;/li&gt;
&lt;/ol&gt;&lt;h3&gt;
	So how do I run doxygen on one of my projects?&lt;/h3&gt;
&lt;ol&gt;&lt;li&gt;
		If you have ubuntu run sudo apt-get install doxygen or download tar gzip/installer from &lt;a href="http://www.stack.nl/%7Edimitri/doxygen/download.html" target="_blank"&gt;here&lt;/a&gt; or go to &lt;a href="http://www.stack.nl/~dimitri/doxygen/download.html"&gt;http://www.stack.nl/~dimitri/doxygen/download.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Download Matt Farinas excellent file from &lt;a href="https://github.com/mattfarina/drupal-6-doxygen" target="_blank"&gt;here&lt;/a&gt; or go to &lt;a href="https://github.com/mattfarina/drupal-6-doxygen"&gt;https://github.com/mattfarina/drupal-6-doxygen&lt;/a&gt; and put this into your drupal root directory&lt;/li&gt;
&lt;li&gt;
		CD to the directory you want to doxygen&lt;/li&gt;
&lt;li&gt;
		Next on command line execute &lt;code&gt;doxygen drupal.doxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
		Once its finished compiling navigate to your html docs so it could be something &lt;a href="http://sitename/docs/html/index.html"&gt;http://sitename/docs/html/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;So as an overview use Doxygen as a great developers guide for any documentation you have written for specifically custom written functionality and use the Coder module to help you achieve those best &lt;a href="http://drupal.org/coding-standards" target="_blank"&gt;coding standards&lt;/a&gt; in Drupal.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/coding-best-practices" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;coding best practices&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/doxygen" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Doxygen&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/H6VsYHvIO8s" height="1" width="1"/&gt;</description>
     <pubDate>Fri, 07 Oct 2011 13:55:35 +0000</pubDate>
 <dc:creator>Indy</dc:creator>
 <guid isPermaLink="false">2501 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/indy/doxygen-and-best-practices#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/indy/doxygen-and-best-practices</feedburner:origLink></item>
  <item>
    <title>The 10 most critical Drupal security risks</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/hx0PDILYUNk/10-most-critical-drupal-security-risks</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/barbed_wire.jpg" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;One of the most interesting sessions I attended at the DrupalCon London was "&lt;a href="http://london2011.drupal.org/conference/sessions/doing-drupal-security-right"&gt;Doing Drupal security right&lt;/a&gt;", given by &lt;a href="http://hojtsy.hu/"&gt;Gá&lt;/a&gt;&lt;a href="http://hojtsy.hu/"&gt;bor Hojtsy&lt;/a&gt;, a Drupal 6 maintainer involved in the security team.&lt;/p&gt;
&lt;p&gt;It was a very useful presentation, with lots of tips and advises that you don't always realise when you write custom code or setup a website environment.&lt;/p&gt;
&lt;p&gt;The presentation was based on the "&lt;a href="http://www.owasp.org/images/0/0f/OWASP_T10_-_2010_rc1.pdf"&gt;Top 10 Most Critical Web Application Security Risks&lt;/a&gt;" guide, written by &lt;a href="https://www.owasp.org"&gt;OWASP&lt;/a&gt;, adapting each one of the cases to a Drupal site.&lt;/p&gt;
&lt;p&gt; &lt;a href="#top-10"&gt;&lt;strong&gt;The 10 most critical Drupal security risks&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		&lt;a href="#point1"&gt;SQL Injection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point2"&gt;Cross Site Scripting (XSS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point3"&gt;Authentications and sessions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point4"&gt;Insecure direct object references&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point5"&gt;Cross Site Request Forgery (CSRF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point6"&gt;Security misconfiguration&lt;/a&gt; &lt;strong&gt;(Main source of attacks!)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point7"&gt;Insecure cryptographic storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point8"&gt;Failure to restrict URL access&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point9"&gt;Insufficient transport protection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="#point10"&gt;Unvalidated redirects&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;a href="#resources"&gt;&lt;strong&gt;Resources&lt;/strong&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="#points-contact"&gt;Points of contact with the Drupal security team&lt;/a&gt; &lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
	&lt;a id="top-10" name="top-10"&gt;&lt;/a&gt;The 10 most critical Drupal security risks&lt;/h2&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point1" name="point1"&gt;&lt;/a&gt;&lt;strong&gt;1. SQL Injection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You shouldn't use data that you don't trust (as a feed, a user input, another database, etc) directly in a database query without escape it:&lt;/p&gt;
&lt;pre&gt;
index.php?id=12 
&lt;/pre&gt;&lt;pre&gt;
mysql_query("UPDATE mytable SET value = '". $value ."' WHERE id = ". $_GET['id']);  
&lt;/pre&gt;&lt;p&gt;Instead you should use Drupal functions passing the user input as parameters:&lt;/p&gt;
&lt;pre&gt;
db_query("UPDATE {mytable} SET value = :valueWHERE id = :id", array(  ':value' =&amp;gt; $value,  ':id' =&amp;gt; $id);
&lt;/pre&gt;&lt;p&gt;If you need to include dynamic table or column names in your query, you can use &lt;strong&gt;db_escape_table()&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point2" name="point2"&gt;&lt;/a&gt;&lt;strong&gt;2. Cross Site Scripting (XSS)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;XSS is injecting data to the HTML output. This is a very important one: &lt;a href="https://www.whitehatsec.com/assets/presentations/PPTstats082708.pdf"&gt;there is a 64% likelihood a website has a XSS issue.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You should always escape the variables you send to the output if they come from a non trusted source, like the &lt;strong&gt;parameters of a URL&lt;/strong&gt;. For example, this code is unsecure:&lt;/p&gt;
&lt;pre&gt;
index.php?id=12
print $_GET['id']; &lt;/pre&gt;&lt;p&gt;It's also very common see codes like this, specially in &lt;strong&gt;custom themes&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;
$output .= $node-&amp;gt;title;
&lt;/pre&gt;&lt;p&gt;The problem in the code above is that Drupal doesn't usually filter the user input when a node is saved. So the user could save &lt;strong&gt;malicious code in the title&lt;/strong&gt; and then it will be printed without any kind of filtering.&lt;/p&gt;
&lt;p&gt;	One more obvious mistake is giving &lt;strong&gt;full HTML permissions &lt;/strong&gt;to not trusted users, or allow to use unsafe tags as &amp;lt;script&amp;gt;.&lt;/p&gt;
&lt;p&gt;If we grant Full HTML permissions to users, they could add this JS code to a page, which would change the admin password if he views the content:&lt;/p&gt;
&lt;pre&gt;
jQuery.get('/user/1/edit',
  function (data, status) {
  if (status == 'success') {
      var p = /id="edit-user-edit-form-token" value="([a-z0-9]*)"/;
      var matches = data.match(p);
      var token = matches[1];
      var payload = {
        "form_id": 'user_edit',
        "form_token": token,
        "pass[pass1]": 'hacked',
        "pass[pass2]": 'hacked'
      };
      jQuery.post('/user/1/edit', payload);
    }
  }
);  
&lt;/pre&gt;&lt;p&gt;This technique, with code changes, works up to Drupal 6. &lt;em&gt;(Example from Heine Deelstra, Drupal Security team lead &lt;a href="http://heine.familiedeelstra.com/change-password-xss"&gt;http://heine.familiedeelstra.com/change-password-xss&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;what can you do?&lt;/strong&gt; Drupal provides a set of functions you should use:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img alt="" height="370" id="__mce_tmp" src="/sites/default/files/drupal_approach_filters.PNG" width="508" /&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		&lt;strong&gt;Use placeholders &lt;/strong&gt;in functions like t() or format_plural(): %name, @url, !insecure:&lt;/li&gt;
&lt;/ul&gt;&lt;pre&gt;
t(' %name has a blog at &amp;lt;a href="   @url " _fcksavedurl="   @url " _fcksavedurl="   @url " _fcksavedurl="   @url "&amp;gt; @url &amp;lt;/a&amp;gt;', array('@url' =&amp;gt;   valid_url($user-&amp;gt;profile_blog), '%name' =&amp;gt;   $user-&amp;gt;name));
&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;
		Use &lt;strong&gt;Drupal.t() &lt;/strong&gt;, &lt;strong&gt;Drupal.formatPlural()&lt;/strong&gt; in JavaScript.&lt;/li&gt;
&lt;/ul&gt;&lt;h3 dir="ltr"&gt;
	 &lt;a id="point3" name="point3"&gt;&lt;/a&gt;&lt;strong&gt;3. Authentications and sessions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You need to deal with these issues:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Weak password storage and account management&lt;/li&gt;
&lt;li&gt;
		Session hijacking / fixation&lt;/li&gt;
&lt;li&gt;
		Lack of session timeout / logout&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Drupal has good solutions for that, so don't need to worry too much about these:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Passwords are stored hashed&lt;/li&gt;
&lt;li&gt;
		Session IDs changed when permissions change&lt;/li&gt;
&lt;li&gt;
		Drupal works with Apache's SSL transport&lt;/li&gt;
&lt;li&gt;
		Modules to set certain URLs to use SSL&lt;br /&gt;
		 &lt;/li&gt;
&lt;/ul&gt;&lt;h3 dir="ltr"&gt;
	&lt;a id="point4" name="point4"&gt;&lt;/a&gt;&lt;strong&gt;4. Insecure direct object references&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;We sometimes don't check if the user has permission to access objects:&lt;/p&gt;
&lt;pre&gt;
index.php?id= 12
db_query("SELECT * FROM {node} WHERE nid = :id", array(':id' =&amp;gt; $_GET['id'] ));
&lt;/pre&gt;&lt;p&gt;When using Views, sometimes we don't make sure the user has access to nodes. One common issue is forget to add "&lt;strong&gt;published = Yes&lt;/strong&gt;" to the view filters.&lt;/p&gt;
&lt;p&gt;Drupal approach:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Menu system handles permission checking&lt;/li&gt;
&lt;li&gt;
		user_access('administer nodes', $account)&lt;/li&gt;
&lt;li&gt;
		node_access('edit', $node, $account);&lt;/li&gt;
&lt;li&gt;
		$select-&amp;gt;addtag('node_access');&lt;/li&gt;
&lt;li&gt;
		Form API checks for data validity&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point5" name="point5"&gt;&lt;/a&gt;&lt;strong&gt;5. Cross Site Request Forgery (CSRF)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If there is an image like this the user who loads it will be logged out.&lt;/p&gt;
&lt;pre&gt;
&amp;lt;img src="http://example.com/user/logout" /&amp;gt;
&lt;/pre&gt;&lt;p&gt;In the same way some content could be deleted:&lt;/p&gt;
&lt;pre&gt;
http://example.com/index.php?delete=12
&amp;lt;img src="http://example.com/index.php?delete=12" /&amp;gt; &lt;/pre&gt;&lt;p&gt;That's why Drupal always asks "Are you sure you want to delete this?"&lt;/p&gt;
&lt;p&gt;Again, we can avoid this issue doing things in "The Drupal Way":&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Form API works with POST submissions by default (makes it harder)&lt;/li&gt;
&lt;li&gt;
		Form API includes form tokens, requires form retrieval before submission, checks valid values&lt;/li&gt;
&lt;li&gt;
		drupal_valid_token() provided to generate/validate tokens for GET requests.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;
	 &lt;a id="point6" name="point6"&gt;&lt;/a&gt;&lt;strong&gt;6. Security misconfiguration&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Secure server&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		First you should check security holes behind Drupal, like the server configuration&lt;/li&gt;
&lt;li&gt;
		Avoid using FTP at all cost and check your client tool. There are software to decrypt passwords stored in FTP clients.&lt;/li&gt;
&lt;li&gt;
		In shared servers, know who do you share the server with. You might be sharing hosting with a site of a politic party, which could be the objective of an attack.&lt;/li&gt;
&lt;li&gt;
		Which applications are running on the server? Applications like phpBB2 have lots of security holes.&lt;/li&gt;
&lt;li&gt;
		Keep your OS, PHP, SQL server, etc. up to date.&lt;/li&gt;
&lt;/ul&gt;&lt;p dir="ltr"&gt;&lt;strong&gt;Secure Drupal&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Is your &lt;strong&gt;admin password &lt;/strong&gt;"admin"?&lt;/li&gt;
&lt;li&gt;
		Look at all &lt;strong&gt;"administer *" permissions &lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;strong&gt;"administer filters"&lt;/strong&gt; can take over a site&lt;/li&gt;
&lt;li&gt;
		Use &lt;strong&gt;Update module&lt;/strong&gt;, watch the security news (security updates are made on Wednesdays)&lt;/li&gt;
&lt;li&gt;
		Avoid any kind of &lt;strong&gt;PHP input&lt;/strong&gt;, write your own modules instead. Look into using Paranoia module&lt;/li&gt;
&lt;li&gt;
		Watch your input formats, &lt;strong&gt;you can be googled&lt;/strong&gt;&lt;strong&gt;!&lt;/strong&gt;. If we enable Full HTML for anonymous users, somebody can find our site searching the filter description ("Full HTML, Web page addresses and e-mail addresses turn...") and could hack our site.&lt;/li&gt;
&lt;li&gt;
		Check out the &lt;strong&gt;security_review &lt;/strong&gt;module .&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point7" name="point7"&gt;&lt;/a&gt;&lt;strong&gt;7. Insecure cryptographic storage&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Drupal approach:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Drupal stores user passwords hashed with a one-way hash&lt;/li&gt;
&lt;li&gt;
		Different randomly generated private key is provided on each site, which can be used to do reversible encryption&lt;/li&gt;
&lt;li&gt;
		Modules exist to help encrypt more data&lt;/li&gt;
&lt;li&gt;
		Up to you to ensure backups are properly protected&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point8" name="point8"&gt;&lt;/a&gt;&lt;strong&gt;8. Failure to restrict URL access&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Drupal approach:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Menu system uses access callback and access arguments&lt;/li&gt;
&lt;li&gt;
		Continually review permissions&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point9" name="point9"&gt;&lt;/a&gt;&lt;strong&gt;9. Insufficient transport protection&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Tools like Firesheep, get data flowing in the same network you are connected. So somebody connected to the same network as you could see Facebook connections, pictures, etc. You could even login as this user grabbing the login session id.&lt;/p&gt;
&lt;p&gt;	Drupal approach:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Run Drupal on top of &lt;strong&gt;full SSL&lt;/strong&gt;, which is expensive.&lt;/li&gt;
&lt;li&gt;
		Use &lt;strong&gt;securepages &lt;/strong&gt;and &lt;strong&gt;securepages_prevent_hijack &lt;/strong&gt;to wall your important pages.&lt;/li&gt;
&lt;li&gt;
		&lt;a href="http://drupalscout.com/knowledge-base/drupal-and-ssl-multiple-recipespossible-solutions-https"&gt;http://drupalscout.com/knowledge-base/drupal-and-ssl-multiple-recipespos...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Use a &lt;strong&gt;valid certificate&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h3 dir="ltr"&gt;
	&lt;a id="point10" name="point10"&gt;&lt;/a&gt;&lt;strong&gt;10. Unvalidated redirects&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Having custom redirect systems can be also unsafe:&lt;/p&gt;
&lt;pre&gt;
http://example.com/index.php?target=evil.com
&lt;/pre&gt;&lt;p&gt;Drupal approach:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		Drupal has various internal redirections, which use local paths and generate URLs based on them&lt;/li&gt;
&lt;li&gt;
		Look for use of &lt;strong&gt;drupal_goto()&lt;/strong&gt; and Form API &lt;strong&gt;#redirect&lt;/strong&gt; instances in your modules to validate their compliance&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;
	&lt;a id="resources" name="resources"&gt;&lt;/a&gt;Resources:&lt;/h2&gt;
&lt;ul&gt;&lt;li&gt;
		Session video: &lt;a href="http://london2011.drupal.org/conference/sessions/doing-drupal-security-right"&gt;http://london2011.drupal.org/conference/sessions/doing-drupal-security-r...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Session slides: &lt;a href="http://london2011.drupal.org/sites/default/files/DrupalSecurity2011London_0.pdf"&gt;http://london2011.drupal.org/sites/default/files/DrupalSecurity2011Londo...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		&lt;a href="http://drupal.org/writing-secure-code"&gt;http://drupal.org/writing-secure-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Book: Cracking Drupal, A drop in the Bucket (specially chapter 8)&lt;/li&gt;
&lt;li&gt;
		The ten most critical web application security risks: &lt;a href="https://www.owasp.org/images/0/0f/OWASP_T10_-_2010_rc1.pdf"&gt; https://www.owasp.org/images/0/0f/OWASP_T10_-_2010_rc1.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;
	&lt;br /&gt;&lt;a id="points-contact" name="points-contact"&gt;&lt;/a&gt;Points of contact with the Drupal security team:&lt;/h2&gt;
&lt;ul&gt;&lt;li&gt;
		Releases at &lt;a href="http://drupal.org/security"&gt;http://drupal.org/security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Reporting issues: &lt;a href="http://drupal.org/node/101494"&gt;http://drupal.org/node/101494&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Reporting cracked sites: &lt;a href="http://drupal.org/node/213320"&gt;http://drupal.org/node/213320&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
		Discuss general issues: &lt;a href="http://groups.drupal.org/best-practices-drupalsecurity"&gt;http://groups.drupal.org/best-practices-drupalsecurity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt;(&lt;a href="http://www.flickr.com/photos/auntiep/84885643/"&gt;image credit&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/security" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;security&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/drupalcon" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;drupalcon&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/hx0PDILYUNk" height="1" width="1"/&gt;</description>
     <pubDate>Tue, 20 Sep 2011 10:02:08 +0000</pubDate>
 <dc:creator>Pablo</dc:creator>
 <guid isPermaLink="false">2436 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/pablo/10-most-critical-drupal-security-risks#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/pablo/10-most-critical-drupal-security-risks</feedburner:origLink></item>
  <item>
    <title>How to Make Drupal Perform and Scale Like a Rockstar!</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/kN0tiioPkLI/how-make-drupal-perform-and-scale-rockstar</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/vol_knob.png" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Some of the developers of our team had the opportunity to attend the drupalcon session:&lt;br /&gt;&lt;strong&gt;Damn Quick Drupal: How to Make Drupal Perform and Scale Like a Rockstar!&lt;/strong&gt; by Michael Cooper (Soyarma), you can find very useful information about the mentioned conference here:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://london2011.drupal.org/conference/sessions/damn-quick-drupal-how-make-drupal-perform-and-scale-rockstar"&gt;http://london2011.drupal.org/conference/sessions/damn-quick-drupal-how-m...&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;	It was very useful but also very quick, so we've written up the most important points in this quick reference guide.&lt;/p&gt;
&lt;p&gt;There are 2 main parts: &lt;strong&gt;drupal configuration&lt;/strong&gt; and &lt;strong&gt;apache configuration&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;Drupal configuration&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
	 &lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		&lt;em&gt;Consider always caching your pages (including front and 404s pages):&lt;/em&gt;&lt;br /&gt;
		This can be achieved in a lot of ways: the use of apache cache modules (as you will see in the server configuration section), the use of drupal default cache settings and you can use too extra modules like: &lt;a href="http://drupal.org/project/authcache" target="_blank" title="http://drupal.org/project/authcache"&gt;http://drupal.org/project/authcache&lt;/a&gt; (APC apache module + AuthCache drupal module is a WIN combination for your page caching).&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Don't let anonymous hit imagecache generation URLs:&lt;/em&gt;&lt;br /&gt;
		An easy way that helps to avoid this is the use of generic hotlinking protection, you can find a lot of useful information about this here: &lt;a href="http://bit.ly/piLnel" target="_blank" title="http://bit.ly/piLnel"&gt;http://bit.ly/piLnel&lt;/a&gt;&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Be careful with cookies and session data caching:&lt;/em&gt;&lt;br /&gt;
		An easy win to reduce pages load time in your site in relation with session data is to use the module: &lt;a href="http://drupal.org/project/no_anon" target="_blank" title="http://drupal.org/project/no_anon"&gt;http://drupal.org/project/no_anon&lt;/a&gt; which allows drupal to avoid session data and cookie caching for anonymous users.&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Consider Path alias cache:&lt;/em&gt;&lt;br /&gt;
		You can use a module for this purpose: &lt;a href="http://drupal.org/project/pathcache" target="_blank" title="http://drupal.org/project/pathcache"&gt;http://drupal.org/project/pathcache&lt;/a&gt;&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Examine your views queries and views pages:&lt;/em&gt;&lt;br /&gt;
		The main problem in views queries is the excesive use of JOINs, but the performance of views queries can be significantly improved by using index tables. There is a very interesting module which automates the mentioned process: &lt;a href="http://drupal.org/project/shadow" target="_blank" title="http://drupal.org/project/shadow"&gt;http://drupal.org/project/shadow&lt;/a&gt;&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Double check your headers to avoid your browser requests continuously for freshed pages:&lt;/em&gt;&lt;br /&gt;
		This option is included by default in drupal 6 pressflow and drupal 7 core.&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Drupal aggresive cache:&lt;/em&gt;&lt;br /&gt;
		This kind of cache management can improve a lot the load times for your site pages but the problem is that a lot of modules are incompatible with this kind of caching becasuse some of their hooks are not called or called in the non appropriate way, so if you are thinking about enabling this setting be sure about your modules compatibility with it and about the existence of patches that can solve this kind of issue.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Server configuration (Apache, MySQL)&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;
	 &lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		&lt;em&gt;Enable &lt;strong&gt;MYSQL query cache&lt;/strong&gt;&lt;/em&gt;. If enabled, be sure about you are using sane settings:
&lt;p&gt;		&lt;a href="http://www.techiecorner.com/45/turn-on-mysql-query-cache-to-speed-up-mysql-query-performance/" target="_blank" title="http://www.techiecorner.com/45/turn-on-mysql-query-cache-to-speed-up-mysql-query-performance/"&gt;http://www.techiecorner.com/45/turn-on-mysql-query-cache-to-speed-up-mysql-query-performance/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;		Use the following settings:&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;key_buffer_size=12M (key cache)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;query_cache_size=24M&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;query_cache_limit=2M&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;table_cache=96&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;sort_buffer_size=12M&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;myisam_sort_buffer_size=12M&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;tmp_table_size=12M&lt;/span&gt;&lt;br /&gt;
		 &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
		Use &lt;strong&gt;&lt;em&gt;Advanced PHP Cache&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;&lt;strong&gt;(APC)&lt;/strong&gt;&lt;/em&gt; module for Apache: Every time a file is read by PHP it is compiled (checked for syntax errors, optimized, compiled into byte-code).&lt;br /&gt;
		APC (advanced PHP cache) will do this once and then cache the results. APC will check the file every time it is accessed to determine if it is still the same. If that happens rarely, set apc.stat to 0 and you will save that check.&lt;br /&gt;
		The &lt;em&gt;&lt;strong&gt;cacherouter module&lt;/strong&gt;&lt;/em&gt; for drupal will integrate APC with the standard cache clearing functions:&lt;br /&gt;&lt;a href="http://drupal.org/project/cacherouter" target="_blank" title="http://drupal.org/project/cacherouter"&gt;http://drupal.org/project/cacherouter&lt;/a&gt;&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		Set the appropiate value for your max-clients apache parameter. Yo can calculate this parameter in this way:
&lt;ul&gt;&lt;li&gt;
				Use a tracking system (GA, statistics, devel performance logging, webserver logs) to determine how many actual page loads you get at your peak traffic time.&lt;br /&gt;
				 &lt;/li&gt;
&lt;li&gt;
				Depending on how sharp the spike is, pike a time period that sits at around the top 90% of that spike.&lt;br /&gt;
				 &lt;/li&gt;
&lt;li&gt;
				Work out how many pageviews you get a minute during the peak of that spike.&lt;br /&gt;
				 &lt;/li&gt;
&lt;li&gt;
				Since you know how long (on average) it takes to generate a page, you can determine how many of those requests are concurrent. You can calculate this value in this way:
&lt;p&gt;				&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;(P / M) x (E / 60) = C&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;P = Number of page views that hit Drupal&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;M = Minutes page views collected over&lt;br /&gt;
				E = Average Execution time per page in seconds (obtained from your tracking system)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;C = Concurrent requests (the right value for apache max-clients parameter)&lt;br /&gt;
				  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new,courier; font-size: medium;"&gt;&lt;span style="text-decoration: underline;"&gt;Example:&lt;/span&gt;&lt;br /&gt;
				Number of requests: 5000 (P parameter)&lt;br /&gt;
				Time taken: 28.9 seconds = 28.9/60 = 0.482 minutes (M parameter)&lt;br /&gt;
				Mean time/request: 578ms = 0.578 sec (E parameter)&lt;br /&gt;
				C = (5000 / 0.482) x (0.578 / 60) = 100&lt;br /&gt;
				So the max-client parameter should be set to 100&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;				 &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt; &lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;Extra Tips: Improving front-end performance&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
	 &lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
		&lt;em&gt;Mod Pagespeed, help out your users by helping their browers load your site faster:&lt;/em&gt;&lt;br /&gt;
		Pagespeed is an apache module developed by Google team and based on its performance philosophy, you can find a lot of useful information here: &lt;a href="http://bit.ly/bBPcYl" target="_blank" title="http://bit.ly/bBPcYl"&gt;http://bit.ly/bBPcYl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;
		&lt;em&gt;Reverse proxies save Apache/PHP from running when they don't have to:&lt;/em&gt;&lt;br /&gt;
		The best drupal accelerator based on reverse proxies idea is Varnish, you can find a lot of information here: &lt;a href="http://drupal.org/project/varnish" target="_blank" title="http://drupal.org/project/varnish"&gt;http://drupal.org/project/varnish&lt;/a&gt;&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;CDNs&lt;/em&gt; offer shorter round trips for your users, but are often notfaster than a good reverse proxy and can cause some confusion when clearing caches.&lt;br /&gt;
		 &lt;/li&gt;
&lt;li&gt;
		&lt;em&gt;Domain Sharding, a good way to help your users get content faster:&lt;/em&gt;&lt;br /&gt;
		Browsers open a limited number of connections per domain. Most notably, Internet Explorer 6 and 7 open only two connections per domain. Domain Sharding is a technique based on serving your site contents from different domains (normally used to improve the pages load in relation with images). There is a drupal module which can help you to configure a domain sharding to serve your images faster: &lt;a href="http://drupal.org/project/parallel_css" target="_blank" title="http://drupal.org/project/parallel_css"&gt;http://drupal.org/project/parallel_css&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;br /&gt;&lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Conclusions&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt; &lt;br /&gt;
	Yo can easily improve a lot your site performance only doing the following:&lt;br /&gt;
	 &lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
		Use default cache options available in drupal (take care of the aggresive mode).&lt;/li&gt;
&lt;li&gt;
		Use APC + cacherouter module to cache compiled php code, APC + authcache will help you too with the page caching.&lt;/li&gt;
&lt;li&gt;
		Beware of: hotlinking, anonymous session data caching, url alias caching, views queries and headers.&lt;/li&gt;
&lt;li&gt;
		Use basic mysql cache settings (first point of the server configuration tips).&lt;/li&gt;
&lt;li&gt;
		Calculate the right value for your max-clients apache parameter and set it.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;	 &lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/performance-optimisation" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;performance optimisation&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/kN0tiioPkLI" height="1" width="1"/&gt;</description>
     <pubDate>Fri, 16 Sep 2011 11:16:24 +0000</pubDate>
 <dc:creator>José</dc:creator>
 <guid isPermaLink="false">2323 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/jos%C3%A9/how-make-drupal-perform-and-scale-rockstar#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/jos%C3%A9/how-make-drupal-perform-and-scale-rockstar</feedburner:origLink></item>
  <item>
    <title>How to add custom Rules to your module in 5 minutes</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/8vAx5tEXtco/how-add-custom-rules-your-module-5-minutes</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/newton_balls.png" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;It's very interesting to know that something so simple as adding custom &lt;a _fcksavedurl="http://drupal.org/project/rules" href="http://drupal.org/project/rules"&gt;Rules&lt;/a&gt; to your module can make it much more flexible and allow you to integrate it with other modules and processes.&lt;/p&gt;
&lt;p&gt;You can do it in two simple steps:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Step 1:&lt;/b&gt; Define your custom events using the hook_rules_event_info for your modules:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;&lt;span style="color: #000000"&gt;&lt;span style="color: #0000BB"&gt;&amp;lt;?php&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #007700"&gt;return array(&lt;br /&gt;      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'my_event_1' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array(&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'label' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;t&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Title of my event 1'&lt;/span&gt;&lt;span style="color: #007700"&gt;),&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'module' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'yourModule'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arguments' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array (&lt;br /&gt;                                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg1' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array (&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'type' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg1_type'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'label' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;t&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'your_arg1_label'&lt;/span&gt;&lt;span style="color: #007700"&gt;)),&lt;br /&gt;                                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg2' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array (&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'type' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg2_type'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'label' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;t&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'your_arg2_label'&lt;/span&gt;&lt;span style="color: #007700"&gt;)),&lt;br /&gt;                                            ),&lt;br /&gt;                      ),&lt;br /&gt;      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'my_event_2' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array(&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'label' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;t&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'Title of my event 2'&lt;/span&gt;&lt;span style="color: #007700"&gt;),&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'module' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'yourModule'&lt;/span&gt;&lt;span style="color: #007700"&gt;,&lt;br /&gt;                      &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arguments' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array (&lt;br /&gt;                                            &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg1' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; array (&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'type' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'arg1_type'&lt;/span&gt;&lt;span style="color: #007700"&gt;, &lt;/span&gt;&lt;span style="color: #DD0000"&gt;'label' &lt;/span&gt;&lt;span style="color: #007700"&gt;=&amp;gt; &lt;/span&gt;&lt;span style="color: #0000BB"&gt;t&lt;/span&gt;&lt;span style="color: #007700"&gt;(&lt;/span&gt;&lt;span style="color: #DD0000"&gt;'your_arg1_label'&lt;/span&gt;&lt;span style="color: #007700"&gt;)),&lt;br /&gt;                                            ),&lt;br /&gt;                      ),&lt;br /&gt;              );&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000BB"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;This function returns an array containing the definition of every event you wish to define. The definition of every event is at the same time another array with the keys:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;'label'&lt;/b&gt; to define your event title (as it will appear later when you create a triggered rule for it).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;'module'&lt;/b&gt; to specify the name of your module.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;'arguments'&lt;/b&gt; to define the arguments you will need when you invoke your event in your module.&lt;/p&gt;
&lt;p&gt;Every argument is defined as an array in which you need to define the type (for example you could 'node', 'user', 'comment'... depending on what you need), and a label that is the title which will be used if you want to access that argument when you are creating your triggered rule by interface.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Step 2:&lt;/b&gt; After defining the hook_rules_event_info you can invoke your events in any place of your module related to the condition you wish to call an specific event (or events). You can do this in this way:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;  &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And that's it, once this is done you can choose your custom events when you are creating your triggered rules by interface. If you want to see an example out in the wild, have a look at our &lt;a _fcksavedurl="http://drupal.org/node/1213016#comment-4987960" href="http://drupal.org/node/1213016#comment-4987960"&gt;recent patch&lt;/a&gt; for the &lt;a _fcksavedurl="http://drupal.org/project/antispam" href="http://drupal.org/project/antispam"&gt;Antispam module&lt;/a&gt;&lt;/p&gt;
&lt;p style="font-size:8px"&gt;(&lt;a _fcksavedurl="http://www.flickr.com/photos/evoo73/3341993081/" href="http://www.flickr.com/photos/evoo73/3341993081/"&gt;image credit&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/rules" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;rules&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/category/tags/coding" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;coding&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/8vAx5tEXtco" height="1" width="1"/&gt;</description>
     <pubDate>Fri, 16 Sep 2011 10:56:31 +0000</pubDate>
 <dc:creator>José</dc:creator>
 <guid isPermaLink="false">2324 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/jos%C3%A9/how-add-custom-rules-your-module-5-minutes#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/jos%C3%A9/how-add-custom-rules-your-module-5-minutes</feedburner:origLink></item>
  <item>
    <title>DrupalCon London- Team C&amp;W's takeaways </title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/ImdHLqcdaq0/drupalcon-london-team-cws-takeaways</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/drupalcon_crowd.jpg" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;The whole team made it down to the recent &lt;a href="http://london2011.drupal.org"&gt;DrupalCon&lt;/a&gt; that took place in London. DrupalCon happens twice a year, once in the US and once in Europe. London's DrupalCon saw 1,750 people attend three days of sessions, trainings and group discussions. Attending DrupalCon is a lot like "drinking from a fire hose", you are bombarded with more information, new concepts and ideas than it is possible to sensibly absorb. It's thrilling, exhausting but utilimately a great rejuvenator.&lt;/p&gt;
&lt;p&gt;We recently carried out our DrupalCon debrief session where we exchanged what we took away and how we can integrate it into day to day work in the business.&lt;/p&gt;
&lt;p&gt;This is what we learnt:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Neil&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Anybody doing anything interesting or significant on Drupal is using Drupal 7. The time is right to make the switch.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://drupal.org/project/workbench"&gt;Workbench module &lt;/a&gt;solves a whole bunch of content and permissions problems that many of our clients have had. I can see this module becoming a one of our default instalation modules for all new sites.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Ed&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Managing config and DB changes through code is more than just a bragging right. Although it requires a shift in working methods and extra time to test deployment functions, it will yield time savings in managing merges and deployment and improve quality.&lt;/li&gt;
&lt;li&gt;Distributions are really powerful and easier than ever to create. The first thing we'll be doing is creating a starter D7 distro with selection of modules pre configured.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Indy&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;With more OO code in D7 core and contrib, we should start to make more use of OO for custom modules in order to make the code more efficient and maintainable.&lt;/li&gt;
&lt;li&gt;We should make more use of coder module to ensure strict adherence to best practice.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Pablo&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The &lt;a href="http://london2011.drupal.org/conference/sessions/doing-drupal-security-right"&gt;Drupal security talk&lt;/a&gt; was really interesting and highlighted some points you don't normally think about. We should make a security checklist we can through during and after a site build.&lt;/li&gt;
&lt;li&gt;The &lt;a href="http://london2011.drupal.org/conference/sessions/damn-quick-drupal-how-make-drupal-perform-and-scale-rockstar"&gt;performance talk &lt;/a&gt;was also really useful (so useful, we've written up &lt;a href="http://www.cameronandwilding.com/blog/jos%C3%A9/how-make-drupal-perform-and-scale-rockstar"&gt;our notes&lt;/a&gt; on it), this will make a great first list of things to check and implement when looking at the performance of a site.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Tom&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Content staging between environments is still one of the big challenges for Drupal. Lots of people are talking about it, but there is no one good solution yet.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://london2011.drupal.org/conference/sessions/adaptive-responsive-mobile-first-and-drupal-theming-future-html5-css3-and-omega"&gt;Responsive design&lt;/a&gt; is being talked about more and more, it would be great if our themes were responsive by default&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Jos?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Node.js looks really interesting, but we can't quite figure out what we would use it for other than real time chat. Also seem to some serious security loop holes.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://london2011.drupal.org/conference/sessions/building-and-maintaining-distribution-drupal-7-features"&gt;Features and code driven development&lt;/a&gt; should be used as much as possible.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Ben&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The very rapid and recent injection of money and corporate culture into the Drupal ecosystem seems to be causing some tensions. It will be interesting to see how it affects the community.&lt;/li&gt;
&lt;/ul&gt;&lt;p style="font-size:8px"&gt; (&lt;a href="http://www.flickr.com/photos/batigolix/6096262066/"&gt;image credit&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/drupalcon" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;drupalcon&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/ImdHLqcdaq0" height="1" width="1"/&gt;</description>
     <pubDate>Fri, 16 Sep 2011 10:41:05 +0000</pubDate>
 <dc:creator>Neil</dc:creator>
 <guid isPermaLink="false">2322 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/neil-cameron/drupalcon-london-team-cws-takeaways#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/neil-cameron/drupalcon-london-team-cws-takeaways</feedburner:origLink></item>
  <item>
    <title>A video introduction to Drupal</title>
    <link>http://feedproxy.google.com/~r/CameronandWilding/~3/GSoTaxqOXfU/video-introduction-drupal</link>
    <description>&lt;div class="field field-name-field-teaser-image-200 field-type-image field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" src="http://www.cameronandwilding.com/sites/default/files/styles/blog_post_teaser/public/what_is_drupal.jpg" alt="" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Our friends over at the &lt;a href="http://bad-ass.org.uk/"&gt;Brighton Drupal Association&lt;/a&gt;&amp;nbsp;put together this video, which is a really good three minute overview of what actually constitutes Drupal (more than just code). If you are interested in finding out more about Drupal and how it can benefit your organisation, consider going along to the &lt;a href="http://bad-ass.org.uk/"&gt;Discover Drupal Day&lt;/a&gt; in Brighton on September 16th.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;  

&lt;iframe src="http://player.vimeo.com/video/28789460?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="516" height="290" frameborder="0" webkitAllowFullScreen allowFullScreen&gt;&lt;/iframe&gt;&lt;p&gt;&lt;a href="http://vimeo.com/28789460"&gt;What is Drupal?&lt;/a&gt; from &lt;a href="http://vimeo.com/larchmontfilms"&gt;Larchmont Films&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-upload field-type-file field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-taxonomy-vocabulary-1 field-type-taxonomy-term-reference field-label-inline clearfix"&gt;&lt;div class="field-label"&gt;tags:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/category/tags/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel"&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CameronandWilding/~4/GSoTaxqOXfU" height="1" width="1"/&gt;</description>
     <pubDate>Thu, 15 Sep 2011 18:48:38 +0000</pubDate>
 <dc:creator>Ben</dc:creator>
 <guid isPermaLink="false">2321 at http://www.cameronandwilding.com</guid>
 <comments>http://www.cameronandwilding.com/blog/ben-wilding/video-introduction-drupal#comments</comments>
  <feedburner:origLink>http://www.cameronandwilding.com/blog/ben-wilding/video-introduction-drupal</feedburner:origLink></item>
  </channel>
</rss>

