Thursday, January 21, 2016

Using multiple databases with Symfony2 and Doctrine2

I was looking for documentation on how to use multiple databases with Symfony and all the results were talking about having 2 connections with 2 entity managers and adding mappings for each bundle ...too complicated for a simple thing.

But I kept on searching and I found this article:  https://techpunch.co.uk/development/using-multiple-databases-with-symfony2-and-doctrine2  which is saying:

"
You will need to use only connection that spans all of your databases, if you want to build a relationship between entities then they must use the same connection. Do to this you will need a user that has access to all of the databases the you wish to access. Setup this user as per usual within your Symfony2 application, for the database name just select one of the databases, it doesn't matter which one.
No extra Doctrine config is needed to get this working, ....

The key to getting multiple databases to work is within your entity classes, you need to specify the table name of the entity with a prefix of the name of the database to which the table belongs. Here is an example using annotations:

<?php
namespace Demo\UserBundle\Entity;

use DoctrineORMMapping as ORM;

/**
 * Demo\UserBundle\Entity\User
 *
 * @ORMTable(name="users.User")
 */
class User implements
{
  /* ... */

"
I tried this solution on my project and worked fine.

You may want to look also at Doctrine's  Master-Slave Connection:  http://blog.alejandrocelaya.com/2014/04/18/configure-multiple-database-connections-in-doctrine-with-zend-framework-2-2/

Monday, January 18, 2016

Useful JavaScript libraries

Below are some JS libraries I used and they work :) :

1. Sending AJAX form with attachments (which works on IE9 )


I found this JQuery pugin  http://malsup.com/jquery/form/ with decent documentation which meet the requirements.


Quick Start Guide

1. Add a form to your page. Just a normal form, no special markup required: 
<form id="myForm" action="comment.php" method="post"> 
    Name: <input type="text" name="name" /> 
    Comment: <textarea name="comment"></textarea> 
    <input type="submit" value="Submit Comment" /> 
</form>
 
2. Include jQuery and the Form Plugin external script files and a short script to initialize the form when the DOM is ready: 
<html> 
<head> 
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> 
    <script src="http://malsup.github.com/jquery.form.js"></script> 
 
    <script> 
        // wait for the DOM to be loaded 
        $(document).ready(function() { 
            // bind 'myForm' and provide a simple callback function 
            $('#myForm').ajaxForm(function() { 
                alert("Thank you for your comment!"); 
            }); 
        }); 
    </script> 
</head> 

2. Date picker with options (which works on IE9 )

The answer is Datepicker from JQuery UI: https://jqueryui.com/datepicker/
You may want to stop the user to insert data directly in the input field manually, this can be archived by setting 'readonly' parameter to 'true'. The problem is that the field looks disabled all the time, you may encounter some users thinking that they should not click on that input field.
Solution: make the input field readonly when the user clicks on it and after closing the Datepicker the input field will be made again writable ('readonly' set to 'false').

 beforeShow: function(input, inst) {
                             $(input).attr('readonly', true);
 },
 onClose: function(dateText, inst) {
                        $(this).attr('readonly', false);

 }


3. HTML 5 Placeholder working on  IE9 (make sure not to send default values when submitting the form)


https://github.com/parndt/jquery-html5-placeholder-shim

Usage

Just include the jquery.html-placeholder-shim.js script into your document head like so:
<head>
  <script type='text/javascript' src='jquery.js'></script>
  <script type='text/javascript' src='jquery.html5-placeholder-shim.js'></script>
</head>
The script will automatically execute itself on the $(document).ready event and can be re-executed at any time (for example, to add placeholders to text boxes created during dynamic changes to the page) by running $.placeholder.shim();.

HTML5 placeholder Example:

<input type="search" placeholder="search the internets" name="query" />

4. Searchable Drop down list

 http://harvesthq.github.io/chosen/
Also Bootstrap theme for Chosen:  https://github.com/dbtek/chosen-bootstrap


If you form is dynamically loaded you can use it like this:

<script>
        $( document ).ajaxComplete(function() {
            $.placeholder.shim();
            $("#select_input").chosen();
        });
  </script>



Monday, January 11, 2016

CPANAGeneratorBundle

I was looking for a CRUD generator able to do more than the one from Sensio Labs, this is how I found PUGXGeneratorBundle.

PUGXGeneratorBundle is extending SensioGeneratorBundle and very important has decent documentation. Some of the  functionalities I like from it:
  • support for form themes (customizable)
  • default templates suitable with Boostrap and Font Awesome
  • nice "check" icons for boolean fields (when using Font Awesome)
  • support for pagination (requires KnpPaginatorBundle)
  • support for filters (requires LexikFormFilterBundle)
  • support for sorting 
Of course I wanted something more so I made my own flavor of CRUD Generator.

CPANAGeneratorBundle adds to the Show view of an entity the associated objects from Bidirectional relations.
Example: there are 2 entities: Author and Book found in One-to-Many BIDIRECTIONAL relation. In 'Author' entity there is a property called 'books' of type ArrayCollection. In the author/show view after the fields related to Author there will be listed the Books associated. Also CPANAGeneratorBundle is adding buttons for Add book, view and edit.
Author
Last name: Herbert
First name: Frank
Nationality: American
Id: 1
Books
Add book
Title: Dune Chronicles
Genre : Science Fiction
Id:1
view edit
Title: Dune Mesiah
Genre: Science Fiction
Id: 2
view edit

You can find it on Github:  https://github.com/cristianpana86/GeneratorBundle
and on Packagist for installing via Composer:  https://packagist.org/packages/cpana/generator-bundle

Friday, January 8, 2016

Symfony custom constaint: check total size of several form attachements


The cookbook link on how to create a custom constraint is this one:
http://symfony.com/doc/master/cookbook/validation/custom_constraint.html


Request: total size of form attachments should not be bigger than a given value.

Implementation:

I've created a directory 'Validator' under my Bundle where I added two classes:
- FilesTotalSize which extends class Constaint
- FilesTotalSizeValidator extends ConstaintValidator

FilesTotalSize:


<?php
namespace Bundle\Validator;

use Symfony\Component\Validator\Constraint;

/** @Annotation */
class FilesTotalSize extends Constraint
{
    public $message;
   
    public function validatedBy()
    {
        return get_class($this).'Validator';
    }

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }
}


The name of the Validation class will be constraint class concatenated with 'Validator';

Because this constraint is checking values from several fields is considered a class validation (as opposite to field validation which can be seen in the documentation examples ).
For this reason getTargets will return CLASS_CONSTRAINT.

The actual check of the condition is made in the validator class. The variable '$value' will give access to the object to be validated. 'attachement1', 'attachement2' and 'attachement3' are the names of the fields declared in the Entity used for file uploading (file). The size is expressed in bytes, so for 3MB I have 3 millions of bytes. The method  'addViolation' receive as parameter the error message to be displayed.
.
FilesTotalSizeValidator:

<?php
namespace  Bundle\Validator;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;


class FilesTotalSizeValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        $size_att1=0;
        $size_att2=0;
        $size_att3=0;
       
        if (property_exists($value, 'attachement1')){
            if(!is_null($value->getAttachement1())){
                $size_att1= $value->getAttachement1()->getClientSize();
            }
        }
       
        if (property_exists($value, 'attachement2')){
            if(!is_null($value->getAttachement2())){
                $size_att2= $value->getAttachement2()->getClientSize();
            }
        }
       
        if (property_exists($value, 'attachement3')){
            if(!is_null($value->getAttachement3())){
                $size_att3= $value->getAttachement3()->getClientSize();
            }
        }
       
        $totalSize=0;
        $totalSize=(int)$size_att1 +(int)$size_att2 +(int)$size_att3;

        if ($totalSize > 3145728) {  //check if total size of files is bigger than 3MB
            $this->context->addViolation('Maximum size is 3MB!');
        }
    }
}



Usage:

In the entity class:

use MyBundle\Validator\FilesTotalSize;

/**
 * @ORM\Entity
 * @FilesTotalSize
 */


class EntityName {

Doctrine Single Table Inheritance

I have a request to develop 3 forms to collect information from users. They share some  of the information like: name, address, dateamount and some fields are different, each form will have some attachments (3 or 2) which represent different types of documents. More than that on the 'amount ' field there are different validations to make, depending on which form is applied.

How should I implement this? After some research the Doctrine Single Table Inheritance seems to be the answer:

Official documentation: http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html
Useful blog: https://blog.liip.ch/archive/2012/03/27/table-inheritance-with-doctrine.html

Because the objects (corresponding to the forms) to be saved in the database have a lot in common  they can all be kept in just one table. The table needs to allow NULL for the fields which are not common for all forms.

In Symfony I will create a base entity class which will be extended by child entities (one child for each form). The base entity can be "abstract' as it is not supposed to be directly used (the child entity classes  will be used just as regular entities ).
Because I want to have different validation on the 'amount' field (and I want to keep them in  entity) I will move the 'amount' from the base class to child classes.
Also in the table there will be a column which will keep the type of the record (object typeA from formA, object typeB from formB, etc ). The equivalent of this column in Doctrine language is DiscriminatorColumn.

        @ORM\DiscriminatorColumn: indicates which column will be used as discriminator (i.e. to store the type of item). You don’t have to define this column in the entity, it will be automagically created by Doctrine.

Exaple:

Base entity class:


<?php

namespace Bundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Base entity class
 *
 * @ORM\Table(name="table")
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="refund_type", type="string")
 * @ORM\DiscriminatorMap( {"typeA_in_database" = "ChildEntityA", "
typeB_in_database" = "ChildEntityB" } )
 */
abstract class Base
{

 --------------------------------------
---------------------------------------
Child entity class

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use DDRCBundle\Validator\FilesTotalSize;

/**
 * @ORM\Entity
 * Child
 *
 */
class Child extends Base