Archív

Archív pro ‘zend framework’ Kategorie

Zend_Rest_Route a Zend_Rest_Controller v ZF 1.9

01.09.2009 View Comments

Proč REST a co to obnáší?

V Zend Frameworku 1.9 byla přidána pro používání REST v url a v controlleru.

REST je v módě a proto nám ho přidali i do ZF. Ne vážně samozřejmě každý teď dělá do REST. Implementace RESTu existuje v každém větším frameworku. V ZF už delší dobu je REST klient i server. Klienta můžete využít pro práci s mnohými službami na internetu (twitter, flickr, …).

V tabulce je dobře vidět jak se využije HTTP protokol. Metody PUT, DELETE se běžně nevyužívají.

Akce SQL HTTP
Create Insert PUT
Read Select GET
Update Update POST
Delete Delete DELETE

REST API je součástí mnoha z nich. Pokud máte aplikaci RESTful, není problém potom provozovat i REST api.

  • do ZF byli přidány dvě nové třídy Zend_Rest_Route, Zend_Rest_Controller
  • přinese nám to využití HTTP protokolu (GET, POST, PUT, DELETE)
  • pro používání RESTu změníme controller, budeme používat Zend_Rest_Controller místo Zend_Action_Controller
  • v controlleru je potřeba potřeba definovat tyto metody
    • indexAction()
    • getAction()
    • postAction()
    • putAction()
    • deleteAction()
  • GET je get a všechny destruktivní akce jsou přes POST

Vzal jsem základní tutorial z akrabatu a modifikoval jsem ho pro použití s REST. Zdrojové kódy jsou k dispozici na bitbucketu.

Do bootstrapu je potřeba přidat definici pro Zend_Rest_Route

    function _initRestRoute()
    {
        $this->bootstrap('Request');
        $front = $this->getResource('FrontController');
        $restRoute = new Zend_Rest_Route($front, array(), array(
            'default' => array('albums')
                ));
        $front->getRouter()->addRoute('rest', $restRoute);
    }

    function _initRequest()
    {
        $this->bootstrap('FrontController');
        $front = $this->getResource('FrontController');
        $request = $front->getRequest();
        if (null === $front->getRequest()) {
            $request = new Zend_Controller_Request_Http();
            $front->setRequest($request);
        }
        return $request;
    }

a je potřeba modifikovat controller, aby využíval celký HTTP protokol.

class AlbumsController extends Zend_Rest_Controller
{
    private $_albums;
    private $_form;

    public function init()
    {
        /* Initialize action controller here */
        $this->_albums = new Zend_Db_Table('albums');
     	$this->_form = new Form_Album();
    }

    public function indexAction()
    {
        $this->view->title = "My Albums";
        $this->view->headTitle($this->view->title, 'PREPEND');
        $this->view->albums = $this->_albums->fetchAll();
    }

    public function listAction()
    {
        $this->_forward('index');
    }

    public function getAction()
    {
        $this->view->album = $this->_albums->find($this->_getParam('id'))->current();
    }

    public function putAction()
    {
        $album = $this->_albums->find($this->_getParam('id'))->current();
        if ($this->_form->isValid($this->_request->getParams())) {
            $album->setFromArray($this->_form->getValues())->save();
            $this->_redirect('albums');
        } else {
            $this->view->album = $album;
            $this->view->form = $this->_form;
            $this->render('edit');
        }

    }

    public function postAction()
    {
        if ($this->_form->isValid($this->_request->getParams())) {
	       $this->_albums->createRow($this->_form->getValues())->save();
           $this->_redirect('albums');
        } else {
            $this->view->form = $this->_form;
            $this->view->title = "Add new album";
           $this->render('new');
        }

    }

    public function newAction()
    {
        $this->view->title = "Add new album";
        $this->view->headTitle($this->view->title, 'PREPEND');

        $this->view->form = $this->_form;

    }

    public function editAction()
    {
        $this->view->title = "Edit album";
        $this->view->headTitle($this->view->title, 'PREPEND');
        $album = $this->_albums->find($this->_getParam('edit'))->current();
	    if ($album) {
    	    $this->_form->populate($album->toArray());
	    }
    	$this->view->form = $this->_form;
    	$this->view->album = $album;

    }

    public function deleteAction()
    {
        $this->view->title = "Delete album";
        $this->view->headTitle($this->view->title, 'PREPEND');

    	$album = $this->_albums->find($this->_getParam('id'))->current();
    	$album->delete();
        $this->_redirect('albums');

    }
}
Categories: zend framework Tags: ,

Zend Framework 1.6 a ajax pomocí jQuery

23.09.2008 View Comments

Jak jsem psal v Zend Framework 1.6 a moje zkušenosti s Dojo TabContainer, nakonec jsem použil jQuery. Ve formuláři se dají měnit některá data, které jsou závislá na dalších, které automaticky předvyplňuji a na to jsem použil při změnách ajax. Docela mě potěšilo jak jednoduše a pěkně se to dá udělat pomocí jQuery.

<script>
$(document).ready(function(){
     $("#example > ul").tabs();
     $('#page1-deadline_vyzva').datepicker();
     $('#page3-datum_zahajeni').datepicker();
     $('#page3-datum_ukonceni').datepicker();

      $('#page1-editor').change(function(){
             $.ajax({
                        type: "POST",
                        url: "<?php echo $this->baseUrl();?>/user/info/idcvut/" + $(this).val(),
                        success: function(xml){
					if ($.browser.msie)
					{
						xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
						xmlDoc.async="false";
						xmlDoc.loadXML(xml);
						$("#page1-navrhovatel_jmeno")[0].value = xmlDoc.getElementsByTagName("name")[0].childNodes[0].nodeValue;
						$("#page1-navrhovatel_email")[0].value = xmlDoc.getElementsByTagName("email")[0].childNodes[0].nodeValue;
						$("#page1-navrhovatel_telefon")[0].value = xmlDoc.getElementsByTagName("phone")[0].childNodes[0].nodeValue;
						$("#page1-navrhovatel_pracoviste")[0].value = xmlDoc.getElementsByTagName("dept")[0].childNodes[0].nodeValue;
					}
					else
					{
					$("#page1-navrhovatel_jmeno")[0].value = $("name", xml).text();
					$("#page1-navrhovatel_email")[0].value = $("email", xml).text();
					$("#page1-navrhovatel_telefon")[0].value = $("phone", xml).text();
					$("#page1-navrhovatel_pracoviste")[0].value = $("dept", xml).text();
					}
                        }
             }); // end ajax
      }); // end change function
}); // end document ready
</script>
...

Původní skript jsem rošířil o několik dalších funkcí, přidal jsem datapickery pro datumy a potom ten ajax. Nejprve pomocí vybere prvek a přidáme mu attribut onChange.

$('#page1-editor').change(function(){ … });

Do této funkce jsem vložil volání ajaxu. Je to jednoduché a dobře pochopitelné. Type je typ GET nebo POST, v url je URL Controlleru, který vrací XML s potřebnými daty. Pomocí $(this.val) si šáhnu na vyplněnou hodnotu v políčku na které jsem aplikoval onChange(). Success vrací data, které si jednoduše parsuji přes $(„name“, xml).text(), kde name je <name></name> z xml dat, které posílá php.

Je to jednoduché a moc pěkný kód, který najde uplatnění. Dobré je, že není potřeba do formuláře přidávat do atributů funkci onchange, jak jsem to musel dělat, když jsem nepoužívat jQuery.

Ještě přidám část kódu z controlleru:

…
function infoAction()
{
$this->_helper->layout->disableLayout();
$this->_helper->getHelper('ViewRenderer')->setNoRender();
$idcvut = (int)$this->_request->getParam('idcvut');
//echo $idcvut;
$ssu = new Usermap($this->config);
// make xml
//Zend_Debug($i);
$i=$ssu->getUsermapInfoByID($idcvut);
$xml = '<user><name>'.$i[‘cn’].'</name><email>'.$i['email'].'</email><phone>'.$i[‘phone’].'</phone><dept>'.$i[‘department’].'</dept></user>';
echo $xml;
}
…

Snad to někomu pomůže, moc příkladů na Zend a jQuery ajax jsem nikde nenašel.

Categories: jquery, zend framework Tags:

Zend Framework 1.6 a moje zkušenosti s Dojo TabContainer

11.09.2008 View Comments

Zrovna dělám na jednom malém projektu, který jsem hned začal psát zrovna jak vyšel ZF 1.6, celkem standardní věci až na to, že jsem potřeboval rozdělit formulář na více stránek a udělat záložky.

Postupoval jsem podle manulálu, vyvořil jsem si formulář se subformy a celkem to dobře funguje. Potom když jsem potřeboval rozbrazit záložky narazil jsem na několik problémů se kterými jsem si různě poradil.

Takto vypadají záložky pomocí Dojo frameworku.

Nejdříve byl problém přidat záložku kde byl jen text. Tak jsem vytvořil vlastní element a ten potom vracel jen co jsem do něj napsal za text. Dalším problémem byl konec fomuláře jak je vidět na obrázku tak špatně uzavíral a číst ho mizela.

To jsem opravil tak, že jsem celou strukturu záložek přesunul do View.

<?php echo $this->form; ?>

jsem musel udělat

<?php
$this->dojo()->enable();

echo "<form method='".$this->form->getMethod()."' enctype='application/x-www-form-urlencoded' >";

// Container with tabs
$this->tabContainer()->captureStart('tab1', array(), array('style' => 'width:950px;height:800px;'));

    // First tab "Dates"
    $this->contentPane()->captureStart('pane1', array(), array('title' => 'Vstupní evidence'));
        echo $this->form->getSubform('page1');
    echo $this->contentPane()->captureEnd('pane1');

    // Second tab "FAQ"
    $this->contentPane()->captureStart('pane2', array(), array('title' => 'Příprava rozpočtu'));
      echo $this->form->getSubform('page4');     
    echo $this->contentPane()->captureEnd('pane2');

    // Third tab "Closable"
    $this->contentPane()->captureStart('pane3', array(), array('title' => 'Podání projektu'));
        echo $this->form->getSubform('page2');
    echo $this->contentPane()->captureEnd('pane3');

    // Fourth tab "Splitted"
    $this->contentPane()->captureStart('pane4', array(), array('title' => 'Realizace projektu'));
      echo $this->form->getSubform('page3');
    echo $this->contentPane()->captureEnd('pane4');

echo $this->tabContainer()->captureEnd('tab1');

echo $this->form->submit;

echo "</form>"
?>

 

Je to složitější ale všechno vypadalo jak mělo, jen byl problém s poslední stranou formuláře. Je tam málo položek a tabContainer se neumí přizpůsobit výšce vloženého obsahu. To se mi nepodařilo vyřešit jinak než nahradit Dojo jQuery UI, který jsem byl zvyklý používat doteď.

  <script>
  $(document).ready(function(){
    $("#example > ul").tabs();
  });
  </script>
<?php
foreach ($this->notice as $n) {
    echo '<div class="error">'.$n . '</div>';
}
echo "<form method='".$this->form->getMethod()."' enctype='application/x-www-form-urlencoded' >";

// Container with tabs
?>
  <div id="example" class="flora">
            <ul>
                <li><a href="#page-1"><span>Vstupní evidence</span></a></li>
                <li><a href="#page-2"><span>Příprava rozpočtu</span></a></li>
                <li><a href="#page-3"><span>Podání projektu</span></a></li>
                <li><a href="#page-4"><span>Realizace projektu</span></a></li>
            </ul>
            <div id="page-1">
            <?php echo $this->form->getSubform('page1'); ?>
            </div>
            <div id="page-2">
            <?php
                  echo "<div style='padding:1em;'>";
                  include("../application/views/scripts/index/rozpocet.phtml");
                  echo "</div>";
            ?>
            </div>
            <div id="page-3">
            <?php echo $this->form->getSubform('page2'); ?>
            </div>
            <div id="page-4">
            <?php echo $this->form->getSubform('page3'); ?>
            </div>
        </div>
<?php
echo $this->form->submit;
echo "</form>";

?>

 

Po úpravě stylu to vypadá jinak, ale je to funkční jak chci a přesně kopíruje rozměry formuláře. 

Přijde mi, že v Dojo je spousta jednoduchých věcí jako jsou třeba ty taby zatím celkem nedotažené. Co si myslíte o té integraci ZF s Dojo?

Categories: javascript, jquery, zend framework Tags:

Gettext a PHP

15.07.2008 View Comments

Gettext je Open Source nástroj na překlad aplikací. Kdo s tímto nástrojem pracuje může můj článek rovnou vynechat, protože tyto věci zná.

Getext má jedinou nevýhodu, kterou lze celkem přejít, nejde přímo lidsky číst, ukládájí se v binárním tvaru do souboru s příponou *.mo. Pokud používáte nějakou vlastní metodu pro překlad určitě to bude něco z toho co nabízí Zend Framework (ZF) v Zend_Translate (pole, csv, xml – tbx, xliff, xmltm, gettext) nebo nějakou metodu založenou na databázi. Sám jsem zkusil během let většinu těchto metod a celkem se s nimi pracovalo dobře pokud se aplikace moc nerozrostla a případně pokud neměl překládat někdo kdo neuměl pracovat s prostředím ve kterém jsem pracoval.

Na Gettextu se mi líbí hlavně aplikace pro editaci poEdit. Aplikace umí parsovat zdrojové kódy pro překlad. To je asi nejlepší co moje dřívější metody nikdy neměli, gettext si najde sám co překládat a umožňuje použít už hotové překlady pro automatické překlady.

Pro práci s Gettextem potřebujete buď ZF nebo extenze pro gettext. ZF v 1.5 zatím nepodporuje množná čísla.

Ukázka použití getextu jako extenze PHP.

<?php
// Nastaveni jazyka
setlocale(LC_ALL, 'cs');
// Urcení mista prekladu
bindtextdomain("TestApp", "./lang");
// Nastaveni domeny
textdomain("TestApp");
// Preklad se hleda v souboru ./lang/cs/LC_MESSAGES/TestApp.mo
// Pro tisk je potreba pouzit tento postup
echo gettext("Vitejte v aplikaci");
// nebo pouzit alias _() pro gettext()
echo _("Vitejte v aplikaci");
?>

V ZF nemusíte tak striktně dodržovate cesty a práce s gettextem je obdobná.

<?php
// Překlad

$t = new Zend_Translate('gettext', '../lang/czech.mo', 'cs');

$t->setLocale('cs');

// tisk

echo $t->_(‘Vítejete v aplikaci’);

?>

Aplikace poEdit je podle mě asi nejznámější a teké nejlepší pro práci s Gettextem, edituje soubory zdrojové v *.po a kompiluje výsledek do *.mo při ukládání. Je potřeba jen mít správně nastavené cesty k projektu se kterým právě pracujete.

Pro práci s ZF je jen potřeba přidat pro v konfiguraci další koncovky do PHP parseru, já jsem používal překlad kromě php skriptech také v v phtml. Bez úpravy nastavení by nenašel xgettext vaše řetězce k předkladu.

Osobně se mi líbí na gettextu, že můžu mít poEdit současně otevřený s Eclipse nebo jiným editorem a překlady průběžně doplňovat a když je to větší projekt tak jednoduše to celé dělám v jednom jazyce případně v CZ, EN variantě a potom může kdokoliv lehce přeložit text do dalšího jazyka.

Zdrojáky ukázky jsou ke stažení na zip archivu.

V ZF 1.6 budou změny v Zend_Translate.

Používá někdo nějakou vlastní metodu s parsováním pro překlad textů obdobně jako to dělá getext?

Categories: php, zend framework Tags:

Zkušenosti s Zend_Auth_Adapter_Ldap

05.05.2008 View Comments

V nové verzi Zend Framework 1.5 byla do Zend_Auth přidána podpora pro LDAP. Protože u mě v práci se bez toho neobejde ani ta nejjednoduší aplikace, zkusil jsem ho a seznámím vás s problémy na které jsem narazil a jak jsem je obešel.

Nejprve standarní řešení přes Ldap modul v PHP. Něco o našem LDAPu, používáme port 1636 a pro bind vlastní DN, které kopíruje naší strukturu. Pro bind nepotřebuje aplikace žádného vlastního uživatele použije se jméno a heslo toho kdo se hlásí. Část kódu, která je podstatná pro naše porovnání.

/**
     * Autentizace proti OpenLDAP Usermap (SSU)
     * @param string $uid
     * @param string $pass
     * @return bool
     */
    private function Autentizace_LDAP($uid,$pass)
    {
        $ds = ldap_connect($this->_config->ldaphost);
        @$r = ldap_bind($ds, "cvutLoginName=$uid,ou=People,ou=usermap,o=cvut,c=cz",$pass);
        ldap_close($ds);
        if ($r)
        {
            $this->logger->info("Uspesna autentizace k LDAP ($uid)");
            return true;
        }
        else
        {
            $this->logger->error("Chyba autentizace k LDAP ($uid)");
            return false;
        }
    }

V Zendu se to řeší pomocí tohoto kódu, který je odvozen od toho v manuálu, ale musel projít úpravou v sekci $options, protože LDAP modul v Auth nějak nepočítá s tím, že nemáte uživatele pro přístup k Ldapu, což je pokud vím dost běžná situace.

class AuthController extends Zend_Controller_Action
{
    function indexAction()
    {
      $username = $this->_request->getParam('username');
      $password = $this->_request->getParam('password');
$auth = Zend_Auth::getInstance();
   $registry = Zend_Registry::getInstance();
      $config=$registry->get('config');
      $log_path = $config->ldap->log_path;
      $options = $config->ldap->toArray();
     // modifikovani options
      $options['server1']['username'] = "cvutloginname=$username,ou=People,ou=usermap,o=cvut,c=cz";
      $options['server1']['password'] = $password;
      unset($options['log_path']);
      $adapter = new Zend_Auth_Adapter_Ldap($options, $username, $password);
      $result = $auth->authenticate($adapter);
      if ($log_path)
      {
          $messages = $result->getMessages();
          $logger = new Zend_Log();
          $logger->addWriter(new Zend_Log_Writer_Stream($log_path));
          //$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
          $filter = new Zend_Log_Filter_Priority(Zend_Log::INFO);
          $logger->addFilter($filter);
          foreach ($messages as $i => $message)
          {
              if ($i-- > 1) { // $messages[2] and up are log messages
                  $message = str_replace("\n", "\n  ", $message);
                  $logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
              }
          }
      }
      // vypis
      if ($result->isValid())
      {
      $this->view->status = "You are logged-in as " . $auth->getIdentity() . "<br>\n";
      }
      else
      {
      $this->view->status = "Error. You are not logged. <a href='../../'>Please login again</a>.";
      }
    }
}

ještě moje options:

[stage]
ldap.log_path = ../logs/ldap.log;
Typical options for OpenLDAP
ldap.server1.host = usermap.cvut.cz
ldap.server1.port = 1636
ldap.server1.useSsl = true
ldap.server1.baseDn = "ou=People,ou=usermap,o=cvut,c=cz"
ldap.server1.bindRequiresDn = true
ldap.server1.accountFilterFormat = "(&(objectClass=person)(uid=%s))"

v další fázi se obvykle ještě snažíme vytáhnout některá data jako je osobní číslo podle kterého se potom pracuje s aplikací, ale to bude dobře možné až pomocí Zend_Ldap_Ext, která je zatím ve vývoji, ale můžete samozřejmě použít stávající Ldap funkce v php.

Categories: php, zend framework Tags:

Switch to our mobile site