Friday 26 February 2016

How to Add Maxmind IP redirecting to your Drupal 7 theme

This is using GeoIP2 Precision - information on this can be found at http://dev.maxmind.com/geoip/geoip2/web-services Just a quick note on what you’ll need. 1. Some Credits in your Maxmind account http://www.maxmind.com/en/geoip2-precision-services 2. Your domain needs to be on the Javascript Domains list. In your Drupal Template either in template.php or in page.preprocess.php

we need to add the maxmind js .

drupal_add_js('http://js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js', 'external');

In my code I’ve wrapper this in a check to see what page we’re on as I only need it on the front page.

In the themes .info file we have added the line to include this script

scripts[] = js/custom/rcni.maxmind.js

Here’s my code for that file. This is just a either UK or Rest of the World split.
If the page is the same that we are on then we’ll go no where.
And I’ve also made it so to activate this check we’ll add the class ‘ipswitch’ to the page we want it on.


(function ($) {
Drupal.behaviors.rcniMaxmind = {
attach: function (context, settings) {

// this code only needs to run once on landing.

if ( $( "body" ).hasClass( "ipswitch" ) ) {
var redirect = (function () {
/* This implements the actual redirection. */
var redirectBrowser = function (site) {
var uri = 'http://' + window.location.host + '/' + site;
window.location = uri;
};

/* These are the country codes for the countries we have sites for.
* We will check to see if a visitor is coming from one of these countries.
* If they are, we redirect them to the country-specific site. If not, we
* redirect them to world.example.com */
var sites = {
"gb": true
};
var defaultSite = "row";
var onSuccess = function (geoipResponse) {

var site;
/* There's no guarantee that a successful response object
* has any particular property, so we need to code defensively. */
if (!geoipResponse.country.iso_code) {
redirectBrowser("gb");
return;
}
/* ISO country codes are in upper case. */
var code = geoipResponse.country.iso_code.toLowerCase();

if (sites[code]) {
if (code == 'gb') {
site = "uk/home"
var currentLoc = window.location.pathname;
var pathCheck = '/' + site;

if ( window.location.pathname === pathCheck) {
console.log('do nothing');
return;
}
else {
redirectBrowser(site);
}

}
}
else {
site = "row/home"
redirectBrowser(site);
}
};

/* We don't really care what the error is, we'll send them
* to the default site. */
var onError = function (error) {
redirectBrowser("uk/home");
};

return function () {
geoip2.country(onSuccess, onError);
};
}());

redirect();
}
}
};
})(jQuery);

Thursday 25 February 2016

Setting up Vlad development environment

The place to go for more information is https://www.vagrantup.com  & https://vlad-docs.readthedocs.org

What is It ?  A tool for building complete development environments.

Why ?   To decrease development setup time and increase production parity.


What do we need to set up on our local machines -
 
  1. Virtual Box
  2. Vagrant
  3. Ansible - use PIP 

The first two are as easy as going to these websites and downloading the latest versions https://www.virtualbox.org/  and https://www.vagrantup.com/downloads.html

Downloading the third App 'Ansible' may depend on your operating system . At the time of writing it was recommended by Dan that we should install version 1.9.4 using 'pip' .  Or though homebrew will work also. The following command should work

sudo pip install ansible==1.9.4 

This didn't work for me an I ended up install the lastest version with Homebrew, but everything seems to be working fine.

 
Here endeth the set up for your local environment that will only need to be done once.  From here on the instructions will need to be followed per project 

Per Project Settings 
__________________
Once set up we can up a project with inside our folder we should then have a 'docroot' folder .  

In terminal 'cd' into your project folder 
INSTALL VLAD -  which is grabbed from the github page https://github.com/hashbangcode/vlad  - at the time of writing we should be taking Vlad from DEV and not master. 
HOWEVER at the time of writing it's been requested we download the dev version as there are important changes and features on there that we'll need. 
We need to set up a settings.yml file which will go in a sibling folder to docroot called 'settings' 


So here you'll need to create the folder 'settings' and then you can copy an example file from vlad_guts/example.vlad_settings.yml .

Here's my file from my test set up
-


---
# Webserver settings webserver_hostname: 'test.local' webserver_hostname_aliases:  - 'www.test.local'
# Vagrantfile configuration boxipaddress: "192.168.111.122" boxname: "test" host_synced_folder: "../docroot" aux_synced_folder: "../vlad_aux"

 #SSH Settings use_host_id: true

  #CPUs and memory to be allocated vm_cpus: "auto" vm_memory: "auto"
 php_version: "5.6"
 aberdeen_cli_install: true

 db_import_up: true


  • Paths in settings are relevant to wherever the Vagrant file is.  
  • Aux folder should be set to "../vlad_aux" so it appears as a sibling, as in the image above. 
  • Box Ip Address to be unique for each dev and project.  This will need to be agreed with other Devs
  • Aberdeen Cli installation has been added to sql sync database straight from Aberdeen

  •  DB import up - will make sure a Database will import if in vlad_aux/db_io/[path_to_file] if it exists.  More information here .  https://vlad-docs.readthedocs.org/en/latest/usage/variables/
cd into the folder where the 'Vagrantfile' is . 
'cd vlad'
'vagrant up'
To see the database with adminer then add this before your domain  http://www.adminer.domain

Sharing a project .  

we can use the command 'vagrant share'  to get a url to share our project with others , but first we'll need to set ourselves up on https://atlas.hashicorp.com/

Tuesday 23 February 2016

Drupal 7 views : How to sort order on a Multiple data field.

The task - What we have is a column of Dates of when the entity was sent. This could be one or more dates, ie multivalued . The objective here is for each row to present the most recent sent date and for the rows to be sorted by the date. 
 I encountered 2 issues that I had to get over.  
If we we’re just to add a sort here then we get multiple returns for each Entity, which we don’t want. 
The second issue is that the date ‘Multiple Field Settings’ - ‘Reversed’ tick box doesn’t effect my result ordering in that field.  And therefore display the oldest date and not most recent. 
Let’s take a look at the first issue.  To resolve this what I like to do is group the fields together and present 1 row for each Entity , but by doing so the normal way through > Table > Settings > ‘Grouping field’  .  Here I get the right results in the right order but it creates multiple tables for each row.  The solution is to use the module ['https://www.drupal.org/project/views_table_rowspan'] Views Table Rowspan.  With this module you
  1. Install it
  2. Clone your View ‘display’ and this time set the ‘Format’ to ‘table rowspan’ 
  3. now in Table Rowspan > Settings .  Add all the fields and then tick ‘Merge rows in table’ 



Now with that second issue a full fix is to investigate and write a patch. Like https://www.drupal.org/node/2070313  

I’ll be taking a look at this shortly . In the meantime though it can be dealt with in the template layer ( as long as it’s not being outputted to CSV ) .  For my template fix I output all results with out any styling or HTML. Separated with ‘,’ - if the string passes has a comma then I split the value in to an array and take the last element as my date. 
Here's code I used in the template overwrite.


$html_wrapper = '%REPLACE%'; 



if (strpos($output, ',') != TRUE ){

  print str_replace('%REPLACE%', $output, $html_wrapper);

}

elseif(strpos($output, ',') == TRUE ) {

  $date_array = explode(',', $output);

  $last_date = end($date_array);

  print str_replace('%REPLACE%', $last_date, $html_wrapper) ;

}

else {

  print str_replace('%REPLACE%', $output, $html_wrapper);

}

Monday 22 February 2016

Drupal 7 Jquery statement to add Class and remove when tabbing into an input

Here's a snippet of code that will allow you to change the class of an input field in your form when you tab into it.

I've got this in a file in my theme /sites/all/themes/mytheme/js/custom

Remember to add this file to the file /sites/all/themes/mytheme/mytheme.info

(function ($) {
Drupal.behaviors.skyFocus = {
attach: function (context, settings) {

var focusClass = "has-focus";

$('.form-text').keyup(function(e) {
if(e.keyCode === 9){
$(this).addClass(focusClass);
}
}
);
$('.form-text').focusout(function() {
$(this).removeClass(focusClass);
}
);

}
};
})(jQuery);

Friday 19 February 2016

Drupal 7 Views - Views Filter Field Default value 'all' change.

The change is to the field handlers .

To do this we can extend the field handler class for this module which we have in /sites/all/modules/contrib/views_filterfield/handlers/views_filterfield.inc - which itself extends the ‘views_handler_field'

You’ll need to put this new class in a custom module of your own . We’ve got all ours in Custom module called reports and the folders are arranged like this.

Reports /
admin_views_defualt /
includes/
src/
Controller /
Plugin /
Reports/
SqlQueries/
Views/
Wrappers/
theme/

At this point it you haven’t worked with classes before I’d need to go into more depth into namespacing and organisation but don’t want to get too sidetracked. So you’ll have to find this out yourself it you’re not sure.

In the class extension of ‘views_filterfield’ make the change to render the default dates correctly as they’ve been rendered into a sub-array.

We do a check to see if our filter is indeed empty. And we then go and get the value we want to fill it with and put that in the output. Unfortunately it’s not quite that straight forward as we also need to create a load of create_function calls to fill the array where needed.

Here’s the code



/**

 * @file

 * Contains Drupal\report\Views\Filter\DateFilterFieldFilter.

 *

 * The only purpose for extending these filters is to handle dates correctly;

 * by default they don't work because they've been rendered into a sub-array.

 */



namespace Drupal\report\Views\Filter;



use views_filterfield;



class DateFilterFieldFilter extends views_filterfield {



  function render($values) {

    $output = ['all'];



    $filter = $this->get_filter($this->options['views_filterfield_field']);



    // BEGIN CHANGES

    if (!empty($this->view->exposed_input[$filter['expose']['identifier']]['value'])) {

      if (is_array($this->view->exposed_input[$filter['expose']['identifier']]['value'])) {

        $output = $this->view->exposed_input[$filter['expose']['identifier']]['value'];

      }

      else {

        // Turn a single value into an array, so the transform array_walk

        // function works.

        $output = [$this->view->exposed_input[$filter['expose']['identifier']]['value']];

      }

    }

    // END CHANGES



    // Lots of create_function() calls next, as array_walk does not generally

    // play nice with internal functions, as it passes too many args. These

    // will simply throw a warning and not work.

    // @see http://php.net/manual/en/function.array-walk.php




    // Transform spaces to dashes.

    if (!empty($options['views_filterfield_transform_dash'])) {

      array_walk($output, create_function('&$val', '$val = strtr($val, array(" " => "-"));'));

    }



    // Transform case as needed by walking the array of values.

    switch ($this->options['views_filterfield_case']) {

      case 1: // Lower case.

        array_walk($output, create_function('&$val', '$val = drupal_strtolower($val);'));

        break;



      case 2: // Title case.

        array_walk($output, create_function('&$val', '$val = ucwords($val);'));

        break;



      case 3: // Upper case.

        array_walk($output, create_function('&$val', '$val = drupal_strtoupper($val);'));

        break;



      case 4: // Sentence case.

        array_walk($output, create_function('&$val', '$val = drupal_ucfirst($val);'));

        break;

    }



    // Turn the transformed array values into a delimited string.

    $separator = $this->options['views_filterfield_separator'];

    $output = implode($separator, $output);



    // Do some basic sanity checking. We don't want crazy values, do we?

    $checked = filter_xss($output);

    return $checked;

  }



}


Thursday 11 February 2016

Creating exact sized files to help with testing - using terminal and OS X

Syntax for mkfile is as follows:



mkfile -n size[b|k|m|g] filename



Thanks to Os X Daily for the Creating a Large file tip.  It's not only useful for large files tho !

Monday 8 February 2016

PHP comparing if 2 files were modified in X amount of time of each other

So I have 2 files and want to know that they were created at the same time, although there may be a small gap between them, let's say not over 2 mins.

filemtime(filename) - will give us a Unix time stamp.  So

$file_1_timestamp = filemtime($path_to_file1);
$file_2_timestamp = filemtime($path_to_file2);

If ( $file_1_timestamp > $file_2_timestamp-120 && $file_1_timestamp < $file_2_timestamp+120 ) {

TRUE

}

Friday 5 February 2016

Mysql using SUM and DISTINCT - Why not use GROUP


Mysql using SUM and DISTINCT  - Why not use GROUP

Yes the answers in the title .  Consider

SELECT SUM(DISTINCT te.field_company_total_employees_value)

    FROM field_data_field_company_total_employees AS te

    INNER JOIN  field_data_field_user_company AS uc ON te.entity_id = uc.field_user_company_target_id

    INNER JOIN field_claiming_user AS cu ON uc.entity_id = cu.field_claiming_user_target_id

    INNER JOIN field_data_field_urn_offer as uo ON cu.entity_id = uo.entity_id

    WHERE uo.field_urn_offer_target_id = 20

GROUP BY te.id


Produced the results wanted. 

Wednesday 3 February 2016

How to access your .ssh folder from Mac OS File chooser


Recently while in Filezilla and needing to open my id_rsa.pub file in the hidden folder .ssh ; I couldn’t see the folder. 


To view folder ( as long as you know the folder name ) you can use. CMD + SHIFT + G