Tuesday 26 July 2016

Drupal 7 - Extending Push Notification Extended

The following is an extension to Push Notifications module in Drupal 7 to pass through extra data with the Payload.

This module is currently for testing purposes and can be called through the URL call to notifications/send_extend/%

Where % is the User Id of the user we'll be sending the notification to.

The change to the Payload array is in push_notifications_send_alert_extended .

Super Administration and Administration are the only roles allowed to visit the above link.

Module -> push_notifications_extend

push_notifications_extend.info

name = Push Notifications Extend
description = A module for extending the Push Notifications Module
core = 7.x
dependencies[] = push_notifications


push_notifications_extend.module

 'Send APNS Notifications',
    'page callback' => 'push_notifications_extend_manual_send',
    'access callback' => 'push_notifications_extend_send_access',
    'type' => MENU_CALLBACK,
  );

  return $items;
}


function push_notifications_extend_manual_send() {

  $user_to_send_to = arg(2);

  $users_to_notify[] = $user_to_send_to;

  $return = "

Sending push notification to " . count($users_to_notify) . " user.

"; push_notifications_extend_send_message($users_to_notify); variable_set("user_queue", 0); variable_set("apns_sent", 0); return $return; } function push_notifications_extend_send_message($users) { $unix_timestamp = microtime(); $watchdog_msg = 'Sending test message to ' . count($users) . ' user - at ' . $unix_timestamp; $message = "Test - Log Ref : $unix_timestamp"; push_notifications_send_message_extended($users, $message); } /** * Access callback for users to send APNS. * * @return bool */ function push_notifications_extend_send_access() { global $user; $access = FALSE; if (in_array('Super Admin', $user->roles) || in_array('administrator', $user->roles)) { $access = TRUE; } return $access; } /** * Send a simple message alert to an array of recipients. * * @param array $recipients Array of user ids. * @param string $message Message to be included in payload. * @return mixed Flag to indicate if delivery was successful. */ function push_notifications_send_message_extended($recipients, $message) { // Shorten the message characters / 8 bit. $message = truncate_utf8($message, PUSH_NOTIFICATIONS_APNS_PAYLOAD_SIZE_LIMIT, TRUE, TRUE); // Convert the payload into the correct format for delivery. $payload = array('alert' => $message); $tokens = array(); foreach ($recipients as $uid) { $user_tokens = push_notification_get_user_tokens($uid); if (!empty($user_tokens)) { $tokens = array_merge($tokens, $user_tokens); } } // Stop right here if none of these users have any tokens. if (empty($tokens)) { return FALSE; } // Send a simple alert message. push_notifications_send_alert_extended($tokens, $payload); } /** * Handle delivery of simple alert message. * * @param array $tokens Array of token record objects. * @param array $payload Payload. * */ function push_notifications_send_alert_extended($tokens = array(), $payload = array()) { // Group tokens into types. $tokens_ios = array(); $tokens_android = array(); foreach ($tokens as $token) { switch ($token->type) { case PUSH_NOTIFICATIONS_TYPE_ID_IOS: $tokens_ios[] = $token->token; break; case PUSH_NOTIFICATIONS_TYPE_ID_ANDROID: $tokens_android[] = $token->token; break; } } // Send payload to iOS recipients. if (!empty($tokens_ios)) { // Convert the payload into the correct format for APNS. $payload_apns = array('aps' => $payload, 'acme' => 'foo'); push_notifications_apns_send_message($tokens_ios, $payload_apns); } // Send payload to Android recipients if configured correctly. if (!empty($tokens_android) && ((PUSH_NOTIFICATIONS_C2DM_USERNAME && PUSH_NOTIFICATIONS_C2DM_PASSWORD) || PUSH_NOTIFICATIONS_GCM_API_KEY)) { // Determine which method to use for Google push notifications. switch (PUSH_NOTIFICATIONS_GOOGLE_TYPE) { case PUSH_NOTIFICATIONS_GOOGLE_TYPE_C2DM: push_notifications_c2dm_send_message($tokens_android, $payload); break; case PUSH_NOTIFICATIONS_GOOGLE_TYPE_GCM: push_notifications_gcm_send_message($tokens_android, $payload); break; } } }

Friday 22 July 2016

Drupal 7 changing links of the fly in a Drupal Menu

This is a bit of hack but I thought I’d get it documented here anyway. Please for feel free to message me with better solutions for sorting this issue.

The reason you can’t do this with hook_menu_alter is that this method does not create the menu on the fly; as the menu is built and stored in cache.

Here in my code I’ve got a calculation that returns a NID that I want to replace with the default one that I have in the menu item.

So I’ve added this to the body class list and retrieve it in the Javascript.

/*
 * Implements hook_preprocess_html()

 */

function MODULE_preprocess_html(&$variables){

  global $user;

  drupal_add_js(drupal_get_path('module', 'MODULE') . '/js/MODULE.menu.overrides.js');

// the method here calculates what Nid I need to direct what user too. 
    $getNid = SupplierFormHelpers::getNid($user->uid);

    $variables['classes_array'][] = 'ROLE-logged-in';
    $variables['classes_array'][] = $getNid;

  }

}



and here's the Javascript file

/**
 * @file
 * Javascript to replace NID with the one for the current User
 */
(function ($) {

    /**
     * Process controls.
     */
    Drupal.behaviors.moduleMenuOverrides = {

        attach: function (context) {

            // first of all lets place the number somewhere ( body class !! ) and retrieve that .

            if ($("body").hasClass("ROLE-logged-in")){

                var pageNid = 1;

               /* get the body class array and retrieve the next number along */
                var classList = $("body").attr('class').split(/\s+/);

                for (var i = 0; i < classList.length; i++) {
                    if (classList[i] === 'ROLE-logged-in') {
                        var i2 = i + 1;
                        pageNid = classList[i2];
                    }
                }

                /* i now have the number I want to replace with - so let's do a swap */
                
                var editLink = '/node/' + pageNid + '/edit';
                var navigation = $("#block-system-navigation");
                $("#block-system-navigation").each(function(){
                    var html = $(this).html();
                    html = html.replace("/node/1/edit", roleLink);
                    $(this).html(html);

                })

            }

        }
    }

})(jQuery);

Wednesday 20 July 2016

Drupal 7 form API trying to use 'commerce_price' type .

I couldn't find a solution to this. Similar to the question raised here.

http://drupal.stackexchange.com/questions/127864/custom-form-adding-a-commerce-price-field

But I adopted another angle of how to display my form which I think is worth listing. As the form I wanted my user to see is pretty much the same as the one I already had in Admin for the entity then I changed the permissions for the front end users Roles to be able to see and edit the form.

I then used Pathauto to change the URL of the path, as the former path had '/admin/structure' at the beginning which I wasn't happy with.

And finally to add and process some other areas of the form that I wanted to was to user 'hook_form_FORM_ID_alter'



So if you searching for things like

drupal 7 Price with currency widget for form

drupal 7 form api example of '#type' => 'commerce_price',

Then maybe you to like me where barking up the wrong tree !!

Tuesday 19 July 2016

Drupal 7 : How to make an editable Content page that displays depending on the User : Part 1

This is a conceptual note making for this task . Part 2 will be the concise instructions on how to do this.


What I want to do is display some editable content to a User .


> Created a Page in Page Manager
> using the path /profile/edit
> in context selected ‘Node Edit Form’
> Set the Node ID - I’ll need to set this programmatically depending on the User that I’m logged in as
> Save
> now in Content when clicking on the ‘cog’ image on the top left of the pane you’ll be able to select from a ‘FORM’ tab that will have all the fields and buttons you’ll need to display the form .

Next up is to write a programmatical solution for changing the Profile content depending on the User and Role I have logged in.

Wednesday 13 July 2016

OpenOffice : Delete an apostrophe before numbers in cells

I've been having an issue with some data and processing it. On checking I notice that some cells have an apostrophe before the data .

I found how to Find and Replace then in this post https://forum.openoffice.org/en/forum/viewtopic.php?f=9&t=49046

1. Highlight all of the cells and use Format -> Cells to change the cell format to an appropriate number format.
2. With all of the cells still selected, go to the menu Edit -> Find & Replace
3. In the Search For box enter .* (period asterisk)
4. In the Replace with box enter &
5. Select More Options and check Current Selection Only and Regular Expressions
6. Click Replace All

Monday 11 July 2016

Drupal 7 : How to Create and Save data to Entities ( in a formAPI )

Here’s a code sample of how I’ve saved to an Entity using EntityMetaDataWrapper . I’ve included on how you’d save a Taxonomy as well as a text field.
All of this code I’ve put in the ‘_submit’ function of the Form . You could create the entity in the hook_form and then pass this through the $form_state although I’ve decided not to here.

Let's create the Entity . Where you see 'marquee' this is the Entity name and the 'type' is the bundle.

 
$pricing = entity_create('marquee', array('type' =>'pricing'));

We then use this entity to create our MetaDataWrapper - The documentation for entity_metadata_wrapper gives the first argument to be passed in as $type. Which is slightly confusing as above 'type' is the bundle, here its the Entity type for example 'node', 'user', 'file' or a custom type .

$wrapper = entity_metadata_wrapper('marquee', $pricing);

You can then prepare the Entity's data like this
$wrapper->title->set('My title);

To get a list of all the fields that you have in the entity to set you can use the Field Map function .

$a_look_at_the_field_map = field_info_field_map();

No need to leave this line in though as it's just so you can add a breakpoint and check other all your entity maps.

From here you'll be able to check what you can set in your entity. To set a field with a taxonomy it's a easy as
$wrapper->field_type_size->set($sizes_tid);

With text fields that hold more than one piece of data then you'll need to fill each cell . For example we have a carpet price that also needs a currency code set with it. So here I needed to add both bits of data .

$wrapper->field_base_price->amount->set($base_price);
$wrapper->field_base_price->currency_code->set('USD');
If you're wondering how I worked out that I needed to user 'field_base_price->amount->set' and 'field_base_price->currency_code→set' . Well I got those from the database . I checked the database table 'field_data_field_base_price' and in here we have the columns 'field_base_price_amount' and 'field_base_price_currency_code' - if you ignore the 'field_base_price_' part of the name that will give you the directions for where to make these value changes.

All that's left is to Save and leave a success message .

$wrapper->save();
 
drupal_set_message(t('Success'));

Friday 8 July 2016

How to Use Classes in Your Drupal 7 Custom Module

I’ve had a couple of issues with this the last time I’ve set it up from scratch. Normally I’m coming into a project to make changes and not starting from scratch.

The one thing I’d been missing though is that you need to install a ‘Autoload’ into Drupal 7 . This is core in Drupal 8 Install ‘X Autoload’ - https://www.drupal.org/project/xautoload
Enable
In your module create a new folder . i.e. ‘src’
Create and name a file in that Folder. Use camel case and make it self explanatory

For example MyUsefulHelper.php

**
 * @file
 * Contains MyUsefulHelper
 */
 
namespace Drupal\MY_MODULE;
 
 
class MyUsefulHelper {
 
// Methods go here
 
}


Note that in the case of 'src' you do not need to name that in the Namespace .
And then in your .module file use code like.

use Drupal\supplier_form\TaxonomyHelpers;

From here on you should be able to call on the methods in the class.

Thursday 7 July 2016

Drupal 7 - Some useful FormAPI notes

Here's some instruction on how to make a Basic Form with a Menu Link -
https://www.drupal.org/node/1419390

Attached is a basic Hello World version demonstrating this .

How to use Ajax to display, hide or change Fields.

Say for example you have a drop down selection and you'd like it so that a choice here effects the next selections that you may take.

What you need to do is add an 'Ajax Event' to the form field . Take this for an example


$form['shop_select'] = array(
  '#type' => 'select',
  '#title' => t('Selected'),
  '#options' => array(
    0 => t('Fruit'),
    1 => t('Veg'),
  ),
  '#ajax' => array(
    'event' => 'change',
    'wrapper' => 'type-wrapper',
    'callback' => 'type_ajax_callback',
    'method' => 'replace',
  ),
  '#default_value' => 0,
  '#description' => t('Select what your looking for.'),
);


This will be added to the form in hook_form or hook_form_alter .

Following this we'll no need to set up the wrapper that's being called in '#ajax' . Note: make sure this is an 'id' in the div. Using 'class' will not work .

$form['type-wrapper'] = array('#prefix' => '
', '#suffix' => '
');

After this , still in hook_form you can write the code that will change the form to how you want it on the conditions you want. First off I'm checking what the current value in the first dropdown is

$shop_select = isset($form_state['values']['shop_select']) ? $form_state['values']['shop_select'] : 0;

I've made the default here '0' . Next I add another dropdown depending on that result.
switch ($shop_select) {
  case 0:
    // Set default options.
    $form['type-wrapper']['sizes'] = array(
      '#type' => 'select',
      '#title' => t('Sizes'),
      '#options' => array(
        0 => t('Size 1'),
        1 => t('Size 2'),
      ),
    );
    break;
  case 1:
    // Set up case 2
    $form['type-wrapper']['sizes'] = array(
      '#type' => 'select',
      '#title' => t('Sizes'),
      '#options' => array(
        2 => t('Size 3'),
        3 => t('Size 4'),
      ),
    );
    break;
}

Lastly in the 'ajax' call we set up a callback function. We use this to tell our code to only refresh that part of the form that we want it to

function sizes_ajax_callback($form, $form_state) {
   return $form['type-wrapper'];
}