Tuesday, June 1, 2010

Symfony Tips (part2)

1. Error 500
http://symfony-check.org/

throw new sfException('Testing the 500 error'); 

http://www.symfony-project.org/gentle-introduction/1_4/en/19-Mastering-Symfony-s-Configuration-Files#chapter_19_sub_default_modules_and_actions

symfony 1.2-
web/errors/error500.php

symfony 1.2+
config/error/error.html.php
config/error/unavilable.php


In application settings.yml
set check_lock to true

2. Session name

# ProjectName/apps/appName/config/factories.yml
  storage:
    class: MysqlSession
    param:
        session_name: xxxsession
        db_table: session
        database: uxsession


http://www.symfony-project.org/reference/1_4/en/07-Databases
symfony use databases.yml to determine the connection settings (host, database name, user, and password)

# ProjectName/config/database.yml

all:
 
xxxsession:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://xxxxxxx


Problem:
Fatal error: Class 'sfPropelDatabase' not found in /root/workspace/ProjectName/cache/appName/dev/config/config_databases.yml.php on line 6

From doctrine to Prople
http://stackoverflow.com/questions/1835676/switch-symfony-1-4-from-doctrene-to-propel

#ProjectName/config/ProjectConfiguration.class.php

public function setup()
{
//    $this->enablePlugins('sfDoctrinePlugin');
      $this->enablePlugins('sfPropelPlugin');
}


Problem:
Fatal error: Declaration of MysqlSession::sessionWrite() must be compatible with that of sfDatabaseSessionStorage::sessionWrite() in /root/workspace/ProjectName/lib/symfony/MysqlSession.class.php on line 2


#ProjectName/lib/symfony/MysqlSession.class.php
public function sessionWrite($id, &$data) //reference parameter


Problem:
Unable to open PDO connection [wrapped: SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)]



3. Incomplete Object

Fatal error: xxx_xxxActions::executeGroup() : The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition XXXXXXX of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition in /root/workspace/xxxx/actions/actions.class.php on line 40

Add the XXXXXXX object into the config.php

require_once('xxxxxx/service/xxxx/XXXXXXX.php');

4. Symfony cc
Different environment, index_dev.php works, index.php not.
Try to symfony10 cc, command not found;
Use ./symfony cc

Thursday, May 27, 2010

Symfony: Mailer

In action

$message = $this->getMailer()->compose(
    array('your@email.com'=>'Your Name'),
    'otheremail@email.com',
    'Subject',
    'Body'
);
$this->getMailer()->send($message);


factories.yml

dev:
  mailer:
     class: sfMailer
     param:
       logging:           %SF_LOGGING_ENABLED%
       charset:           %SF_CHARSET%
       delivery_strategy: realtime
       transport:
         class: Swift_SmtpTransport
         param:
           host:       localhost
           port:       25
           encryption: ~
           username:   ~
           password:   ~

Tuesday, May 25, 2010

YUI: Customize YUI

Building Your Own Widget Library with YUI
http://yuiblog.com/blog/2008/06/24/buildingwidgets/

Customizing Existing YUI Component

YAHOO.namespace static function to create an object space for our own library

YAHOO.namespace('SATYAM');  // create a property SATYAM under YAHOO


Define Constructor

YAHOO.SATYAM.LoadingPanel = function(id) {

  YAHOO.SATYAM.LoadingPanel.superclass.constructor.call(this,
    id || YAHOO.util.Dom.generateId() ,
    {
       width: "100px",
       fixedcenter: true,
       constraintoviewport: true,
       underlay: "shadow",
       close: false,
       visible: false,
       draggable: true
    }
  );

  this.setHeader("Loading ...");
  this.setBody('');
  YAHOO.util.Dom.setStyle(this.body, 'textAlign', 'center');
  this.render(document.body);
};


Use YAHOO.lang.extend
superclass is part of the inheritance mechanism provided by YUI’s extend method. After you declare the constructor for your new object, you call extend:

YAHOO.lang.extend(YAHOO.SATYAM.LoadingPanel, YAHOO.widget.Panel);

The constructor itself does not get executed immediately. The extend function does get executed immediately.

We use method call of JavaScript native Function object, which takes the first argument as the execution scope of the function called and passes it the rest of the arguments.

To Use the object we just created

if (!loadingPanel2) {
   loadingPanel2 = new YAHOO.SATYAM.LoadingPanel();
}
loadingPanel2.show();


Puts all the code within an anonymous function, which gets immediately executed (notice the empty parenthesis at the end)

YAHOO.namespace('SATYAM');
(function(){
    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Panel = YAHOO.widget.Panel;

 // here goes the library contents itself
 // constructor
 // extend component
})();
YAHOO.register('SATYAM.LoadingPanel', YAHOO.SATYAM.LoadingPanel, {version: "0.99", build: '11'});

After we declare the instance of the YUI Loader that we will use, we call method addModule providing the information about our library file

var loader = new YAHOO.util.YUILoader();

loader.addModule({
   name: 'SATYAM.LoadingPanel',
   type: 'js',
   requires: ['container'],
   fullpath: 'LoadingPanel.js'
});

loader.require('reset', 'grids', 'base', 'SATYAM.LoadingPanel');






Thursday, May 20, 2010

YUI: Drag & Drop

YUI 2: Drag & Drop
http://developer.yahoo.com/yui/dragdrop/

var dd1 = new YAHOO.util.DD("element1");
var dd2 = new YAHOO.util.DDProxy("element2"); //proxy element during movement
var dd3 = new YAHOO.util.DDTarget("element3"); //target for drag & drop interaction


Drag & Drop Manager
YAHOO.util.DragDropMgr (or alias YAHOO.util.DDM)

//sets the time delay between a mousedown and a
//drag event to 1200 milliseconds:
YAHOO.util.DragDropMgr.clickTimeThresh = 1200;


Interaction Groups
Each Drag and Drop object belongs to one or more interaction groups. Drag and Drop events fire only when the dragged element interacts with other objects that with which it shares a group membership. If no group is specified in the constructor, an object belongs to the "default" group

// No group specified so dd0 is assigned to the "default" group
var dd0 = new YAHOO.util.DD("elementid0");
// dd1 is a member of group1
var dd1 = new YAHOO.util.DD("elementid1", "group1");
// dd2 is a member of group2
var dd2 = new YAHOO.util.DD("elementid2", "group2");
// dd3 is a member of both group1 and group2
var dd3 = new YAHOO.util.DD("elementid3", "group1");
dd3.addToGroup("group2");
//groups can be removed via script as well:
dd1.removeFromGroup("group1");


Interesting Moments & Custom Events

var dd = new YAHOO.util.DD('demo');
dd.on('dragEvent', function(ev) {
YAHOO.log('Element is being dragged.');
}, dd, true);






Wednesday, May 19, 2010

Javascript Tips - Part2

1. Declare Function
http://www.permadi.com/tutorial/jsFunc/index.html
functionName([parameters]){functionBody};

function add(a, b)
{
    return a+b;
}

assign a variable to an unnamed function: consider the function as an object

var add = function(a, b)
{
    return a+b;
}
var add=function theAdd(a, b)
{
    return a+b;
}
alert(add(1,2)); // produces 3
alert(theAdd(1,2)); // also produces 3

Useful in object oriented program, we can have a function be a property of an object

var myObject=new Object();
myObject.add=function(a,b){return a+b};
// myObject now has a property/a method named "add"
// and I can use it like below
myObject.add(1, 2);


When we declare a function, JavaScript actually creates an object;
We can add properties to Objects, including function objects.

function Ball()     // it may seem odd, but declaration
{                   // creates an object named Ball, and you can
}                   // refer to it or add properties to it like below
Ball.callsign="The Ball"; // add property to Ball
alert(Ball.callsign); // produces "The Ball"

Since function is an object, we can assign a pointer to a function

function myFunction(message)
{
    alert(message);
}
var ptr=myFunction; // ptr points to myFunction
ptr("hello"); // executes myFunction which will prints "hello"


2. Function as Data Type and Function Constructor
http://www.permadi.com/tutorial/jsFunc/index2.html

By declaring a function, we have also created a new data type

function Ball(message)
{
    alert(message);
}
var ball0=new Ball("creating new Ball"); // creates object &
                                         // prints the message
ball0.name="ball-0"; // ball0 now has a "name" property
alert(ball0.name); // prints "ball-0"

The red portion as a shortcut for doing below

function Ball(message)
{
    alert(message);
}
var ball0=new Object();
ball0.construct=Ball;
ball0.construct("creating new ball"); // executes ball0.Ball("creating..");
ball0.name="ball-0";
alert(ball0.name);


Constructor function

function Ball(message, specifiedName)
{
    alert(message);
    this.name=specifiedName;
}
var ball0=new Ball("creating new Ball", "Soccer Ball");
alert(ball0.name); // prints "Soccer Ball"


The "new" keyword eventually causes the constructor function to be executed. In this case, it will executel Ball("creating new Ball", "Soccer Ball"); and the
keyword this will refer to ball0.
Therefore, the line: this.name=specifiedName becomes ball0.name="Soccer Ball".

Every constructor function has a property named prototype.
You do not need to explicitly declare a prototype property, because it exists on every constructor function.

function Test()
{
}
alert(Test.prototype); // prints "Object"


Prototype is an object
when an object is created, the constructor function assigns its prototype property to the internal __proto__ property of the new object.

function Fish(name, color)
{
this.name=name;
this.color=color;
}
Fish.prototype.livesIn="water";
Fish.prototype.price=20;


You can use prototype to assign functions that are common on all objects

function Employee(name, salary)
{
this.name=name;
this.salary=salary;
}
Employee.prototype.getSalary=function getSalaryFunction()
{
return this.salary;
}
Employee.prototype.addSalary=function addSalaryFunction(addition)
{
this.salary=this.salary+addition;
}



Symfony Tips

1. Add Timer (symfony 1.0)

/**** init timer *****/
$timer = sfTimerManager::getTimer('myTimer');
/**********/


/**** display timer *****/
$timer->addTime();
$elapsedTime = $timer->getElapsedTime();
echo $elapsedTime;
die();
/**********/


2. Unit Test (symfony 1.4)
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/08
Create test.php file under ProjectName/test/unit/test

// test/unit/JobeetTest.php
require_once dirname(__FILE__).'/../bootstrap/unit.php';

$t = new lime_test(1);
$t->pass('This test always passes.');


To launch the test
$ php test/unit/test.php

Sample

require_once dirname(__FILE__).'/../bootstrap/unit.php';
$t = new lime_test(6); // display 1..6

$t->comment('::slugify()'); // display #::slugify()
$t->is(Jobeet::slugify('Sensio'), 'sensio', '::slugify() converts all characters to lower case'); // display ok 1 - ::slugify() converts all ...


3. User Flash (symfony 1.4)
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/13
A flash is an ephemeral message stored in the user session that will be automatically deleted after the very next request. It is very useful when you need to display a message to the user after a redirect.

setFlash(): The first argument is the identifier of the flash and the second one is the message to display. You can define whatever flashes you want, but notice and error are two of the more common ones.
// apps/frontend/modules/job/actions/actions.class.php
public function executeExtend(sfWebRequest $request)
{
    $request->checkCSRFProtection();

    $job = $this->getRoute()->getObject();
    $this->forward404Unless($job->extend());

    $this->getUser()->setFlash('notice', sprintf('Your job validity has been extended until %s.', $job->getDateTimeObject('expires_at')->format('m/d/Y')));

    $this->redirect($this->generateUrl('job_show_user', $job));
}

Include the flash message in the templates
// apps/frontend/templates/layout.php
<?php if ($sf_user->hasFlash('notice')): ?>
  <div class="flash_notice"><?php echo $sf_user->getFlash('notice') ?></div>
<?php endif ?>
 
<?php if ($sf_user->hasFlash('error')): ?>
  <div class="flash_error"><?php echo $sf_user->getFlash('error') ?></div>
<?php endif ?>


4. User Attribute (symfony 1.4)
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/13
getAttribute(), setAttribute()

// apps/frontend/modules/job/actions/actions.class.php
class jobActions extends sfActions
{
    public function executeShow(sfWebRequest $request)
    {
    $this->job = $this->getRoute()->getObject();

    // fetch jobs already stored in the job history
    $jobs = $this->getUser()->getAttribute('job_history', array());

    // add the current job at the beginning of the array
    array_unshift($jobs, $this->job->getId());

    // store the new job history back into the session
    $this->getUser()->setAttribute('job_history', $jobs);
    }
}

myUser class
The myUser class overrides the default symfony base sfUser class with application specific behaviors

// apps/frontend/modules/job/actions/actions.class.php
class jobActions extends sfActions
{
    public function executeShow(sfWebRequest $request)
    {
    $this->job = $this->getRoute()->getObject();

    $this->getUser()->addJobToHistory($this->job);
    }
}
// apps/frontend/lib/myUser.class.php
class myUser extends sfBasicSecurityUser
{
    public function addJobToHistory(JobeetJob $job)
    {
    $ids = $this->getAttribute('job_history', array());

    if (!in_array($job->getId(), $ids))
    {
        array_unshift($ids, $job->getId());
        $this->setAttribute('job_history', array_slice($ids, 0, 3));
    }
    }
}

remove attribute
User's attributes are managed by an object of class sfParameterHolder. The getAttribute() and setAttribute() methods are proxy methods for getParameterHolder()->get() and getParameterHolder()->set().

// apps/frontend/lib/myUser.class.php
class myUser extends sfBasicSecurityUser
{
    public function resetJobHistory()
    {
        $this->getAttributeHolder()->remove('job_history');
    }
}



5. i18n and l10n (symfony 1.4)
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/19
User Culture
The language French is ‘fr’, English is ‘en’; the country Canada is ‘CA’, United States is ‘US’; the culture for a user speaking French from Canada is ‘fr_CA’
setCulture()and getCulture()

// in an action
$this->getUser()->setCulture('fr_BE');
echo $this->getUser()->getCulture();

The preferred user culture can be configured in the settings.yml configuration file

#apps/frontend/config/settings.yml
all:
    .settings:
       default_culture: en_CA

Internationalization
set i18n setting to true in settings.yml

# apps/frontend/config/settings.yml
all:
   .settings:
       charset: utf-8
       i18n: true

The I18N helper group is not loaded by default, you need to either manually add itin each template with use_helper(‘I18N’) or load it globally by adding to the standard_helpers setting

# apps/frontend/config/settings.yml
all:
   .settings:
      standard_helpers: [Partial, Cache, I18N]

Sample template of how to use the __() helper

    // apps/frontend/templates/layout.php

      <a href=""><?php echo __('About Jobeet') ?></a>

      <?php echo link_to(__('Full feed'), 'job', array('sf_format' => 'atom')) ?>

    Create catalogue using i18n:extract

    $ php symfony i18n:extract frontend fr --auto-save

    Each translation is managed by a trans-unit tag which has a unique id attribute. A lot of tools exist to ease the translation process. (check out Open Language Tools https://open-language-tools.dev.java.net/)

    <!-- apps/frontend/i18n/fr/messages.xml -->

    <xliff version="1.0">
      <file source-language="EN" target-language="fr" datatype="plaintext"
          original="messages" date="2008-12-14T12:11:22Z"
          product-name="messages">
        <header/>
        <body>
          <trans-unit id="1">
            <source>About Jobeet</source>
            <target>A propos de Jobeet</target>
          </trans-unit>
          <trans-unit id="2">
            <source>Feed</source>
            <target>Fil RSS</target>
          </trans-unit>
        </body>
      </file>
    </xliff>

    How to use format_date
    sfDateFormat::getPattern()
    http://fellipeeduardo.com/blog/symfony-helper-format_date-how-to-use/en/

    6. autoload.yml (symfony 1.4)
    http://www.symfony-project.org/reference/1_4/en/14-Other-Configuration-Files
    The autoload.yml configuration determines which directories need to be autoloaded by symfony

    7. Authentication (symfony 1.4)
    entire application require the user to be authenticated

    # apps/backend/config/security.yml
    default:
       is_secure: true

    when an un-authenticated user tries to access a secured action, symfony forwards the request to the login action

    # apps/backend/config/setting.yml
    all:

      .actions:
         login_module: default
         login_action: login


    By default, the myUser class extends sfBasicSecurityUser, and not sfUser. sfBasicSecurityUser provides additional methods to manage user authentication and authorization.

    To manage user authentication, use the isAuthenticated() and setAuthenticated() methods:

    if (!$this->getUser()->isAuthenticated())
    {
        $this->getUser()->setAuthenticated(true);
    }


    8. Basic File Structure (1.2)
    http://www.symfony-project.org/book/1_2/19-Mastering-Symfony-s-Configuration-Files

    sf_root_dir # myproject/
    sf_apps_dir # apps/
    sf_app_dir # frontend/
    sf_app_config_dir # config/
    sf_app_i18n_dir # i18n/
    sf_app_lib_dir # lib/
    sf_app_module_dir # modules/
    sf_app_template_dir # templates/
    sf_cache_dir # cache/
    sf_app_base_cache_dir # frontend/
    sf_app_cache_dir # prod/
    sf_template_cache_dir # templates/
    sf_i18n_cache_dir # i18n/
    sf_config_cache_dir # config/
    sf_test_cache_dir # test/
    sf_module_cache_dir # modules/
    sf_config_dir # config/
    sf_data_dir # data/
    sf_doc_dir # doc/
    sf_lib_dir # lib/
    sf_log_dir # log/
    sf_test_dir # test/
    sf_plugins_dir # plugins/
    sf_web_dir # web/
    sf_upload_dir # uploads/


    9. Use Helper in Action
    http://snippets.symfony-project.org/snippet/69
    In PrjectConfiguration file

    # ProjectName/config/ProjectConfiguration.class.php
    include_once('/opt/symfony/symfony14/lib/helper/DateHelper.php');

    In Action
    format_date(time(), 'D', 'fr');

    Format
    http://trac.symfony-project.org/wiki/formatDateHowTo

    JavaScript Tips - Part1

    1. Change ClassName

    document.getElementById(element).setAttribute('class', 'className');
    or document.getElementById(element).className = 'className';
    or using YUI
    YAHOO.util.Dom.getElementByClassName(className, tagName, rootNode);
    YAHOO.util.Dom.hasClass(element, className);
    YAHOO.util.Dom.addClass(element, className);
    YAHOO.util.Dom.replaceClass(element, oldClassName, newClassName);


    2. ParseAjaxResult

    function ajaxCall(id) {
        var displayResult = {
                success: function(o) {
                    var response = parseAJAXResult(o);
                    var elem = document.getElementById('div_id');
                    elem.innerHTML = response.result;
                },
                failure: generalAjaxFailure
            }   
            var params = 'id='+id;
            YAHOO.util.Connect.asyncRequest('POST', '<?php echo url_for('module/action')?>', displayResult , params);  
    }


    3. Ajax Form

    YAHOO.util.Connect.setForm(document.getElementById(form_id));
    document.search_transaction = YAHOO.util.Connect.asyncRequest('POST',
       '<?php echo url_for('module/action')?>',
       { success: successComplete, failure: generalAjaxFailure });

    Make sure the hidden field has name, otherwise setForm won't pick it up.
    <input type="hidden" id="selected_ids" name="selected_ids">

    4. String Functions
    http://www.w3schools.com/jsref/jsref_obj_string.asp

    if(resultVal.indexOf("keyword") != -1) { // contain keyword ... }
    function ucfirst(str) {   // capitalize first letter
        var firstLetter = str.substr(0, 1);
        return firstLetter.toUpperCase() + str.substr(1);
    }


    5. Check if variable exists
    if ( typeof (variableName) == "undefined" ) {
    } else {
    }


    6. Create Elements 
    var body = document.createElement('form');
    body.id = 'elem_id';
       var row1 = document.createElement('div');
       row1.className = 'formRow';
       row1.innerHTML = '<label for="cell_value">Enter a new value: </label>';
       // Input Text           
      var elTextbox = row1.appendChild(document.createElement("input"));
      elTextbox.id = "cell_value";
      elTextbox.name = "cell_value";
      elTextbox.type = "text";
      elTextbox.style.width = "130px";
      elTextbox.style.margin= "0 10px 0 0";           
      Event.addListener(elTextbox, "keydown", function(oArgs){ if(enterDown(oArgs)) { this.cellEditorAction(prod_id, column_key, 'newValue'); }}, this, true);
                   
      // Save button
     var elSaveBtn = row1.appendChild(document.createElement("button"));
     elSaveBtn.className = DT.CLASS_DEFAULT;
     elSaveBtn.innerHTML = this.LABEL_SAVE || DT.LABEL_SAVE;
      Event.addListener(elSaveBtn, "click", function(oArgs){ this.cellEditorAction(prod_id, column_key, 'newValue');}, this, true);


    body.appendChild(row1);
    panel.setBody(body);
    panel.render();
    panel.show();
                    


    7. Reload Page
    window.location.reload()

    8. Window onload
    YAHOO.util.Event.on(window, 'load', function () {
        if(window.parent.location.href != window.location.href) {
            window.parent.location.href = '<?php url_for('public/index') ?>';
        }
        document.getElementById('username').focus();
    });


    or

    window.onload = funcName;
    function funcName() {
    }

    Loading Sequence

    #js
    window.onload = getRight_onload; // IE doesn't take function() Error: Not implemented

    function getRight_onload() {
       getRight();
    }
    function getRight() {
       var displayData = {
          success: function(request) {
             document.getElementById('right_div').innerHTML = request.responseText;
          },
          failure: ajaxFailure
      }
       var params = 'column='+ column;
       YAHOO.util.Connect.asyncRequest('POST', url, displayData, params);
    }