martes, 30 de noviembre de 2010

Another Simple jQuery Plugin

Though it seem there is a jQuery plugin for every thing. I wanted to write my own to understand how plugins work.

While using Symfony I use jQuery to have master checkbox to select/deselect all the checkboxex in a table and add a class to the row depending on whether the row was even or odd.

The code in my indexSuccess.php looke like this

<script type="text/javascript">
$('input#masterCheck').click(function(){
var chks = $('td input[name^=ids]');
if($(this).is(':checked')){
chks.attr('checked', true)
}else{
chks.attr('checked', false)
}
}
);
$('tbody tr:even').addClass('even');
$('tbody tr:odd').addClass('odd');
</script>

There was nothing wrong with this code. But it had to be repeated in every single module. I wanted something a little more flexible so I went on and "pluginized" it.

Add a new javascript file named web/js/jquery-formattable.js (this path is for Symfony users, if you're not using Symfony you can put anywhere it's accessible) and type the following code:

jQuery.fn.formatTable = function(options){
settings = $.extend({
checkControlId : 'masterCheck',
childrenCheckSelector: 'input[name^=ids]'
}, options);
jQuery('input#' + settings.checkControlId, this).click(function(){
var chks = jQuery('td ' + settings.childrenCheckSelector);
if(jQuery(this).is(':checked')){
chks.attr('checked', true)
}else{
chks.attr('checked', false)
}
}
);
jQuery('tbody tr:even', this).addClass('even');
jQuery('tbody tr:odd', this).addClass('odd');
};

As you can see it is pretty much the same code except we declared a function formatTable and added some two default settings:

  • checkControlId: Is the id for the master checkbox control. The one when clicked will chech/uncheck the rest of the checkboxes in the table.
  • childrenCheckSelector: Is the CSS selector to find the checkboxes to change.

Now all you have to do is replace the first set of code with :

<script type="text/javascript">

$('table.datalist').formatTable();

</script>

Voilá!! It works!

lunes, 29 de noviembre de 2010

Implementing Ajax Pagination with Symfony

I wanted to use ajax to update the list generated in the indexSucces.php of a module.
After some research I found to great posts:
  1. jQuery DataTables and Symfony This post uses jQuery and Datatables to update a list. I took a look at the jQuery plugin Datatables and it looks great. But since I'm including actions in my tables and didn't know how to implement them on Datatables I went and look for something a bit more simple.
  2. Symfony Tips & Tricks IV: Generalized & Ajax Pagination This post extends the sfDoctrinePager to generate the pagination navigation. I'm unclear why to extend the sfDoctrinePager to do this, but since I'm new to Symfony I won't question the authors approach. What I did did was implement his pagination with jQuery but I included the sorting too.
  3. Symfony: How to render a partial from an action: What I was missing was a way to render the data in simple way without messing with JSON and building the tables with jQuery (wich is what Datatables does).
On a previous post Using Pagination with Symfony and Doctrine I blogged about pagination. So I decided to extend that example.

Creating an Ajax Pagination Control

Create a file named /myproject/apps/myapplication/templates/_ajax_pagination_control.php and copy the following code on it. Then save it.
<div class="pagination">
<a href="#" onclick="loadPage(1);">
<?php echo image_tag('/images/first.png', array('alt' => __('First page', array(), 'sf_admin'), 'title' => __('First page', array(), 'sf_admin'))) ?>
</a>
<a href="#" onclick="loadPage(<?php echo $pager->getPreviousPage() ?>);">
<?php echo image_tag('/images/previous.png', array('alt' => __('Previous page', array(), 'sf_admin'), 'title' => __('Previous page', array(), 'sf_admin'))) ?>
</a>

<?php foreach ($pager->getLinks() as $page): ?>
<?php if ($page == $pager->getPage()): ?>
<?php echo $page ?>
<?php else: ?>
<a href="#" onclick="loadPage(<?php echo $page ?>);"><?php echo $page ?></a>
<?php endif; ?>
<?php endforeach; ?>
<a href="#" onclick="loadPage(<?php echo $pager->getNextPage() ?>);">
<?php echo image_tag('/images/next.png', array('alt' => __('Next page', array(), 'sf_admin'), 'title' => __('Next page', array(), 'sf_admin'))) ?>
</a>
<a href="#" onclick="loadPage(<?php echo $pager->getLastPage() ?>);">
<?php echo image_tag('/images/last.png', array('alt' => __('Last page', array(), 'sf_admin'), 'title' => __('Last page', array(), 'sf_admin'))) ?>
</a>
</div>

Editing the Action


Open your actions.php file and change it to look like this:
   public function executeIndex(sfWebRequest $request) {
if ($request->getParameter('sort') && $this->isValidSortColumn(
$request->getParameter('sort'))) {
$this->setSort(array($request->getParameter('sort'),
$request->getParameter('sort_type')));
}

$items_x_page = sfConfig::get('app_max_items_x_page');
$this->pager = $this->getPager($request);
$this->sort = $this->getSort();
}

protected function getPager(sfWebRequest $request){
$items_x_page = sfConfig::get('app_max_items_x_page');
$pager = new sfDoctrinePager('RepairRequest', $items_x_page); // Table, items per page
$pager->setQuery($this->buildQuery());
$pager->setPage($request->getParameter('page', 1)); // actual page
$pager->init();
return $pager;
}
public function executeGetList(sfWebRequest $request) {
$pager = $this->getPager($request);
$sort = $this->getSort();
return $this->renderPartial('repairrequest/list',
array('pager' => $pager, 'sort' => $sort));
}
On line 15 change RepairRequest for your object and on line 24 change the partials path to yours.

Creating the List Partial


Create /myproject/apps/myapplication/modules/mymodule/templates/_list.php file with a code that looks like the following. You will have to adjust for your project.
<?php use_helper('I18N') ?>
<div id="loading"></div>
<table class="datalist">
<thead>
<tr>
<th><input type="checkbox" id="masterCheck"name="master" value="bar" /> </th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'id',
'fieldlabel' => 'Id', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'requestDate',
'fieldlabel' => 'Request Date', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'location',
'fieldlabel' => 'Location', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th><?php echo __('Description', array(), 'messages') ?></th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'rt.name',
'fieldlabel' => 'Repair Type', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'repair_status_id',
'fieldlabel' => 'Repair Status', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'real_state_id',
'fieldlabel' => 'Real State', 'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th><?php echo __('Updated at', array(), 'messages') ?></th>
<th><?php echo __('Actions', array(), 'messages') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($pager->getResults() as $i => $repair_request): ?>
<tr>
<td><?php include_partial('global/list_td_batch_actions', array('obj' => $repair_request)) ?></td>
<td><a href="<?php echo url_for('repairrequest/show?id=' . $repair_request->getId()) ?>">
<?php echo $repair_request->getId() ?></a></td>
<td><?php echo format_date($repair_request->getRequestDate(),
sfConfig::get('app_string_date_format')) ?>
</td>
<td><?php echo $repair_request->getLocation() ?></td>
<td><?php echo $repair_request->getDescription() ?></td>
<td><?php echo $repair_request->getRepairType() ?></td>
<td><?php echo $repair_request->getRepairStatus() ?></td>
<td><?php echo $repair_request->getRealState() ?></td>
<td class="long_date"><?php echo format_date($repair_request->getUpdatedAt(),
sfConfig::get('app_string_datetime_format')) ?></td>
<td>
<?php include_partial('global/list_td_actions', array('module'
=> 'repairrequest', 'obj' => $repair_request)) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr><td colspan="10">

<?php include_partial('global/page_numbers', array('pager' => $pager)) ?>
<?php include_partial('global/ajax_pagination_control', array('pager' => $pager, 'module' => 'repairrequest')) ?>
</td></tr>
</tfoot>
</table>
<script type="text/javascript">
$('input#masterCheck').click(function(){
var chks = $('td input[name^=ids]');
if($(this).is(':checked')){
chks.attr('checked', true)
}else{
chks.attr('checked', false)
}
}
);
$('tbody tr:even').addClass('even');
$('tbody tr:odd').addClass('odd');
</script>
This partial will be rendered by the ajax call to getList.
Open your /myproject/apps/myapplication/modules/mymodule/templates/indexSuccess.php .
<?php use_helper('I18N') ?>
<h1>Repair requests List</h1>
<form action="<?php echo url_for('repairrequest/batch') ?>" method="post">

<div id="data">
<?php include_partial('list', array('pager' => $pager, 'sort' => $sort)) ?>
</div>
<a href="<?php echo url_for('repairrequest/new') ?>">New</a>
<?php include_partial('list_batch_actions', array()) ?>
</form>

<script type="text/javascript">
// as we have the <div id="data"> we'll completely reload it's contents
var container = jQuery("#data");
$('#loading').hide();
// note that you'll need a routing for the offers index to point to module: offers, action: index..
var url = "<?php echo url_for("repairrequest/getList"); ?>";

function loadPage(page)
{
$.ajax({
url: url+"?page="+page,
type: 'POST',
dataType: 'html',
timeout: 4000,
beforeSend: function(){
$('#loading').show();
},
complete: function(){
$('#loading').hide();
},
error: function(xhr, textStatus, errorThrown){
msg = "Error " + errorThrown;
alert(msg);
},
success: function(data){
container.html(data);
}
});
}
</script>

Editing the CSS


To get a gif to show while the data is uploading you'll need an animated gif. You can create one online athttp://www.ajaxload.info/.
open your main.css file and add the following code:
#loading{
background: url(../images/ajax-loader_2.gif) no-repeat center;
position: relative;
top: 50%;
left: 50%;
height: 40px;
width: 40px
}

domingo, 21 de noviembre de 2010

Extracting modified files from a Subversion Project

Sometimes you work on a project but don´t want to commit the changes but also want to take the changes with you to another computer.
Here´s a little trick for linux and Mac. On a terminal move to your versioned project directory and type
svn status | grep ^[AM\?] | awk  '{print $2}' | zip ../backup_`date +"%Y%m%d_%H%M"` -@

This will zip all added (A), modified (M) and new (?) files to a file named backup_20101117.zip with the directory structure
To unzip it:
tar xvf /path/to/zip/backup_20101117.zip -C /path/to/project

If you´re using Windows…. Be afraid, be very afraid. Nah just kidding you can install Cygwin (http://www.cygwin.com ) and use this trick.

jueves, 11 de noviembre de 2010

Using Flash Messages in Symfony

Symfony has a very cool way to handle states. The traditional way would be to declare a variables in the session and then eliminate it. With flash messages you create them a they are dropped in the next request.
When you generate a module using the doctrine:generate-module task you don't get any message telling you the result of your saves.
We're going to show you how to add a message after a record was successfully saved.

Creating a Partial

First create a globlal partial at myproject/apps/myapplication/templates/_flahes.php with the following code:
<?php if ($sf_user->hasFlash('notice')): ?>
<div class="notice"><?php echo __($sf_user->getFlash('notice'),
array(), 'sf_admin') ?></div>
<?php endif; ?>

<?php if ($sf_user->hasFlash('error')): ?>
<div class="error"><?php echo __($sf_user->getFlash('error'),
array(), 'sf_admin') ?></div>
<?php endif; ?>

Editing the _form.php Partial

Open your myproject/apps/myapplication/modules/mymodule/templates/_form.php and add the partial and the i18n helper.
<?php use_helper('I18N') ?>
<?php use_stylesheets_for_form($form) ?>
<?php use_javascripts_for_form($form) ?>
<?php include_partial('global/flashes') ?>

Add the Flash Message in the Action

Open your myproject/apps/myapplication/modules/mymodule/actions/actions.class.php, find the processForm function and add the flash message as shown:

protected function processForm(sfWebRequest $request, sfForm $form) {
$form->bind($request->getParameter($form->getName()),
$request->getFiles($form->getName()));
if ($form->isValid()) {
$repair_request = $form->save();
$this->getUser()->setFlash('notice', 'The item was updated successfully.');
$this->redirect('repairrequest/edit?id=' . $repair_request->getId());
}
}

Styling the Message

Lets style the message open your main.css file and add the following:
.notice{
font: 11px/24px Verdana, Arial, Helvetica, sans-serif;
background: url(../images/ok.png) no-repeat 4px 4px;
margin: 0px 0px 0px 35px;
padding-left: 23px
}
You'll need an ok.png file to use as an icon.

lunes, 8 de noviembre de 2010

Sorting Lists in Symfony

On my previous post Using Pagination with Symfony and Doctrine I discussed how to implement pagination based what the admin generator created.

With sorting I did pretty much the same, looked around the cache to see what the generator did.

Creating the sortable_header Partial


Create a file named /myproject/apps/myapplication/templates/_sortable_header.php and copy the following code on it. Then save it.

<?php if ($fieldname == $sort[0]): ?>
<?php echo link_to(__($fieldlabel, array(), 'messages'), $routename,
array('query_string' => 'sort='. $fieldname .'&sort_type=' .
($sort[1] == 'asc' ? 'desc' : 'asc'))) ?>
<?php echo image_tag('/images/' .
$sort[1] . '.png', array('alt' => __($sort[1], array(), 'sf_admin'),
'title' => __($sort[1], array(), 'sf_admin'))) ?>
<?php else: ?>
<?php echo link_to(__($fieldlabel, array(), 'messages'), $routename,
array('query_string' => 'sort='. $fieldname .'&sort_type=asc')) ?>
<?php endif; ?>


This template receives 3 variables:
$fieldname: The name of the field as defined in the Object class.
$fieldlabel: The text you want to display in the header. It implements i18n so if your translate your site it will work.
$routename: Name of the route to generate the link.

You'll need to have the asc.png and desc.png on your /myproject/web/images directory in order to get the arrows.

Editing indexSuccess.php


Open your /myproject/apps/myapplication/modules/mymodule/templates/indexSuccess.php
Your column headers should look something like this:

<thead>
<tr>
<th>Id</th>
<th>Request date</th>
<th>Location</th>
<th>Description</th>
<th>Repair type</th>
<th>Repair status</th>
<th>Real state</th>
<th>Updated at</th>
<th>Updated by</th>
</tr>
</thead>

Choose which headers you want to be sortable. Your code should look something like this:
  <thead>
<tr>
<th>
<?php include_partial('global/sortable_header', array('fieldname'
=> 'id',
'fieldlabel' => 'Id' ,'routename' => '@repairrequest', 'sort'
=> $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname'
=> 'requestDate',
'fieldlabel' => 'Request Date' ,'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname'
=> 'location',
'fieldlabel' => 'Location' ,'routename' => '@repairrequest', 'sort'
=> $sort)) ?>
</th>
<th>Description</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname' => 'repair_type_id',
'fieldlabel' => 'Repair Type' ,'routename' => '@repairrequest', 'sort'
=> $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname'
=> 'repair_status_id',
'fieldlabel' => 'Repair Status' ,'routename' => '@repairrequest', 'sort' => $sort)) ?>
</th>
<th>
<?php include_partial('global/sortable_header', array('fieldname'
=> 'real_state_id',
'fieldlabel' => 'Real State' ,'routename' => '@repairrequest', 'sort'
=> $sort)) ?>
</th>
<th>Updated at</th>
<th>Updated by</th>
</tr>
</thead>


But there is a problem with this logic. For columns that are foreign keys it will only sort by the id. For example RepairRequest has a one to many relation with RepairType, so i can sort by foreign keys only, thats why I uses as $fieldname repair_request_id. What we actually want is to sort by the name of the RepairType.
I think I can fix this with a custom query on the action. I'll post the fix when I find it.
For now enjoy!!

domingo, 7 de noviembre de 2010

Using Pagination with Symfony and Doctrine

In order to understand how the Doctrine pager works, I created a admin module with the admin generator task and started snooping around the cache to see what it generated.

This is how I figured it out, may no be pretty but it works.

Create a Pagination Control


Create a file named /myproject/apps/myapplication/templates/_pagination_control.php and copy the following code on it. Then save it.

<div class="pagination">
<a href="<?php echo url_for($module) ?>?page=1">
<?php echo image_tag('/images/first.png', array('alt' =>
__('First page', array(), 'sf_admin'), 'title' =>
__('First page', array(), 'sf_admin'))) ?>
</a>

<a href="<?php echo url_for($module) ?>?page=
<?php echo $pager->getPreviousPage() ?>">
<?php echo image_tag('/images/previous.png', array('alt' =>
__('Previous page', array(), 'sf_admin'), 'title' =>
__('Previous page', array(), 'sf_admin'))) ?>
</a>

<?php foreach ($pager->getLinks() as $page): ?>
<?php if ($page == $pager->getPage()): ?>
<?php echo $page ?>
<?php else: ?>
<a href="<?php echo url_for($module) ?>?page=
<?php echo $page ?>"><?php echo $page ?></a>
<?php endif; ?>
<?php endforeach; ?>

<a href="<?php echo url_for($module) ?>?page=
<?php echo $pager->getNextPage() ?>">
<?php echo image_tag('/images/next.png', array('alt' =>
__('Next page', array(), 'sf_admin'), 'title' =>
__('Next page', array(), 'sf_admin'))) ?>
</a>

<a href="<?php echo url_for($module) ?>?page=
<?php echo $pager->getLastPage() ?>">
<?php echo image_tag('/images/last.png', array('alt' =>
__('Last page', array(), 'sf_admin'), 'title' =>
__('Last page', array(), 'sf_admin'))) ?>
</a>
</div>

You'll need to have the last.png, first.png, next.png and previous.png on your /myproject/web/images directory in order to get the pretty arrows. You can get the png files from any source you like, I extracted them from the my symonfy installation /symfony_installation/data/web/sf/sf_admin/images.

Editing the Action


Open your /myproject/apps/myapplication/config/app.yml and add the variable max_items_x_page:
all:
max_items_x_page: 5

Open your action file in my case the module is named repairrequest and the class is RepairRequest.
On the executeIndex function change the code to:
public function executeIndex(sfWebRequest $request) {
if ($request->getParameter('sort') && $this->isValidSortColumn(
$request->getParameter('sort'))) {
$this->setSort(array($request->getParameter('sort'),
$request->getParameter('sort_type')));
}

$items_x_page = sfConfig::get('app_max_items_x_page');
$this->pager = new sfDoctrinePager('RepairRequest', $items_x_page);
$this->pager->setQuery($this->buildQuery());
$this->pager->setPage($request->getParameter('page', 1));
$this->pager->init();
$this->sort = $this->getSort();
}

Change RepairRequest for your class.

Insert the following code at the end of your Action class:
//******************************************************************************************
//********************** ROUTINES FOR PAGING AND SORTING ***********************************
//******************************************************************************************
protected function buildQuery() {
$et = Doctrine_Core::getTable('RepairRequest');

$query = $et->createQuery();

$this->addSortQuery($query);

return $query;
}

protected function addSortQuery($query) {
if (array(null, null) == ($sort = $this->getSort())) {
return;
}

if (!in_array(strtolower($sort[1]), array('asc', 'desc'))) {
$sort[1] = 'asc';
}
$query->addOrderBy($sort[0] . ' ' . $sort[1]);
}

protected function getSort() {
if (null !== $sort = $this->getUser()->getAttribute('repairrequest.sort',
null, 'admin_module')) {
return $sort;
}

$this->setSort(array(null, null));

return $this->getUser()->getAttribute('repairrequest.sort', null,
'admin_module');
}

protected function setSort(array $sort) {
if (null !== $sort[0] && null === $sort[1]) {
$sort[1] = 'asc';
}
$this->getUser()->setAttribute('repairrequest.sort', $sort, 'admin_module');
}

protected function isValidSortColumn($column) {
return Doctrine::getTable('RepairRequest')->hasColumn($column);
}


Replace RepairRequest for your class name and repairrequest.sort for yourmodulename.sort.

Editing the Template


Open your /myproject/apps/myapplication/modules/mymodule/templates/indexSuccess.php at the top of the page ad the helper
for i18n.
<?php use_helper('I18N') ?>


The following code will change depending on your class
<tbody>
<?php foreach ($pager->getResults() as $i => $repair_request): ?>
<tr>
<td><a href="<?php echo url_for('repairrequest/show?id='.$repair_request->getId()) ?>">
<?php echo $repair_request->getId() ?></a></td>
<td><?php echo $repair_request->getRequestDate() ?></td>
<td><?php echo $repair_request->getLocation() ?></td>
<td><?php echo $repair_request->getDescription() ?></td>
<td><?php echo $repair_request->getRepairType() ?></td>
<td><?php echo $repair_request->getRepairStatus() ?></td>
<td><?php echo $repair_request->getRealStateId() ?></td>
<td><?php echo $repair_request->getUpdatedAt() ?></td>
<td><?php echo $repair_request->getUpdatedByFk()->getUsername() ?></td>
</tr>
<?php endforeach; ?>
</tbody>

What your doing is using the pager instead of the full cursor your get by default.
Next insert the pagination code.
<?php include_partial('global/pagination_control', array('pager' => $pager, 'module' => 'repairrequest')) ?>
<a href="<?php echo url_for('repairrequest/new') ?>">New</a>

Save it.
Now your pagination should work. On a next post I'll show how to do the sorting.
After I ran the code i got a message as if the route repairrequest did not exist (and it did). I fixed it editing the routing.yml (but I'm not really sure why I had to, just hacked it). I added the following code at the top of the routing.yml:
repairrequest:
class: sfDoctrineRouteCollection
options:
model: RepairRequest
module: repairrequest
prefix_path: /repairrequest
column: id
with_wildcard_routes: true

jueves, 4 de noviembre de 2010

Creating Random Data for Fixtures

A couple a days a go I heard a sales man raving about the capabilities of Toad (a Quest Software software) of populating tables with random data. The problem I saw with this feature is that it filled the table with incomprehensible gibberish.

Symonfy allows you to load data to your tables, but to create random data you need to rely a little on php.
Lets use a basic client table like this one (on config/doctrine/schema.yml):

Client:
columns:
id:
type: integer(4)
primary: true
autoincrement: true
firstname:
type: string(30)
notnull: true
middlename:
type: string(30)
notnull: false
lastname:
type: string(30)
notnull: true
dateOfBirth:
type: date
notnull: true
nationalId:
type: string(13)
notnull: true
gender:
type: enum
length: 1
values: ['M', 'F']

To create random clients will combine PHP code inside the fixtures YaML (data/fixtures/fixtures.yml)file like this:

<?php $names = array('Juan', 'Pedro', 'Perenceo', 'Aquileo', 'Ramiro', 'Esteban',
'John', 'Rabindranath', 'Pablo', 'Judas', 'Akira', NULL); ?>
<?php $lastnames = array('De Urriola', 'Escobedo', 'Einstein', 'Escobar','Gonzalez',
'Luna', 'Martinez', 'Obama', 'Perez',
'Ramirez','Hawkins', 'Marquez', 'Jaramillo',
'Lopez', 'Vergara', NULL); ?>
Client:
<?php for ($i = 1; $i <= 10; $i++): ?>
client_<?php echo $i ?>:
firstname: <?php echo $names[rand(0,count($names)-2)] ."\n" ?>
middlename: <?php echo $names[rand(0,count($names)-1)] ."\n"?>
lastname: <?php echo $lastnames[rand(0,count($lastnames)-2)] ."\n" ?>
nationalId: <?php echo rand(1,9) . '-'.rand(25,999).'-'.rand(1500,9859). "\n" ?>
dateOfBirth: <?php echo "'". rand(1956,1971).'-'.rand(1,12). '-'.rand(1,28) ."'\n" ?>
gender: M
<?php endfor ?>

After running doctrine:data-load the fixtures will create ten cliens records based on the $names and $lastname arrays.

miércoles, 3 de noviembre de 2010

Installation Steps for sfDoctrineGuardPlugin

Steps to install the sfDoctrineGuardPlugin using Netbeans 6.9.x by downloading the package instead of installing it with PEAR.

Download and Installation

Download the correct version of sfDoctrineGuardPlugin, do not download the sfGuardPlugin which is for the Propel ORM.

1. On the sfDoctrineGuardPlugin page http://www.symfony-project.org/plugins/sfDoctrineGuardPlugin click on Download Package select a download directory (/Users/myuser/Downloads).
2. Open the Netbeans right click on the project select Symnfony>Run Commnad...
3. Select plugin:install task.
4. On the parameters field type the path to the downloaded file (for example: /Users/myuser/Downloads/sfDoctrineGuardPlugin-5.0.0.tgz)
5. Click on Run

During the installation I get severl errors like: PHP Deprecated: Function set_magic_quotes_runtime() is deprecated in /Applications/xampp/xamppfiles/lib/php/pear/PEAR/Registry.php on line 790 But the installation seems to work fine.

This process will register the plugin on the project configuration (myproject/Sources Files/config/ProjectConfiguration?.class.php) and copy the plugin to your plugins directory. Verify that the project configuration looks something like this

require_once '/usr/lib/php/symfony/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();

class ProjectConfiguration extends sfProjectConfiguration
{
public function setup()
{
$this->enablePlugins('sfDoctrinePlugin');
$this->enablePlugins('sfDoctrineGuardPlugin');
}
}

Verify that a directory with content is under myproject/Sources Files/plugins under the name sfDoctrineGuardPlugin.

Configuration

Table Creation and Data Loading

1. Copy the file myproject/Sources Files/plugins/sfDoctrineGuardPlugin/data/fixtures/fixtures.yml.sample to myproject/Sources Files/data/fixtures
2. Rename myproject/Sources Files/data/fixtures/fixtures.yml.sample to sfGuard_fixtures.yml
3. Open the Netbeans right click on the project select Symnfony>Run Commnad...
4. Select symfony doctrine:build-model
5. Click on Run
6. Select symfony doctrine:build-sql
7. Click on Run
8. Select symfony doctrine:insert-sql
9. Click on Run
10.Select doctrine:build task.
11.On the parameters field type --all --no-confirmation --and-load
12.Click on Run

This will drop the existing tables recreate them, create the sfGuardPlugin tables and load the fixtures from the application and from the sfGuard_fixtures.yml.
Enabling Modules

This configuration assume you have two applications frontend and backend. The frontend will only authenticate and the backend in addition to authentication will have access to create users, groups and permissions.

Backend Configuration

1. Open the myproject/Sources Files/apps/backend/config/settings.yml
2. Find the enabled_modules, if it does not exist create it, add the sfGuardGroup, sfGuardUser and sfGuardPermission. It should look like this:

all:
.settings:
enabled_modules: [default, sfGuardAuth, sfGuardGroup, sfGuardUser, sfGuardPermission]

3. Change the default login and signin modules. Adding this:
    .actions:
login_module: sfGuardAuth
login_action: signin

secure_module: sfGuardAuth
secure_action: secure
4. Save the file.
5. Open the file myproject/Sources Files/apps/backend/config/filters.yml
6. Add the following before the security filter:
    remember_me:
class: sfGuardRememberMeFilter

security: ~
7. Save the file.
8. Open the file myproject/Sources Files/apps/backend/lib/myUser.class.php
9. Change to myUser to inherit from sfGuardSecurityUser instead of sfBasicSecurityUser

class myUser extends sfGuardSecurityUser
{
}

10. Save the file.
11. Open the file myproject/Sources Files/apps/backend/config/security.yml
12. Change the is_secure variable to true:

default:
is_secure: true

Test the access to the sfGuardUser accesing the following url: http://127.0.0.1:9091/backend_dev.php/sfGuardUser Change the host 127.0.0.1:9091 to your host.

Frontend Configuration


1. Open the file myproject/Sources Files/apps/frontend/config/settings.yml
2. Find the enabled_modules, if it does not exist create it, add the sfGuardAuth. It should look like this:

all:
.settings:
enabled_modules: [default, sfGuardAuth]

3. Change the default login and signin modules. Adding this:

.actions:
login_module: sfGuardAuth
login_action: signin

secure_module: sfGuardAuth
secure_action: secure

4. Save the file.
5. Follow steps 5 through 12 of the Backend Configuration for the frontend application.