Saturday, June 3, 2017

Upcoming Blog: Crosswords Module for Drupal by using one of the most powerful JavaScript library HandsOnTable ...


TYPO3: Extending Powermail with New Fields & Conditions with working example to generate PDF File in Frontend.

Powermail is a most powerful editor-friendly, easy to use mailform extension with a lots of features like spam prevention, marketing information, optin, ajax submit, diagram analysis.

Here in this blog i'll explain with an example how to extend Powermail extension in Frontend. Development version is with 3.19.0 - stable. This example should work with other lower versions as its based on Extbase and Fluid Template Engine.

To make this example more usable and demanding i am going to add a new feature to it. 
Sometimes we require to generate PDF file with the posted data in the Powermail Form. Say  for example you want a form where Frontend Users/ Website Visitors will fill the form and generate a PDF and sign it and upload it again to the server and Send it. i.e. Workflow is like 
Form >> Generate PDF by clicking on Generate PDF file with the filled values ( but no submit) >> Print and Sign the PDF then Upload >> Submit the whole form. 

We can easily add more steps to this flow or can eliminate any step from here.
Now lets begin with the main matters.
Extension "nirmalya_powermailpdf" has extended Powermail with two additional database fields for form field File and Submit.Those are "signedpdf" to store generated PDF File and "signedpdfbutton" to tell on clicking on which button to generate PDF File.
 To Generate PDF File i've used Javascrpt library i.e. jspdf. 
More technically there is no php code logic to generate PDF.
By using this library PDF File generation has became super fast!!!
Adding some screenshot from Backend while creating fields for a Powermail Form.
Submit Filed extended with a checkbox to set whether its PDF File Creation button or not.

File Field extended with a checkbox whether it's to store Generated PDF File or not.

Please Fork this extension from GitHub and use it - extend it - customize it as per your need. I am also happy to hep you more on your requirements.

GitHub: https://github.com/nirmalyamondal/TYPO3-Extensions/tree/master/nirmalya_powermailpdf/

Monday, April 10, 2017

Drupal 8 - Restricting a node content type with access token from viewing.

Now i'll share a Module to alter the existing Drupal "Site Information" form. Specifics:
  • A new form text field named "Site API Key" needs to be added to the "Site Information" form with the default value of “No API Key yet”.
  • When this form is submitted, the value that the user entered for this field should be saved as the system variable named "siteapikey".
  • A message should inform the user that the Site API Key has been saved with that value.
  • When this form is visited after the "Site API Key" is saved, the field should be populated with the correct value.
  • The text of the "Save configuration" button should change to "Update Configuration".
  • This module also provides a URL that responds with a JSON representation of a given node with the content type "page" only if the previously submitted API Key and a node id (nid) of an appropriate node are present, otherwise it will respond with "access denied".
This Drupal Module is available here at GitHub.
https://github.com/nirmalyamondal/Drupal-Modules/tree/master/site_apikey

Tuesday, February 14, 2017

Theming with Drupal 8

|-config
|    |-install
|    |    |-themename.settings.yml
|    |-schema
|    |    |-themename.schema.yml
|-css
|    |-style.css
|-js
|    |-business.js
|-images
|    |-buttons.png
|-includes
|    |-bootstrap
|    |-flexslider
|-templates
|    |-block.html.twig
|    |-comment.html.twig
|    |-html.html.twig
|    |-maintenance-page.html.twig
|    |-node.html.twig
|    |-page.html.twig
|-favicon.ico
|-logo.png
|-screenshot.png
|-themename.breakpoints.yml
|-themename.info.yml
|-themename.libraries.yml
|-themename.theme

Friday, February 3, 2017

Migration Tutorial: Node Migration from Drupal 7 to Drupal 8

Content Type - Node Migration from Drupal 7 to Drupal 8.
Here i am assuming that you have already gone through my previous blog related to Taxonomy Terms data migration. If not no problem too :)
Say we are developing a module as Custom Migration module with Module key as "migrate_custom".
And yes we'll require to develop this for Drupal 8 :) by maintaining its standard.
migrate_custom will have some dependencies with other modules like Migrate (migrate), Migrate Plus (migrate_plus), Migrate Tools (migrate_tools), Migrate Drupal ...

Lets start with Node Migration with Code Example:
Our aim is to migrate all Node with content type= Blog from d7.blog to d8.blog through a command like
$ drush migrate-import custom_blog --limit="500 items"
Ad per Drupal 8 standard we need a yml file to define everything and a php file to process that yml.
Here is there file/ folder structure
migrate_custom\src\Plugin\migrate\source\Blog.php
migrate_custom\config\install\migrate_plus.migration.custom_blog.yml

In .yml file we define four major parts. These are id, source, process and destination. Id is to identify this Migration process. Source is defined with the data source. Process define basically the mapping of fields in between destination and source.

id: custom_blog
label: Blog node migration from Drupal 7
migration_group: custom
dependencies:
 enforced:
    module:
      - migrate_custom
source:
  plugin: custom_blog
destination:
  plugin: entity:node
  bundle: blog
process:
#  nid: nid
#  vid: vid
  type: type
  langcode:
    plugin: static_map
    bypass: true
    source: language
    map:
      und: und
  title: title
  uid: uid
  status: status
  created: created
  changed: changed
  promote: promote
  sticky: sticky
  'body/format':
    plugin: static_map
    bypass: true
    source: body_format
    map:
      1: plain_text
      2: restricted_html
      3: full_html
      4: full_html
  'body/value': body_value
  'body/summary': body_summary
  field_highlight: fieldHighlightValue
field_image: images

Inside Blog.php class File extends SqlBase { } with four basic public functions these are
1. query() to fetch data from the source.
2. fields() to defined needed fields.
3. getIds() to get and return fid of File.
4. prepareRow() is basically to set source Property. Here we are settings uri.

A working copy of this Migration is available at Github.
https://github.com/nirmalyamondal/Drupal-Modules/blob/master/migrate_custom/

Saturday, January 7, 2017

Git for Beginners Or Git at a glance.

Git is a "distributed" VCS. You can run it locally and disconnected from the Internet, and then "push" your changes to a remote system (such as GitHub) .
It's a source code management system for software development.
A git repository contains, among other things, the following: A set of commit objects. A set of references to commit objects, called heads.
Here i am listing down some Git commands with brief text about what that command does.

1. Remove Git Tracking
$ rm -rf .git

2. Show Origin of the repository
$ git remote show origin

3. Adding files to Git
$ git add <filename>
$ git add *

4. Commit files
$ git commit -m "Commit message."
$ git commit -a

5.Status i.e list the files you've changed and those you still need to add or commit:
$ git status

6. Push i.e.send changes to the remote master branch of your remote repository:
$ git push origin master/dev/prod/branchName

7. Connect to a remote repository to be able to push to it:
$ git remote add origin <server>

8. List all currently configured remote repositories
$ git remote -v

9. List all the branches in your repository, and also tell you what branch you're currently in:
$ git branch

10. Create a new branch and switch to it:
$ git checkout -b <branchname>

11. Switch from one branch to another:
$ git checkout <branchname>

12. Delete the feature branch:
$ git branch -d <branchname> (not the remote branch!)

13. Push the branch to your remote repository, so others can use it:
$ git push origin <branchname>

14. Push all branches to your remote repository:
$ git push --all origin

15. Delete a branch on your remote repository:
$ git push origin :<branchname>

16. Fetch and merge changes on(from) the remote server to your working directory:
$ git pull

17. To merge a different branch into your active branch:
$ git merge <branchname>

18. View all the merge conflicts:
$ git diff

19. View the conflicts against the base file:
$ git diff --base <filename>

20. Preview changes, before merging:
$ git diff <sourcebranch> <targetbranch>

21. Tags. You can use tagging to mark a significant change set, such as a release:
$ git tag 1.0.0 <commitID>

22. Push all tags to remote repository:
$ git push --tags origin

23. Git add remote upstream
$ git remote add upstream https://github.com/nirmalyamondal/Drupal-Modules.git

24. If you want to see more information about a particular remote, you can use the git remote show [remote-name] command.
$ git remote show origin\

25. Undo local changes
If you mess up, you can replace the changes in your working tree with the last content in head:
Changes already added to the index, as well as new files, will be kept.
$ git checkout -- <filename>

26. Check the log of the Git commit 
$ git log

27. Tell Git who you are
git config --global user.name "Nirmalya Mondal"
git config --global user.email nirmalya_email@domain.com
git config --list

28. Create a new local repository
$ git init

29. Instead, to drop all your local changes and commits, fetch the latest history from the server and point your local master branch at it, do this:
$ git fetch origin
$ git reset --hard origin/master

30. Check out a repository
$ git clone /path/to/repository
$ git clone username@host:/path/to/repository

31. Removes all removed remote branches
$ git fetch --all --prune

32. Stashes the local changes, so they can’t be lost during a git pull.
$ git stash

33. Restores the changed files from the stash and tries to merge them.
$ git stash apply

34. Reverts an commit that is already committed and pushed.
$ git revert <hash>

35. Removes the given files from the remote repository
$ git rm <file1> <file2>

Don't be confused with pull and fetch command. In the simplest terms, git pull does a git fetch followed by a git merge.

Git's Workflow that i follow is like -
-------------
Forking the repository -> cloning it -> creating feature branches -> committing changes -> submitting pull requests.
-------------

More commands to be added soon ... 

Some useful Ubuntu commands we use frequently.

There are some Ubuntu commands we use very frequently and its harder to remember these all. To avoid searching over the net i am writing those down here precisely for reference so that i can have a look at it anytime.

1. Setting file permissions to 664 recursively -
$ find . -type f -exec chmod 664 {} \;

2. Setting folder permissions to 775 recursively -
$ find . -type d -exec chmod 775 {} \;

3. Delete files folders recursively -
$ rm -rf folderName

4. Search for a "string" in your system -
$ grep -nr "string"

5. Generating An ISO file From A Folder
$ mkisofs -o image.iso -R /path/to/folder/
$ mkisofs -o image.iso -R $HOME (for home directory)

6. Download and extract Tar file in a command
$ wget url-to-tar-file -O - | tar xfz -
$ wget http://website.com/project/tarFile_4.7.tar.gz -O - | tar xfz -

I also prefer dtrx to unzip files. Because with a single command you can unzip any zipped file format.
To install that use this command
$ sudo apt-get install dtrx

7. Killing a halted process
Top command to list down all process with its id.
$ top 
$ kill -SIGKILL procesid
Or we can use this command below as well
$ kill -SIGTERM procesid

8. Symlink through command
To create a symlink at /foo/bar which references to file /usr/bin/bar use this command below
$ ln -s /usr/bin/bar /foo/foo

9. Reading file say error log of Apache webserver
$ tail -f /var/log/apache2/error.log


10. Export Import mySql data file -
$ mysqldump -u root -p password databaseName > database_filename.sql
$ mysql -u root -p password -h localhost databaseName < database_filename.sql

Many more to add ...

Thursday, December 22, 2016

Migration Tutorial: Taxonomy Migration from Drupal 7 to Drupal 8

Taxonomy consists with Vocabulary and Terms.
While migrating Taxonomy Terms we've to consider few basic settings. Like whether our destination database (drupal 8 instance) is already containing some old data or not. Whether we need to rollback post migration ... If we follow migration strategy and develop our code based on that we can easily achieve that.
Here we'll be introduced with dedupe_entity . It's a process plugin with two configuration keys and these are entity_type and field. It'll rename the field value automatically while already exist. This facility is available from Migrate Module. For more detail please refer here.

Here you can find an working example of Taxonomy - Term - Vocabulary migration working copy.
Please refer the Github code for that.

Migration of Vocabulary:
Migration of Vocabulary is done with these files below.
migrate_custom\src\Plugin\migrate\source\Vocabulary.php
migrate_custom\config\install\migrate_plus.migration.custom_taxonomy_vocabulary.yml

Please refer Vocabulary.php for code reference.
In .yml file we'll define four definitions as required i.e. id, source, process, destination.
So the .yml file will look like this -
id: custom_taxonomy_vocabulary
label: Drupal 7 taxonomy vocabularies
migration_group: custom
dependencies:
  enforced:
    module:
      - migrate_custom
source:
  plugin: custom_taxonomy_vocabulary
process:
  vid:
    -
      plugin: machine_name
      source: machine_name
    -
      plugin: dedupe_entity
      entity_type: taxonomy_vocabulary
      field: vid
      length: 32
  label: name
  name: name
  description: description
  hierarchy: hierarchy
  module: module
  weight: weight
destination:
  plugin: entity:taxonomy_vocabulary

Here the significant plugin in process is "dedupe_entity". This Ensures value is not duplicated against an entity field (Taxonomy). If the value is foo and there is already an entity where the field value is foo, then the plugin will return foo1. For more detail please refer core/modules/migrate/src/Plugin/migrate/process/DedupeEntity.php

Migration of Terms:
migrate_custom\src\Plugin\migrate\source\Term.php

migrate_custom\config\install\migrate_plus.migration.custom_taxonomy_term.yml

Here in Term.php we fetch Term data from 'taxonomy_term_data' and do the needful process before setting the source property.
id: custom_taxonomy_term
label: Drupal 7 taxonomy terms
migration_group: custom
dependencies:
  enforced:
    module:
      - migrate_custom
source:
  plugin: custom_taxonomy_term
process:
  tid: tid
  vid:
    plugin: migration
    migration: custom_taxonomy_vocabulary
    source: vid
  name: name
  description: description
  weight: weight
  parent:
#    -
#      plugin: skip_on_empty
#      source: parent
    -
      plugin: migration
      migration: custom_taxonomy_term
  changed: timestamp
destination:
  plugin: entity:taxonomy_term
migration_dependencies:
  required:
    - custom_taxonomy_vocabulary


Tuesday, December 20, 2016

Configuring UBUNTU 14.04 for WWW root directory from /var/www/html to /home/user/Public

This is very very basic topic but still we need this while configure our new Ubuntu system. Our Public profile gets encrypted thats why its more secure to www/html . I always prefer to use Public folder to setup local development website.

We need to follow these steps below to set this.

sudo gedit /etc/apache2/sites-available/000-default.conf

and change these lines
DocumentRoot /var/www/html to DocumentRoot /home/user/Public
Here set "user" accordingly.
Then search for

<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

and change to

<Directory /home/user/Public>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>

and save it.
Now restart apache server to get the changes.

sudo service apache2 restart

-- Thats it.

Tuesday, November 29, 2016

Migration Tutorial: Files Migration from Drupal 7 to Drupal 8

As per Wikipedia Data Migration is the process of transferring data from one system to another while changing the storage, database or application. In reference to the ETL (Extract-Transform-Load) process, data migration always requires at least Extract and Load steps.
 Like Migrating Data from Drupal 7 database to Drupal 8 database. We can perform Migration on file systems.
Migration can also happen to same (Drupal 7 to Drupal 7) or in between two other systems.

Where Upgrade is the process of replacing your existing software with a newer version of the same product. Like Upgrading your site from Drupal 7 to Drupal 8 version.
 
Here We'll focus on Migration of NODE or Content Type. Before we start reading about the NODE migration process we must be familiar with some basic things.
Please be sure that character sets (encoding) are set as same of Migration Source Data and Migration Destination Data like UTF-8.
Migration basically happens with three major steps i.e analyzing source data, prepare destination data structure and the process stays in between.
Say we are developing a module as Custom Migration module with Module key as "migrate_custom".
And yes we'll require to develop this for Drupal 8 :) by maintaining its standard.
migrate_custom will have some dependencies with other modules like Migrate (migrate), Migrate Plus (migrate_plus), Migrate Tools (migrate_tools), Migrate Drupal ...


Lets start with Files Migration with Code Example:
Our aim is to migrate all records from d7.file_managed to d8.file_managed through a command like
$ drush migrate-import custom_file --limit="500 items"
Ad per Drupal 8 standard we need a yml file to define everything and a php file to process that yml.
Here is there file/ folder structure
migrate_custom\src\Plugin\migrate\source\File.php
migrate_custom\config\install\migrate_plus.migration.custom_file.yml

In .yml file we define four major parts. These are id, source, process and destination. Id is to identify this Migration process. Source is defined with the data source. Process define basically the mapping of fields in between destination and source.

id: custom_file
source:
  plugin: custom_file
process:
  fid: fid
  filename: filename
  uri: uri
  uid:
    -
      plugin: default_value
      default_value: 1
destination:
  plugin: entity:file
status: true
migration_group: custom
dependencies:
  module:
    - file
label: Migrate D7 Files
migration_dependencies: {}

Inside File.php class File extends SqlBase { } with four basic public functions these are
1. query() to fetch data from the source.
2. fields() to defined needed fields.
3. getIds() to get and return fid of File.
4. prepareRow() is basically to set source Property. Here we are settings uri.

A working copy of this Migration is available at Github.

Sunday, November 20, 2016

Drupal 8: Show content based on website visitor's country or content localization/ personalization.

Sometimes we need localization of contents i.e if a website visitor is browsing site from USA will be shown different content then someone is browsing from India or Germany.
So our aim is to show Content based on Visitor's Country, Geo IP, Geo Location.

To do so we'll extend the required content type with a filed say Country. While creating a new content there it will appear a Select Box to choose country as an Option. If this content is set to a country then it'll be available for that country only otherwise it'll be available for all countries.

Here is the technical guidance towards the solution.
Drupal Modules required
  • Country
  • Composer Manager
  •  Address
  • GeoIP
Regarding enabling those modules within Drupal please refer my another blog as "Drupal 8, Modules, Composer JSON, Platform.sh".
For example i've created one content type as "Country Based Content" with fields Title, Body, Country.
Where Country is field type Country.
Also created some contents of the above content type.

Created a view as "country" to show this content type in the Front-end of the website through view Module.
Its very easy but still i am attaching a screen-shot for beginners.
Usage of GeoIP Module :
GeoIP Module tells Drupal about the Country location of the visitor of the site based on Visitor’s
IP Address.
To explain it more technically,
GeoIP Module register a service as “geoip.geolocation” via its Constructor by following Drupal
Service registration standard.
We need to trace the website visitor’s IP v4 address through our PHP code and have to pass
this IP Address to GeoIP Module.
We use this code to trace the IP Address.
$visitorIp = \Drupal::request()->getClientIp();
As per my previous state we need to call the service:
\Drupal::service('geoip.geolocation')->geolocate('14.140.162.242');
So here is the output below:
CommerceGuys\Intl\Country\Country Object
(
[countryCode:protected] => IN
[name:protected] => India
[threeLetterCode:protected] => IND
[numericCode:protected] => 356
[currencyCode:protected] => INR
[locale:protected] => en
)
Now we’ll access property of Country Object from its Data Model.
We need to get Country Code value from countryCode” property. So this code below will return
“IN” as my country code.
\Drupal::service('geoip.geolocation')->geolocate($visitorIp)->getCountryCode();

localization of Content for Website Visitors:
As i am browsing this site from from India so it’ll display only contents belong to India.
Let’s explain a little bit in coding level.
To alter the view we’ve used hook_views_query_alter()
Where we’ve traced the view id to alter.
function geoip_content_views_query_alter(Drupal\views\ViewExecutable $view,
Drupal\views\Plugin\views\query\Sql $query) {
switch ($view->id()) {
case 'country':
$data = 'IN';
$query->where[2]['conditions'][1]['value'] = [$data];
break;
}
}

Drupal 8, Modules, Composer JSON, Platform.sh

In Drupal CMS we can integrate Modules in different ways like uploading module via module manager/ extent, manually copy pasting module folders, via Drush command, Drupal consol and Composer.

Most preferable ways are either via Drush or by Composer. Now we are sometimes confused what is best way to do that actually. My personal opinion is whatever procedure/ technique u've applied must reach the  requirement properly. I also prefer by Dursh or by Composer.
Now some modules has dependency on third party libraries. Drush is unable to load those vendor libraries.
Better explain through an example.
Lets consider about Address Module. Address has third party vendor/ library dependency and if we execute command like

$drush cr --continue-with-error/ --no-halt-on-error
$drush en Address -y

It'll successfully download the Address module but will throw error about Vendor dependency i.e. Address Module will not be enabled.

So, drush fails to enable Address module. Here we need Composer extensively. Composer checks the Module and its Vendors defined in composer.json file. So we need to execute commands like this -

$composer config repositories.drupal composer https://packages.drupal.org/8
$composer require "drupal/address ~1.0"

Similarly to add geoip Module we can execute this command.

 $composer config repositories.drupal composer https://packages.drupal.org/8
$composer require "drupal/geoip 2.x-dev"

Now what should we do when we are on Platform.sh ?
To be continued ...

Wednesday, November 16, 2016

Update Day - Date Time based on systems local time-zone of Website Visitor.

The headline is not quiet clear itself. Definitely it needs some explanation what it actually want to tell. Going through with an example will be a good approach for me to clarify.

Say, there is a WebInar as "What CSS3 can do?" is going to happen at January 16, 2017 10.00 PM
And  considering this WebInar is going to happen on IST time i.e. GMT+5:30 or UTC+5:30

Lets say HTML tag structure is like below
<ul class="webinar-info">
 <li><i class="fa fa-calendar"></i> January 16, 2017</li>
 <li><i class="fa fa-clock-o"></i> 10:00 PM</li>
</ul>

Now our JavaScript code will follow these flowchart to convert this IST to another time zone based on website visitors local system. i.e. If some is browsing this site from EST zone this IST will appear to the visitor on EST time.
  • Read Date Time from the html tag and convert this to time-stamp.
  • Converting this IST time-stamp to UTC-GMT time-stamp.
  • Get time offset of the Visitor's timezone.
  • Calculate the Visitor's local time-stamp based on GMT time-stamp and time offset.
  • Now, generate local date, time, year based on the calculated local time-stamp.
  • Display in the required format by over-writing it.
Here is a sample code that does this same thing above.

var pageInitialized = false;
Drupal.behaviors.webinar_upcomingevent = {
    attach: function(context) {
    if(pageInitialized) return;
    pageInitialized = true;
        ;(function($){
            //return ;
            if($("ul.webinar-info li:first").text().trim().length > 1 ){
                var wInarDateText    = $("ul.webinar-info li:first").text().trim();
                var wInarDate     = wInarDateText.split(" ");    //alert(wInarDate[1].replace(/^,|,$/g,''));

                var wInarTimeText    = $("ul.webinar-info li:last").text().trim();   
                var hours = Number(wInarTimeText.match(/^(\d+)/)[1]);
                var minutes = Number(wInarTimeText.match(/:(\d+)/)[1]);
                var AMPM = wInarTimeText.match(/\s(.*)$/)[1];
                var AMPM = AMPM.toUpperCase();
                if(AMPM == "PM" && hours<12) {
                     hours = hours+12;
                }
                if(AMPM == "AM" && hours==12) {
                     hours = hours-12;
                }
                var sHours = hours.toString();
                var sMinutes = minutes.toString();
                if(hours<10) sHours = "0" + sHours;
                if(minutes<10) sMinutes = "0" + sMinutes;

                var monthNumber = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"].indexOf(wInarDate[0].toLowerCase());
                //var monthNumber = monthNumber + 1;
                var wInarIST    = new Date(wInarDate[2],monthNumber,wInarDate[1].replace(/^,|,$/g,''),sHours,sMinutes).getTime();
                // Perfect timestamp has been calculated "wInarIST"
                //alert(new Date(wInarIST).toUTCString());
                //Considering TimeZone = IST = +5Hrs30mins = +330Mins to milliseconds
                var utcGmtTStamp    = wInarIST - 330*60*1000;
                var offset             = new Date().getTimezoneOffset()*60*1000;
                var localTimeStamp    = utcGmtTStamp - offset;
                //Local timestamp calculation is perfect
                //alert('ist='+wInarIST+'utcGmtTStamp='+utcGmtTStamp+'offset='+offset+'localTimeStamp='+localTimeStamp);
                var localDate    = new Date(localTimeStamp);
                var yearL    = localDate.getFullYear();
                var monthL   = localDate.getMonth();
                var dayL     = localDate.getDate();
                var hourL    = localDate.getHours();
                var minuteL  = localDate.getMinutes();
                //var secondsL = localDate.getSeconds(); 
                var amPmLocal    = hourL >= 12 ? 'PM' : 'AM';
                hourL = hourL % 12;
                hourL = hourL ? hourL : 12; // the hour '0' should be '12'
                minuteL = minuteL < 10 ? '0'+minuteL : minuteL;

                var monthArray = new Array();
                monthArray[0] = "January";
                monthArray[1] = "February";
                monthArray[2] = "March";
                monthArray[3] = "April";
                monthArray[4] = "May";
                monthArray[5] = "June";
                monthArray[6] = "July";
                monthArray[7] = "August";
                monthArray[8] = "September";
                monthArray[9] = "October";
                monthArray[10] = "November";
                monthArray[11] = "December";
                //alert('monthNumber='+monthNumber+'year='+year+'month='+month+'day='+day+'hour='+hour+'minute='+minute);
                $("ul.webinar-info li:first").html('<i class="fa fa-calendar"></i> '+monthArray[monthL]+' '+dayL+', '+yearL);
                $("ul.webinar-info li:last").html('<i class="fa fa-clock-o"></i> '+hourL+':'+minuteL+' '+amPmLocal);
            }
        })(jQuery);
    }
};

This code is based on Drupal 8 behaviour along with some jQuery dependency.
This code also checks whether this it's executing more then once.

Sunday, November 6, 2016

Drupal 8: Validate a file while uploading via AJAX.

In Drupal 8 file uploading is done beautifully with its builtin AJAX support. Now visitor can upload many dump files into your server. This file uploading also gets entry into database with status 0 ;) Or may be you want to allow validated CSV file to be in server for further process.
Say, User is uploading test.csv file. You are checking the content of CSV file is as per required format and acceptable.
To do so you need to take help of hook function in your .module file. Like
function HOOK_file_validate(FileInterface $file) {
}
Here's the complete code :
use Drupal\file\FileInterface;

/**
 * hook function to check CSV file while uploading
 * $dataRow[0]->Name->string,  $dataRow[1]->Mobile->number
 * @param $file
 * @return array
 *
 */
function osu_studentdataupload_file_validate(FileInterface $file) {
  // Get Type of The Node so that this function validate only the specific.
  $node_type = getNodetypeFromUrl();
  if ($node_type == 'myNodeType') {
      //$file->id;
      // Getting Temp path :: we still don't have fully access to the file
      $filePath = $file->getFileUri();
      //$file->getFilename();
      $errors = [];
      foreach (getCsvFileRow($filePath) as $dataRow) {
        //if (!empty($dataRow[0]) && (1 === preg_match('~[0-9]~', $dataRow[0]))) {
        if (1 === preg_match('~[0-9]~', $dataRow[0])) {
          $errors[] = '"' . $dataRow[0] . '" - has number(s).';
        }
        if ((!empty($dataRow[1])) && (0 === preg_match('~[0-9]~', $dataRow[1]))) {
          $errors[] = '"' . $dataRow[1] . '" - has string.';
        }  
      }
      return $errors;
      }
  }
}

/**
 * Get NodeType from anywhere inside Drupal from Request url.
 *
 * @return string
 * The current node_type.
 *
 */
function getNodetypeFromUrl() {
  // While Creating
  $nodeTypeObj = \Drupal::request()->attributes->all()['node_type'];
  if (is_object($nodeTypeObj)) {
    $node_type = accessProtected($nodeTypeObj, 'type');
  }
  // While Editing
  $nodeObj = \Drupal::request()->attributes->all()['node'];
  if (is_object($nodeObj)) {
    $nodeObjToArray = (array) $nodeObj;
    $prefix = chr(0) . '*' . chr(0);
    $node_type = $nodeObjToArray[$prefix . 'values']['type']['x-default'];
  }
  return $node_type;
}

/**
 * Access protected property of Object by using ReflectionClass.
 *
 * @param Object
 * An Object containing public/restricted property.
 * @param string
 * The name of the property need in return.
 *
 * @return
 * Value of the required property.
 *
 */
function accessProtected($obj, $prop) {
  $reflection = new ReflectionClass($obj);
  $property = $reflection->getProperty($prop);
  $property->setAccessible(true);
  return $property->getValue($obj);
}

/**
 * CSV File format handler.
 *
 * @param file path
 * A CSV file path to read contents.
 *
 * @return array
 * Array of data of the current line.
 *
 */
function getCsvFileRow($bigDataFile) {
  $handler = fopen($bigDataFile, 'r');
  if ($handler === false) {
    throw new Exception();
  }
  while (feof($handler) === false) {
    yield fgetcsv($handler);
  }
  fclose($handler);
}

Understanding Camunda BPM at Basic Level and deploying a BPMN workflow.

Here i am trying to share some understanding for beginners by writing down a technical blog regarding
Camunda BPM
It's specially for my reference to recall and understand it at a glance whenever needed and may be this is helpful to someone else as well ;)

Camunda BPM Basics:
Camunda BPM is a JAVA based open-source framework for Business Process Management.
Camunda implements 3 different standards in the BPM and these are
  • BPMN 2.0 - Business Process Model Notation.
  • CMMN 1.1 - Case Management Model and Notation.
  • DMN 1.1 - Decision Model and Notation.
I am not elaborating this blog by describing about Camunda Modeller. Considering that Reader is already aware of that or please refer https://docs.camunda.org/manual/.
The Camunda BPM web applications are based on a RESTful architecture.
JAX-RS based Rest API, AngularJS, RequireJS, jQuery, Twitter Bootstrap are the used frameworks for it.
Camunda BPM consists with Cockpit, Tasklist, Admin section.
Cockpit -  Monitoring and operations that allows you to search for process instances, inspect their state and repair broken instances.
Tasklist - A web application for human workflow management and user tasks that allows process participants to inspect their workflow tasks and navigate to task forms in order to work on the tasks and provide data input
Admin - It allows you to manage users, groups and authorizations.

I am not going to discuss more detail about its architecture, extensions, features. Camunda BPM also helps to generates various reports to its deployed workflows.
Here i'll only discuss with BPMN diagram in brief and its simple deployment with example.

BPMN Basics:
BPMN implementation done with several components.
Like Participants (Pool, Lane), Subprocesses (Subprocess, Transaction, Event Subprocess), Tasks (Service, User, Script), Gateways (XOR, OR, AND), Events (Start, End, Termination, Message)

Designing a BPMN Diagram:

By using Camunda Modeler tool we design the required BPMN workflow diagram.
This Modeling tool is platform independent.
We also set the form variables for gateways while modelling.

Deployment Strategy:
Designing BPMN workflow Model and deploying it inside Camunda Engine is a lengthy process along with some prerequisite environment settings like Java JDK 1.7+ and Apache Maven.

Deployment steps are listed below:
  1. Installation of Camunda BPM Platform and Camunda Modeler. 
    • Download an Apache Tomcat bassed standalone distribution of the Camunda BPM platform.
    • Run Camunda by execute the script named start-camunda.bat(Windows) or start-camunda.sh (Unix).
    • In Browser Camunda will become available in this url http://localhost:8080/camunda-welcome/index.html
    • Download the latest Camunda Modeler release.
    • Modeler can then be started by running the executable named camunda-modeler.
  2. Set up an Apache Maven-based process application inside Eclipse.
    • Add Camunda Maven Dependencies to Eclipse JAVA IDE by adding some of its plugins.
  3. Model a diagram through Camunda Modeller. (https://docs.camunda.org/get-started/bpmn20/model/)
    • Create a new BPMN Diagram.
    • While creating set the task names properly for better understanding and variables for various GATEs.
  4. Generating a Project .war file and Exporting through Apache-Maven. 
    • Add a Process Application Class to the Project. 
    • Add a META-INF/processes.xml Deployment Descriptor file.
  5. Deploying and Checking a .war file inside Camunda BPM.
    • Need to move .war file from Maven project to the $CAMUNDA_HOME/server/apache-tomcat/webapps folder.
    • Test the BPMN 2.0 Process with Camunda Tasklist and Camunda Cockpit.
    • Now use Cockpit to check if the process is successfully deployed. Go to http://localhost:8080/camunda/app/cockpit
    • Start a Process Instance.
    • In Camunda Tasklist ( http://localhost:8080/camunda/app/tasklist ) click on the Start process button to start a process instance.
    • If required Configure Process Start Authorizations.
    • To Work on the Task go to Tasklist ( http://localhost:8080/camunda/app/tasklist ) and log back in with the user credentials.

Some More Information:
PHP SDK is available here http://camunda.github.io/camunda-bpm-php-sdk/ and
**If there is any change in BPMN Model/ Workflow we need to Re-Deploy inside Camunda by re-generating a new “.war” file :)

Screenshot of a Deployment of BPMN Model in Eclipse.

Thursday, September 22, 2016

Setup Sub-Domain for TYPO3 installation in your local system for Apache server.

I've installed TYPO3 version 7.6.10 in Ubuntu 14.04 successfully. Now my aim is to setup a sub-domain for this installation.
We can first configure vhost and then install TYPO3 as well.
Here i am using Apache as a Web Server.
In Ubuntu i've set web drectory (WWW) to /home/nirmalya/Public/ instead of /var/www/html/
So i will explain the configuration steps accordingly.
Say, my TYPO3 installation is here in /home/nirmalya/Public/t7610.local where "t7610.local" is root directory of TYPO3.

i.e. In browser http://localhost/t7610.local/ should be http://t7610.local/

For better understanding and to remember i've divided this into 4 steps.  I'll try to concise it as well.
To edit files i've used gedit instead of nano editor.

1. Create & Update Conf file for Apache:
Execute this command from your Shell to crate a new configuration file for thw sub-domain.
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/t7610.local.conf

After copying the default conf file we need to edit this conf file with this command
sudo gedit /etc/apache2/sites-available/t7610.local.conf
Add the necessary configuration lines inside this file.

At the end it should look like 
-------------------
<VirtualHost *:80>
ServerAdmin myemail@gmail.com
ServerName t7610.local
DocumentRoot /home/nirmalya/Public/t7610.local

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
-------------------

2. Symlink the conf file for Apache:
Now i'll create a symlink to t7610.local.conf file by executing command like this 
sudo a2ensite t7610.local.conf
or
sudo ln -s /etc/apache2/sites-available/t7610.local.conf /etc/apache2/sites-enabled/t7610.local.conf

3. Update in hosts file:
Update the hosts file with the new domain entry
So execute this command from your Shell
sudo gedit /etc/hosts/
 and add the line below at the end of the file
127.0.0.1 t7610.local
 Considering that 172.0.0.1 is your local IP Address.

4. Restart Apache:
Never ever forget to Re-start the Apache web server ;)
So, please execute this Shell command
sudo service apache2 restart 

Now in your browser type http://t7610.local/  and your website will now available in this sub-domain.

Saturday, July 2, 2016

NGINX configuration for a single domain for two different ports and map url to a port.

We can easily configure Apache or NGINX server with specific port(s) to a domain or url.
In this section i would like to share how to configure NGINX web server with two different ports for a domain and then map one url to a specific port.
This way we are also forwarding the a http request to another port.
To clarify myself in easy way let me to define the task like below.

Say, port 8080 will server all the requests to the domain where API (could be REST) related requests will be served via port 8888.
So it becomes like this -
http://localsite.dev:8080 should be the normal site and
http://localsite.dev:8888/myapi/myapi_key should serve the API related requests.

To implement the task above i had configured my Ubuntu 14.04 with PHP 5.9.x, NGINX, php5fpm, ....

server {
        listen 8080;
        root /usr/share/nginx/html/localsite.dev/index.php;
        index index.php index.html index.htm;
        server_name localsite.dev;
        location ^~ /myapi {
             deny all;
        }
        location / {
            try_files $uri $uri/ /index.php;
       }
       location ~ \.php$ {
           try_files $uri =404;
           fastcgi_pass unix:/var/run/php5fpm.
           sock;
           fastcgi_index index.php;
           include fastcgi_params;
     }
}
server {
        listen 8888;
        root /usr/share/nginx/html/localsite.dev/index.php;
        index index.php index.html index.htm;
        server_name localsite.dev;
        location /myapi {
             allow all;
        }
        location / {
             deny all;
       }
      location ~ \.php$ {
           try_files $uri =404;
           fastcgi_pass unix:/var/run/php5fpm.
           sock;
           fastcgi_index index.php;
           include fastcgi_params;
     }
}

Saturday, April 16, 2016

TYPO3 AJAX Example for Backend Extension Module (Extbase/ Fluid)

In our previous posts we've already became familiar with AJAX usage for Frontend Extensions. Here we'll go through with an example of AJAX usage for Backend Extension.
Handsontable (https://handsontable.com/) has been integrated with its free version to make this extension more attractive.
I've shared a screen and that is describing the output of the extension.

Output Screen of Backend AJAX Example Extension Module

All Frontend users from fe_users table has been listed here. JSON data has been manipulated by Handontable view helper to display in editable Excel like spread sheet. But username data has been set as read-only.
TYPO3 version 7.6.0  and Extbase Framework for Extensions version 7.6.0 and Fluid Templating Engine version 7.6.0 has been used as development environment.
You can download and  install this extension from GitHub. Link is here
https://github.com/nirmalyamondal/TYPO3-Extensions/tree/master/backend_ajax

You are most welcome with queries or projects related to this.

Tuesday, April 5, 2016

Google Route Map with auto detection of current location to predefined destinations.

TYPO3 extension "googleroutemap" is to integrate Google Map into your website. It'll locate the current user's location automatically. It'll also has some predefined destinations. These destinations are records from database table 'tx_googleroutemap_domain_model_routemap' from Backend. It's tested with version 7.6.0.
Google Route Map is a very small extension with good example. Please check the screenshot below.

Google Route Map

Source code is available at https://github.com/nirmalyamondal/TYPO3-Extensions/tree/master/googleroutemap

Thursday, February 11, 2016

TYPO3 content sharing in Facebook, Twitter and Google+.

Here this extension "typo3_socialshareprivacy" will show an !dea to share page contents in various social media. This extension runs successfully on 6.2 to 7.6.0. The development version was 7.6.0
Output of typo3_socialshareprivacy plugin.
The way i have adopted to do this sharing task can be doable in lower versions of TYPO3 with a little structural modification.
There is no php code logics inside this plugin but some Typoscript setup along with some javascript code. This extensions don't have any dependency or reverse but jQuery Library is needed.
Please update the Facebook application id here in typo3_socialshareprivacy\Resources\Public\jscript\typo3_socialshareprivacy_en.js at the very first line.
# var global_facebook_appid    = 587977977907178;    //Set Your facebook Apps Id


There is a checkbox that will appear in the last TAB of every TYPO3 content with a label "Share in Social Media". Default value is un-checked i.e. if you want this content to be shared in social media please don't forget to check this checkbox.
The output will look like this
We can found this plugin at https://github.com/nirmalyamondal/TYPO3-Extensions/tree/master/typo3_socialshareprivacy
Believe this example will become helpful.