.: HosiriS :.

Informatica e non solo

Archive for the ‘CakePHP’ Category

Gestiamo in maniera corretta l’edit degli utenti con CakePHP

Posted by hosiris su novembre 14, 2011

Credo che vi sarete accorti che il sistema di login costruito con cake ha, tra gli altri, un piccolo difettuccio: quando si modifica un qualsiasi parametro dell’utente, automaticamente viene modificata la password di accesso. Questo succede perché il modulo calcola l’hash ogni volta che viene sottomesso un form.
Leggi il seguito di questo post »

Annunci

Posted in CakePHP, CMS&MVC, Programmazione | 1 Comment »

Come tenere traccia delle operazioni degli utenti connessi con CakePHP

Posted by hosiris su ottobre 13, 2011

Potrebbe essere abbastanza rognoso trovarsi dei dati che per qualche oscuro motivo sono diversi da come li si erano caricati! Magari qualche birbantello inavvertitamente ha fatto delle modifiche… certo assegnando i permessi alle varie tabelle si possono limitare questi inconvenienti, ma rimarrebbe il problema sulle tabelle su cui quell’utente ha i privilegi amministrativi.
Come possiamo tener traccia di ogni operazione eseguita dell’utente?

Ci viene in aiuto un behavior di CakePHP: LogableBehavior.
Leggi il seguito di questo post »

Posted in CakePHP, CMS&MVC, Programmazione | 1 Comment »

Controlliamo l’esistenza di dati prima di eseguire una query

Posted by hosiris su settembre 26, 2011

Quando si inseriscono dei dati in un db sfruttando le azioni di CakePHP spesso può capitare che vengano inserite delle tuple duplicate. Non ci resta che inserire una funzione che prima dell’esecuzione della query controlli se non sia già esistente.
Leggi il seguito di questo post »

Posted in CakePHP, CMS&MVC, Programmazione | 1 Comment »

Utenti, Gruppi e Permessi con CakePHP

Posted by hosiris su settembre 19, 2011

In questo post vedremo come realizzare un sistema di autorizzazioni per l’accesso al nostro sito.
Leggi il seguito di questo post »

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »

Localizzazione in CakePHP

Posted by hosiris su febbraio 24, 2011

Oggi voglio consigliare due articoli scritti dal buon Blackout.

Con questo articolo scopriremo come localizzare la lingua della nostra applicazione web.

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »

CakePHP su AppServ!

Posted by hosiris su febbraio 22, 2011

Eccoci di nuovo davanti il solito Windows 😀 sempre a creare problemi!
Mi si è presentata la necessità di dover installare un server web ad un amico… e, dovendo puntare sulla semplicità, ho deciso di installare AppServ. Per fare in modo che CakePHP funzioni su questo servizio è necessario abilitare il mod_rewrite, inoltre per evitare problemi sulla scrittura degli indirizzi sarebbe utile poter configurare i virtual host.
Bene, date le specifiche, cominciamo a lavorare.
Apriamo il file “http.conf” che troviamo sotto c:\AppServ\Apache2.2\conf\ e cerchiamo le seguenti linee:

#LoadModule vhost_alias_module module/mod_vhost_alias.so
#LoadModule rewrite_module modules/mod_rewrite.so

e togliamo i commenti ad entrambi, ottenendo:

LoadModule vhost_alias_module module/mod_vhost_alias.so
LoadModule rewrite_module modules/mod_rewrite.so

Poi diciamo al file di configurazione dove andare a prendere le configurazioni dei virtual host, quindi cerchiamo:

#Include conf/extra/httpd-vhosts.conf

e togliamo il commento, così:

#Include conf/extra/httpd-vhosts.conf

salviamo e chiudiamo, quindi possiamo aprire il file “extra/httpd-vhosts.conf”. Calcelliamo tutto ed inseriamo il seguente:

    ServerAdmin webmaster@project
    DocumentRoot "C:/AppServ/www/project/app/webroot/"
    ServerName project
    ErrorLog "logs/project-error.log"
    CustomLog "logs/project-access.log" common

In questa configurazione ipotizziamo che il progetto CakePHP si trovi sotto la cartella “project” e che nel file “hosts” (posizionato sotto c:\windows\system32\drivers\etc) sia presente la seguente linea:

127.0.0.1 project

Riavviamo i servizi… e adesso potremmo coderci la nostra opera 😀

Posted in CakePHP, Programmazione | 2 Comments »

Sistema di login in CakePHP

Posted by hosiris su febbraio 10, 2011

Nei vari esperimenti fatti con cake, non ho mai fatto cenno a come poter mettere in sicurezza parte del nostro sito. Ma sappiamo bene come ogni attività amministrativa debba essere protetta per evitare che malintenzionati sfruttino falle su operazioni “avanzate”.

La prima cosa da fare è creare la tabella degli utenti:

CREATE TABLE `users`(
    `id` int(10) unsigned not null auto_increment,
    `name` varchar(50) not null,
    `surname` varchar(50) not null,
    `username` varchar(50) not null,
    `password` varchar(50) not null,
    `email` varchar(50) not null,
    `created` datetime,
    `modified` datetime,
    PRIMARY KEY (`id`)
) ENGINE InnoDB DEFAULT CHARSET=utf8_unicode_ci

Dopo aver creato il controller, il model e le viste, manualmente o facendo uso di bake, aggiungiamo i seguenti metodi alla classe del controller:

function login() {}
function logout() {
    $this->redirect($this->Auth->logout());
}

Creiamo il file login.ctp all’interno della cartella delle viste:

<?php
    if ($session->check('Message.auth')) $session->flash('auth');
    echo $form->create('User', array('action' => 'login'));
    echo $form->input('username');
    echo $form->input('password');
    echo $form->end('Login');
?>

Nella cartella app creiamo un file chiamato “app_controller.php”. Questo file conterrà delle funzioni che saranno valide per tutti i controller che andremo a generare.

class AppController extends Controller {
    var $components = array('Auth');
    function beforeFilter() {
        $this->Auth->userModel = 'User';
        $this->Auth->fields = array('username' => 'username', 'password' => 'password');
        $this->Auth->loginAction = array('admin' => false, 'controller' => 'users', 'action' => 'login');
        $this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index');
    }
}

Questa funzione causerà il redirect alla pagina di login per tutti i controller, quindi dovremo sovrescrivere questo funzionamento su tutti i controller che non necessitano di tale comportamento (la pagina dei contatti ad esempio). In ognuno dei controller “liberi” aggiungiamo il seguente metodo:

function beforeFilter() {
    $this->Auth->allow('index');
    parent::beforeFilter();
}

Ricordiamo che sarà necessario permettere l’aggiunta di un utente quindi nel controller users_controller.php aggiungiamo:

function beforeFilter() {
    $this->Auth->allow('add');
    parent::beforeFilter();
}

Ok, con questo abbiamo concluso. E’ un sistema basilare, che quindi andrà migliorato.

Buon divertimento!

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »

CakePHP e Google Map v3

Posted by hosiris su gennaio 23, 2011

Ho già descritto come usare Google Maps tramite CakePHP, ma l’articolo che avevo linkato usava la versione 2 di gmap.
Viste le funzionalità aggiuntive della v3 ho continuato a cercare nuove soluzioni, giungendo a questo link.
Anche in questo post viene descritto l’uso di un helper. Ma il codice non svolgeva quello di cui avevo bisogno, quindi sono stato costretto ad aggiungere un pezzo di codice ottenendo il seguente helper:

//app/view/helper/google_map_v3.php
<?php
/*
   CakePHP Google Map V3 - Helper to CakePHP framework that integrates a Google Map in your view
   using Google Maps API V3.
  Copyright (c) 2010 Marc Fernandez Girones: info@marcfg.com
  MIT LICENSE:
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  MarcFG : http://www.marcfg.com
  
  @author   Marc Fernandez Girones <info@marcfg.com>
  @version   1.0
  @license   OPPL
  
  Date     May 13, 2010
  USAGE:
  
  In your CONTROLLER:
    var $helpers = array('GoogleMapV3');  Add the helper
   In your VIEW:
     To add a map that localizes you:
       echo $googleMapV3->map();
    
     OR
    
     You can also pass to the function a variable with any of the followings options and change the default parameters
       $mapOptions= array(
        'width'=>'800px',        //Width of the map
        'height'=>'800px',        //Height of the map
        'zoom'=>7,            //Zoom
        'type'=>'HYBRID',         //Type of map (ROADMAP, SATELLITE, HYBRID or TERRAIN)
        'latitude'=>40.69847032728747,  //Default latitude if the browser doesn't support localization or you don't want localization
        'longitude'=>-1.9514422416687,  //Default longitude if the browser doesn't support localization or you don't want localization
        'localize'=>true,        //Boolean to localize your position or not
        'marker'=>true,          //Boolean to put a marker in the position or not
        'markerIcon'=>'http://google-maps-icons.googlecode.com/files/home.png',  //Default icon of the marker
        'infoWindow'=>true,        //Boolean to show an information window when you click the marker or not
        'windowText'=>'My Position'    //Default text inside the information window
      );
      echo $googleMapV3->map($mapOptions); To add a map that localizes you
    
    To add a marker:
       echo $googleMapV3->addMarker(array('latitude'=>40.69847,'longitude'=>-73.9514));
      
     OR
    
     You can also pass to the function a variable with any of the followings options and change the default parameters
    $markerOptions= array(
      'id'=>1                //Id of the marker
      'latitude'=>40.69847032728747,    //Latitude of the marker
      'longitude'=>-1.9514422416687,    //Longitude of the marker
      'markerIcon'=>'http://google-maps-icons.googlecode.com/files/home.png', //Custom icon
      'shadowIcon'=>'http://google-maps-icons.googlecode.com/files/home.png', //Custom shadow
      'infoWindow'=>true,          //Boolean to show an information window when you click the marker or not
      'windowText'=>'Marker'        //Default text inside the information window
    );
    
   This helper uses the latest Google API V3 so you don't need to provide or get any Google API Key
*/
class GoogleMapV3Helper extends Helper {
  
  //DEFAULT MAP OPTIONS (function map())
  var $defaultWidth="800px";//Width of the map
  var $defaultHeight="800px";//Height of the map
  var $defaultZoom=6;//Default zoom
  var $defaultType='HYBRID';//Type of map (ROADMAP, SATELLITE, HYBRID or TERRAIN)
  var $defaultLatitude=40.69847032728747;//Default latitude if the browser doesn't support localization or you don't want localization
  var $defaultLongitude=-73.9514422416687;//Default longitude if the browser doesn't support localization or you don't want localization
  var $defaultLocalize=true;//Boolean to localize your position or not
  var $defaultMarker=true;//Boolean to put a marker in the position or not
  var $defaultMarkerIcon='http://google-maps-icons.googlecode.com/files/home.png'; //Default icon of the marker
  var $defaultInfoWindow=true;//Boolean to show an information window when you click the marker or not
  var $defaultWindowText='My Position';//Default text inside the information window
    
  //DEFAULT MARKER OPTIONS (function addMarker())
  var $defaultInfoWindowM=true;//Boolean to show an information window when you click the marker or not
  var $defaultWindowTextM=' ';//Default text inside the information window
  
  
/**
   * Function map
   *
   * This method generates a tag called map_canvas and insert
   * a google maps.
   *
   * Pass an array with the options listed above in order to customize it
   *
   * @author Marc Fernandez <info (at) marcfg (dot) com>
   * @param array $options - options array
   * @return string - will return all the javascript script to generate the map
   *
   */  
  function map($options=null){
    if($options!=null) extract($options);
    if(!isset($width))     $width=$this->defaultWidth;
    if(!isset($height))   $height=$this->defaultHeight;  
    if(!isset($zoom))     $zoom=$this->defaultZoom;      
    if(!isset($type))     $type=$this->defaultType;    
    if(!isset($latitude))   $latitude=$this->defaultLatitude;  
    if(!isset($longitude))   $longitude=$this->defaultLongitude;
    if(!isset($localize))   $localize=$this->defaultLocalize;    
    if(!isset($marker))   $marker=$this->defaultMarker;    
    if(!isset($markerIcon)) $markerIcon=$this->defaultMarkerIcon;  
    if(!isset($infoWindow)) $infoWindow=$this->defaultInfoWindow;  
    if(!isset($windowText)) $windowText=$this->defaultWindowText;  
    
    echo '<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>';
    echo '<script type="text/javascript" src="http://code.google.com/apis/gears/gears_init.js"></script>';
    $map = "<div id=\"map_canvas\" style=\"width:".$width."; height:".$height."\"></div>";
    $map .= "
    <script>
      var noLocation = new google.maps.LatLng(".$latitude.", ".$longitude.");
      var initialLocation;
      var browserSupportFlag = new Boolean();
      var map;      
      var geocoder = new google.maps.Geocoder();
      var myOptions = {
       zoom: ".$zoom.",
       mapTypeId: google.maps.MapTypeId.".$type."
      };
      map = new google.maps.Map(document.getElementById(\"map_canvas\"), myOptions);
    ";
    if($localize) $map .= "localize();"; else $map .= "map.setCenter(noLocation);";
    $map .= "
      function localize(){
        if(navigator.geolocation) { // Try W3C Geolocation method (Preferred)
          browserSupportFlag = true;
          navigator.geolocation.getCurrentPosition(function(position) {
           initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
           map.setCenter(initialLocation);";
           if($marker) $map .= "setMarker(initialLocation);";
              
          $map .= "}, function() {
           handleNoGeolocation(browserSupportFlag);
          });
          
        } else if (google.gears) { // Try Google Gears Geolocation
          browserSupportFlag = true;
          var geo = google.gears.factory.create('beta.geolocation');
          geo.getCurrentPosition(function(position) {
           initialLocation = new google.maps.LatLng(position.latitude,position.longitude);
           map.setCenter(initialLocation);";
           if($marker) $map .= "setMarker(initialLocation);";    
        
          $map .= "}, function() {
           handleNoGeolocation(browserSupportFlag);
          });
        } else {
          // Browser doesn't support Geolocation
          browserSupportFlag = false;
          handleNoGeolocation(browserSupportFlag);
        }
      }
      
      function handleNoGeolocation(errorFlag) {
        if (errorFlag == true) {
         initialLocation = noLocation;
         contentString = \"Error: The Geolocation service failed.\";
        } else {
         initialLocation = noLocation;
         contentString = \"Error: Your browser doesn't support geolocation.\";
        }
        map.setCenter(initialLocation);
        map.setZoom(3);
      }";
      $map .= "
      function setMarker(position){
        var contentString = '".$windowText."';
        var image = '".$markerIcon."';
        var infowindow = new google.maps.InfoWindow({
          content: contentString
        });
        var marker = new google.maps.Marker({
          position: position,
          map: map,
          icon: image,
          title:\"My Position\"
        });";
       if($infoWindow){
         $map .= "google.maps.event.addListener(marker, 'click', function() {
                infowindow.open(map,marker);
              });";
       }
       $map .= "}";
    $map .= "</script>";
    return $map;
  }
  
  
  /**
   * Function addMarker
   *
   * This method puts a marker in the google map generated with the function map
   *
   * Pass an array with the options listed above in order to customize it
   *
   * @author Marc Fernandez <info (at) marcfg (dot) com>
   * @param array $options - options array
   * @return string - will return all the javascript script to add the marker to the map
   *
   */
  function addMarker($options){
    if($options==null) return null;
    extract($options);
    if(!isset($id)) $id=rand();
    if(!isset($infoWindow)) $infoWindow=$this->defaultInfoWindowM;
    if(!isset($windowText)) $windowText=$this->defaultWindowTextM;
    if(!isset($latitude) || $latitude==null || !isset($longitude) || $longitude==null){
      /*
       * This section manage position by geocoding address
       *
       * @author Giovanni Ruta <ruta.giovanni@gmail.com>
       * @licence GPL
       *
       * USE - in you view
       * $markerOptions = array(
       *        'address'=>$address,
       *        'city'=>$city,
       *        'number'=>$number
       * );
       * $gmap->addMarker($markerOptions);
       */
      if(!isset($address) || $address==null || !isset($city) || $city==null || !isset($number) || $number==null){
        return null;
      }else{
        $marker = " <script>";
        if(isset($markerIcon)) $marker .= "var image = '".$markerIcon."';";
        if(isset($shadowIcon)) $marker .= "var shadowImage = '".$shadowIcon."';";
        $marker .= "
          geocoder.geocode({ 'address': '".$address." ".$number.", ".$city."'}, function(results, status){
            if (status == google.maps.GeocoderStatus.OK){
              var marker".$id." = new google.maps.Marker({
                map: map,
                position: results[0].geometry.location,";
                if(isset($markerIcon)) $marker .= "icon: image,";
                if(isset($shadowIcon)) $marker .= "shadow: shadowImage,";
        $marker .= "
              });
            } else {
            }
          });";
        $marker .= "</script>";
      }
      /*
       * End for geocoding options
       */
    } else {
      if (!preg_match("/[-+]?\b[0-9]*\.?[0-9]+\b/", $latitude) || !preg_match("/[-+]?\b[0-9]*\.?[0-9]+\b/", $longitude)) return null;    
      $marker = "<script>";
      if(isset($markerIcon)) $marker .= "var image = '".$markerIcon."';";
      if(isset($shadowIcon)) $marker .= "var shadowImage = '".$shadowIcon."';";
      $marker .= "var myLatLng = new google.maps.LatLng(".$latitude.", ".$longitude.");
            var marker".$id." = new google.maps.Marker({
              position: myLatLng,
              map: map,";
              if(isset($markerIcon)) $marker .= "icon: image,";
              if(isset($shadowIcon)) $marker .= "shadow: shadowImage,";
      $marker .= "
            });";
      $marker .= "
        var contentString = '".$windowText."';
        var infowindow".$id." = new google.maps.InfoWindow({
          content: contentString
        });";
      if($infoWindow){
           $marker .= "google.maps.event.addListener(marker".$id.", 'click', function() {
                  infowindow".$id.".open(map,marker".$id.");
                });";
      }
      $marker .= "</script>";
    }
    return $marker;
  }
}
?>

Non ho fatto altro che aggiungere una piccola porzione di codice alla funzione “addMarker()” hce permette di aggiungere i marker anche se non si hanno a disposizione le coordinate.
Il funzionamento è semplice: dopo aver richiamato l’helper nel controller

var $helpers = array('GoogleMapV3');

sarà sufficiente aggiungere il seguente codice nella vista

$mapOptions= array(
        'width'=>'800px',
        'height'=>'800px',
        'zoom'=>6,
        'type'=>'TERRAIN',
        'localize'=>false,
        'latitude'=>40.69847032728747,
        'longitude'=>12.9514422416687,
        'marker'=>false,
        'markerIcon'=>'http://google-maps-icons.googlecode.com/files/home.png',
        'infoWindow'=>true,
        'windowText'=>''
    );
echo $googleMapV3->map($mapOptions);

Ammirate la vostra Italia
Buon divertimento

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »

Unico form per gestire molti model con CakePHP

Posted by hosiris su gennaio 15, 2011

Queste ultime settimane mi hanno visto impegnato nel cercare una soluzione al seguente problema: avendo due form, come posso ridurre al minimo il numero di click per effettuare degli inserimenti sequenziali?
Ho provato di tutto, dai redirect ad Ajax… fin quando ho avuto la semplice idea di unire i due form in unico.
CakePHP fornisce un metodo (saveAll()) che ci permette di effettuare salvataggi su più model, come in una transazione… purtroppo quando lavoriamo con relazioni HABTM questa soluzione non funziona.
Come risolvere allora? La soluzione arriva da un altro metodo: requestAction() che ci permette di fare richieste a controller diversi da quello attuale. Ma passiamo alla pratica; riprendiamo le nostre tabelle users e groups e facciamo in modo che il form di inserimento users contenga anche il form per il group.
Apriamo la vista per l’azione add ed inseriamo il seguente:

<?php echo $this->Form->create('User');?>
  <fieldset>
    <legend><?php __('Add User'); ?></legend>
  <?php
    echo $this->Form->input('name');
    echo $this->Form->input('Group');
    echo $this->Form->input('AddGroup',array('type'=>'checkbox','label'=>'Aggiungi Gruppo'));
    ?><fieldset><?php
    echo $this->Form->input('Group.name');
    ?></fieldset><?php
  ?>
  </fieldset>
<?php echo $this->Form->end(__('Submit', true));?>

Abbiamo aggiunto una checkbox ed un campo di input. Lo scopo è quello di far scegliere all’utente se voler aggiungere un ulteriore gruppo oppure usare quelli esistenti. Allora nel controller dobbiamo inserire una if e la chiamata all’azione del controller groups:

function add() {
  if (!empty($this->data)) {
    /*
     * Nel caso si decida di aggiungere un nuovo gruppo l'if sarà vero
     */
    if($this->data['User']['AddGroup']){
      // Salvo i dati che mi servono in una variabile di sessione
      $this->Session->write('groupname',$this->data['Group']['name'];
      // Eseguo la richiesta
      $groups = $this->requestAction(array('controller'=>'groups','action'=>'savefrom'));
      // Aggiungo l'id dell'ultimo gruppo inserito nell'array di inserimento dell'user
      $this->data['Group']['Group']['0'] = $this->Session->read('idgroup');
    }
    /*
     * Eseguo il normale inserimento dell'user
     */
    $this->User->create();
    if ($this->User->save($this->data)) {
      $this->flash(__('User saved.', true), array('action' => 'index'));
    } else {
    }
  }
  $groups = $this->User->Group->find('list');
  $this->set(compact('groups'));
}

A questo punto dobbiamo creare l’azione savefrom nel controller groups. Questa action non farà altro che leggere la variabile di sessione generata, effettuare l’inserimento e restituire l’ultimo id inserito:

function savefrom(){
  $data['Group']['name']=$this->Sessione->read('groupname');
  $this->Group->save($data);
  $this->Session->write('idgroup',$this->Group->getLastInsertId());
}

Et voilà… il gioco è fatto! Adesso è sufficiente aggiungere un effetto javascript che faccia apparire il “sottoform” solo dopo aver spuntato il box di aggiunta.
Sono sicuro che è la soluzione meno elegante esistente, ma questo è quello che il mio cervelletto ha prodotto! Se qualcuno vuole proporre soluzioni migliori renderebbe un grosso favore alla società.

PS: Grazie ad Allanon per la dritta sulla funzione 😀

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »

Gestiamo GMap tramite CakePHP

Posted by hosiris su gennaio 11, 2011

Ormai non si può fare a meno delle API di Google e di conseguenza bisogna saperli applicare ad ogni situazione. Con questo post voglio portare alla vostra attenzione un articolo che mi ha permesso di raggiungere lo scopo in maniera semplice e lineare.

Link: Adding a Google Map to your App

Posted in CakePHP, CMS&MVC, Programmazione | Leave a Comment »