Category Archives: PHP

Making Drupal Messages appearing in modal dialog with Bootstrap 3

This post is another step in the theming Drupal 7 wit Bootstrap 3, you can read my previous article about “Drupal 7 and bootstrap 3 theming the login form“.

Now the purpose here is to change the default Drupal messages display system :

default drupal messages

to this a nice modal message using Bootstrap 3 :

Drupal messages with bootrap 3

Okay let’s start :

1) Fist you need to rewrite the theme_status_messages() in your theme.php file like this :

function [your_theme_name]_status_messages($variables) {
  $display = $variables['display'];
  $output = '';

  $status_heading = array(
    'status' => t('Status message'),
    'error' => t('Error message'),
    'warning' => t('Warning message'),
  );
  foreach (drupal_get_messages($display) as $type => $messages) {
    // ! important : adding html needed for the modal.
    $output = '<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog ">
      <div class="modal-content">
        <div class="modal-body">';

    $output .= "<div class=\"_messages $type\">\n";
    if (!empty($status_heading[$type])) {
      $output .= '<h2 class="element-invisible">' . $status_heading[$type] . "</h2>\n";
    }
    if (count($messages) > 1) {
      $output .= " <ul>\n";
      foreach ($messages as $message) {
        $output .= '  <li>' . $message . "</li>\n";
      }
      $output .= " </ul>\n";
    }
    else {
      $output .= $messages[0];
    }
    $output .= "</div>\n";

    $output .= '</div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->';
  }
  return $output;
}

2) Now into your script.js file add :

// modals.
$('#myModal').modal();

3) Flush your theme registry cache and Voilà ! now every time the messages will be displayed within the modal dialog box.

Hope you enjoyed !

Drupal 7 and bootstrap 3 theming the login form

Bootstrap 3 is out with responsiveness, simplified code, new components etc .. so how to integrate this new features on a Drupal theme ? in this tutorial we’ll try to change the default Drupal login form from this :

startTo this :

final_result

1) First of all we’ll need to create a new theme ( in this tutorial we’ll be using Zen theme to create a subtheme) and download the bootstrap source.

2) Second we’ll need to create a custom module to alter the form and remove some of the uneeded html elements.

Okay no more talk let’s start !

– We begin by including the bootstrap css minified file into the subtheme :

yourtheme.info content :

stylesheets[all][] = bootstrap/css/bootstrap.min.css

Notice no important change appears that’s because we need to add bootstrap classes ..

Now we set what we need for the templates :

// set custom tpl for the login page.
function [your_theme_name]_theme() {

  $items = array();

  $items['user_login'] = array(
    'render element' => 'form',
    'path' => drupal_get_path('theme', '[your_theme_name]') . '/templates',
    'template' => 'user-login',
  );
  return $items;
}

//add class to buttons
function [your_theme_name]_button($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'submit';
  element_set_attributes($element, array('id', 'name', 'value'));

  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  $element['#attributes']['class'][] = 'btn';
  // adding bootstrap classes.
  if($element['#button_type'] == 'submit'){
    $element['#attributes']['class'][] = 'btn-primary';
    $element['#attributes']['class'][] = 'btn-lg';
  }
  if (!empty($element['#attributes']['disabled'])) {
    $element['#attributes']['class'][] = 'form-button-disabled';
  }

  return '<input' . drupal_attributes($element['#attributes']) . ' />';
}

/**** theme form textfields. ***/
function [your_theme_name]_textfield($variables) {

  $element = $variables['element'];
  $output = '';
  // login form adding glyphicon.
  if($element['#name'] == 'name') {
    $output = '<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>';
  }

  // force type.
  $element['#attributes']['type'] = 'text';
  // set placeholder.
  if(isset($variables['element']['#description'])){
    $element['#attributes']['placeholder'] = $variables['element']['#description'];
  }

  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
  // adding bootstrap classes.
  _form_set_class($element, array('form-text', 'form-control', 'input-lg-3'));

  $extra = '';
  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
    drupal_add_library('system', 'drupal.autocomplete');
    $element['#attributes']['class'][] = 'form-autocomplete';

    $attributes = array();
    $attributes['type'] = 'hidden';
    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
    $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
    $attributes['disabled'] = 'disabled';
    $attributes['class'][] = 'autocomplete';
    $extra = '<input' . drupal_attributes($attributes) . ' />';
  }

  $output .= '<input' . drupal_attributes($element['#attributes']) . ' />';

  return $output . $extra;
}

/*** theme password field ***/
function [your_theme_name]_password($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'password';
  element_set_attributes($element, array('id', 'name', 'size', 'maxlength'));
  _form_set_class($element, array('form-text', 'form-control'));

  $output = '';
  // login form adding glyphicon.
  if($element['#name'] == 'pass') {
    $output = '<span class="input-group-addon"><span class="glyphicon glyphicon-eye-close"></span></span>';
  }

  return $output . '<input' . drupal_attributes($element['#attributes']) . ' />';
}

/** Theme form element **/
function [your_theme_name]_form_element($variables) {
  $element = &$variables['element'];

  // This function is invoked as theme wrapper, but the rendered form element
  // may not necessarily have been processed by form_builder().
  $element += array(
    '#title_display' => 'before',
  );

  // Add element #id for #type 'item'.
  if (isset($element['#markup']) && !empty($element['#id'])) {
    $attributes['id'] = $element['#id'];
  }
  // Add element's #type and #name as class to aid with JS/CSS selectors.
  $attributes['class'] = array('form-item');
  if (!empty($element['#type'])) {
    $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
  }
  if (!empty($element['#name'])) {
    $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
  }
  // Add a class for disabled elements to facilitate cross-browser styling.
  if (!empty($element['#attributes']['disabled'])) {
    $attributes['class'][] = 'form-disabled';
  }
  if (isset($element['#parents']) && form_get_error($element)) {
    $attributes['class'][] = 'has-error';
  }

  if($element['#type'] != 'radio'){
    $attributes['class'][] = 'input-group';
  }

  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";

  // If #title is not set, we don't display any label or required marker.
  if (!isset($element['#title'])) {
    $element['#title_display'] = 'none';
  }
  $prefix = isset($element['#field_prefix']) ? '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ' : '';
  $suffix = isset($element['#field_suffix']) ? ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>' : '';

  switch ($element['#title_display']) {
    case 'before':
    case 'invisible':
      $output .= ' ' . theme('form_element_label', $variables);
      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
      break;

    case 'after':
      $output .= ' ' . $prefix . $element['#children'] . $suffix;
      $output .= ' ' . theme('form_element_label', $variables) . "\n";
      break;

    case 'none':
    case 'attribute':
      // Output no label and no required marker, only the children.
      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
      break;
  }
  // remove description we'll use placeholder.
  if (!empty($element['#description'])) {
    //$output .= '<div class="description">' . $element['#description'] . "</div>\n";
  }

  $output .= "</div>\n";

  return $output;
}

Okay now the user-login-template.tpl.php :

<div class="col-md-5 col-md-offset-3 panel">
<div class="panel-heading"><h2><?php print t('Login'); ?></h2></div>
    <div class="panel-body">
    <?php print drupal_render_children($form) ?>

    </div>
</div>

at this point and if everything is ok you should see something like this :

intermediaire

We need to remove the label to get a nice version, in the custom module :

/** Hook_form_alter **/
function [your_module]_form_alter(&$form, &$form_state, $form_id) {
    // user login
    if($form_id == 'user_login'){
        $form['name']['#title_display'] = 'invisible';
        $form['pass']['#title_display'] = 'invisible';
    }
}

Ps : you’ll need to rebuild the theme registry to see the changes !

Et voilà ! hope you enjoyed. Please if you have any idea about how to do this in a more simple way feel free to comment.

Continuous integration, Hudson and PHP Setting up under Ubuntu – PART 2

In the previous article about Hudson : Continuous integration, Hudson and PHP Setting up under Ubuntu – PART 1 we’ve correctly setup the server and got up fully functional and now comes the funny part : Installing the plugins and the PHP Tools to get all the needed reports.

I will use the php-hudson-template which can be found here, this template provides an easy way to get a proper project configuration and it’s much quicker than configuring every thing manually.

Okay let’s start !

Installing plugins

you’ll need to get the hudson-cli to do this, but you can do this using the Web frontend of hudson Server :

curl -c - -O http://[SERVER]:8080/jnlpJars/hudson-cli.jar

java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin checkstyle
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin dry
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin htmlpublisher
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin jdepend
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin pmd
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin template-project
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin violations
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin xunit
java -jar hudson-cli.jar -s http://[SERVER]:8080 install-plugin clover

Installing PHP Tools


pear channel-discover pear.pdepend.org
pear channel-discover pear.phpmd.org
pear channel-discover pear.phpunit.de
pear channel-discover components.ez.no
pear channel-discover pear.symfony-project.com
pear install pdepend/PHP_Depend-beta
pear install phpmd/PHP_PMD-alpha
pear install phpunit/phpcpd
pear install PHPDocumentor
pear install PHP_CodeSniffer
pear install --alldeps phpunit/PHP_CodeBrowser-alpha
pear install --alldeps phpunit/PHPUnit

Getting the php-hudson-template

You’ll need to the hudson home, in my case it’s /var/lib/hudson and under jobs directory do :

git clone git://github.com/sebastianbergmann/php-hudson-template.git

after that you’ll have to change the owner and the group of the directory to let Hudson recognize it, this is very important !

chown -R hudson:hudson php-hudson-template

sudo /etc/init.d/hudson stop
sudo /etc/init.d/hudson start

Build.xml

this is an example of a standard build.xml file, but you’ll need to change executions options when needed, for example to change the code standard for Php checkstyle etc.

<project name="php-object-freezer" default="build" basedir=".">
 <target name="clean">
  <!-- Clean up -->
  <delete dir="build"/>

  <!-- Create build directories -->
  <mkdir dir="${basedir}/build/api"/>
  <mkdir dir="${basedir}/build/code-browser"/>
  <mkdir dir="${basedir}/build/coverage"/>
  <mkdir dir="${basedir}/build/logs"/>
  <mkdir dir="${basedir}/build/pdepend"/>
 </target>

 <!-- Run unit tests and generate junit.xml and clover.xml -->
 <target name="phpunit">
  <exec executable="phpunit" failonerror="true"/>
 </target>

 <!-- Run pdepend, phpmd, phpcpd, and phpcs in parallel -->
 <target name="parallelTasks">
  <parallel>
   <antcall target="pdepend"/>
   <antcall target="phpmd"/>
   <antcall target="phpcpd"/>
   <antcall target="phpcs"/>
   <antcall target="phpdoc"/>
  </parallel>
 </target>

 <!-- Generate jdepend.xml and software metrics charts -->
 <target name="pdepend">
  <exec executable="pdepend">
   <arg line="--jdepend-xml=${basedir}/build/logs/jdepend.xml ./«  />
  </exec>
 </target>

 <!-- Generate pmd.xml -->
 <target name="phpmd">
  <exec executable="phpmd">
   <arg line="./ xml codesize,unusedcode
              --reportfile ${basedir}/build/logs/pmd.xml" />
  </exec>
 </target>

 <!-- Generate pmd-cpd.xml -->
 <target name="phpcpd">
  <exec executable="phpcpd">
   <arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml ./" />
  </exec>
 </target>

 <!-- Generate checkstyle.xml -->
 <target name="phpcs">
  <exec executable="phpcs" output="/dev/null">
   <arg line="--report=checkstyle
              --report-file=${basedir}/build/logs/checkstyle.xml
              --standard=Zend
              ./" />
  </exec>
 </target>

 <!-- Generate API documentation -->
 <target name="phpdoc">
  <exec executable="phpdoc">
   <arg line="-d ./ -t build/api" />
  </exec>
 </target>

 <target name="phpcb">
  <exec executable="phpcb">
   <arg line="--log    ${basedir}/build/logs
              --source ${basedir}/./
              --output ${basedir}/build/code-browser" />
  </exec>
 </target>

 <target name="build" depends="clean,parallelTasks,phpunit,phpcb"/>
</project>

Now the question that you should ask is : where to put this file ??? well it depends on your needs ..
for example when you will get source code from SVN the simpliest way is to add it into the root of your code.

it’s important to have the build.xml reachable by the hudson server ..

Final configuration

Now go back to the web interface of the hudson server, and choose New Job > free-style software project
Choose your Source code management : SVN or Git etc.
Under Build: click Add build Step -> Invoke Ant
Under Post-build Actions : click Use publishers from another project and write : “php-hudson-template
Hit Save.

Then Click Build Now

Enjoy !

Drupal 6, Theming Search Box

In this tutorial i will try to explain how to modifiy default search box provided by Drupal module “Search“, this one of many other methods and i think it’s the simplest way.

First of all you’ll need to enable it from admin>build>modules interface then associate it to a region.

Creating theme file

First of all create a file on you theme directory called : ‘search-block-form.tpl.php‘ which is a copy of template file of search box module, the problem whith drupal generated forms are the hidden fields and input file names so we need to pay attention to them :

<?php
// $Id: search-block-form.tpl.php,v 1.1 2007/10/31 18:06:38 dries Exp $
?>
<div class="container-inline">
    <?php
    //Default form call.
    //print $search_form;
    ?>
    <label>
<span>
<!-- input type text with correct name search_block_form -->
  <input name="search_block_form" type="text" class="keywords" id="edit-search-theme-form-l" maxlength="50" value="Search..." />
 </span>
<!-- action name "op" -->
<input name="op" type="image" src="<?= url(path_to_theme() . '/images/search.gif', array('absolute' => true)) ?>" class="button" />
    </label>

    <?php
    //hidden values !important
    print $search["hidden"];
    ?>
</div>

That’s all ! there’s an interesting forum topic where you can find other methods like preprocess functions etc. :
http://drupal.org/node/224183

Sqlite, emulating on duplicate update functionnality

On my last article i’ve spoken about what a common MySQL developer needs to know to use Sqlite. In this article we’ll try to simulate a missing feature which is updating if key exists “on duplicate update on MySQL” using PHP Exceptions.


            try {
                // init database cnx.
                $db = new PDO('sqlite:' . $databasePath);
                $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

                $sql = "INSERT INTO table
                        (id, content)
                        VALUES
                        (:id, :content)";

                // Prepare statement
                $stmt = $db->prepare($sql);

                // bind the params
                $stmt->bindParam(':id', $id);
                $stmt->bindParam(':content', $content);

                //
                $stmt->execute();
            // Exception code for constraint violation is 23000
            // That's why we catch this error code and do update :
            } catch (Exception $e) {
                if ($e->getCode() == 23000) {
                    try {
                        $sql = "UPDATE
                            table
                            SET
                            content = :content
                            WHERE
                            id = :id";
                        $stmt = $db->prepare($sql);
                        $stmt->bindParam(':content', $content);
                        $stmt->bindParam(':id', $id);
                        $stmt->execute();
                    } catch (Exception $e) {
                        echo $e->getMessage();
                    }
                }
            }