letölthető script

Batch API: Sok feladat elvégzése Drupalban AJAX-szal.

Egy újabb Drupal gyrostipp következik.

Amikor bekapcsolunk egy új nyelvet, vagy verziófrissítés utána, amikor meglátogatjuk az update.php-t, azt láthatjuk, hogy megjelenik egy teljes képernyős AJAX-os állapotjelző sáv, un. „progress bar”. Azért hasznos ez az AJAX-os megoldás, mert ha a feladatok elvégzése 30 másodpercnél tovább tartana, a php szkript futása megszakadhat, és a feladatok elvégzése félúton megállna. Így viszont a Drupal gondoskodik, hogy néhány másodperc futás utána, a háttérben, egy új http lekérés indul, ezzel kiküszöbölve a 30 másodperces kolátot.

Most mogmutatom, hogyan tudunk mi is ilyet készíteni. Drupal-al ez is nagyon egyszerű:

A funkció lelke a Drupal magban a batch.inc-ben van elrejtve, és nekünk mindössze egyetlen függvényt, a batch_set()-et, és annak paraméterezését kell ismernünk. Ez a függvény egyetlen paramétert vár, egy tömböt. A tömbben meg lehet adni a feladatlista nevét, az elvégzendő feladatokat, amelyek php callback függvények és paramétereik, illetve a befejezéskor meghívandó callback függvény.

A példakód ilyen egyszerű:

<?php
  $batch
= array(
   
'title' => t('Helló batch feladatok'),  // a feladatlista címe
   
'operations' => array(),                // feladatok tömbje
   
'finished' => 'hellobatch_finished',    // befejezéskor meghívandó
 
);
 
  for (
$i=0; $i<$form_state['values']['jobs']; $i++) {
   
$operation = array(
     
'hellobatch_job',   // egy feladat callback fg.
     
array($i),          // és paraméterei
   
);
   
$batch['operations'][] = $operation;
  }
 
batch_set($batch);
?>

Ha mindezt egy form_submit függvényben hívjuk meg, nem is kell mást tennünk, azonnal elindul a feladatok elvégzése. Ha form submit-on kívűl akarjuk használni, akkor még a batch_process() függvényre lesz szükségünk.

További infó angulul az API oldalon.

A példamodul kódját csatolttam, próbáljátok ki!

parse_url() alternatíva

HTML-ből kiszedett url-eket dolgoztam volna fel, de a PHP beépített parse_url() függvénye egy warning kíséretében elszáll, ha relatív url-eket adunk meg.

Szintén nem tetszenek neki az olyan URI-k, mint pl. a mailto: vagy ftp://

Írtam egy függvényt, ami úgy dolgozza fel az URL-eket és URI-kat, hogy

  • soha nem száll el warning-al
  • jól kezeli a relatív URL-eket
  • teljes értékű helyettesítője a php parse_url()-nek

Itt a kód, illetve a post végén egy linken le is tölthető. Bárki bármilyen hibát talál, jelezze a hozzászólásoknál, hogy javíthassam.

<?php
function parse_url_relative($url, $component = NULL){
 
$full_rx = '!^
    (?P<scheme>[a-z][a-z0-9\+\-\.]*):/*         # scheme
    (?:(?P<user>[^:@]*)(?::(?P<pass>[^@]*))?@)? # user and password
    (?P<host>[^/\?\#:]*)                        # host
    (?::(?P<port>[0-9]+))?                      # port
    (?P<path>[^\?\#]*)                          # path
    (?:\?(?P<query>[^\#]*))?                    # query
    (?:\#(?P<fragment>.*))?                     # fragment
  $!ix'
;

 
$path_rx = '!^
    (?P<path>[^\?\#]*)                          # path
    (?:\?(?P<query>[^\#]*))?                    # query
    (?:\#(?P<fragment>.*))?                     # fragment
  $!ix'
;

  if (!
preg_match($full_rx, $url, $m)) {
   
preg_match($path_rx, $url, $m);
  }

 
$return = array(
   
'scheme'    => isset($m['scheme'])    ? $m['scheme']    : NULL,
   
'user'      => isset($m['user'])      ? $m['user']      : NULL,
   
'pass'      => isset($m['pass'])      ? $m['pass']      : NULL,
   
'host'      => isset($m['host'])      ? $m['host']      : NULL,
   
'port'      => isset($m['port'])      ? $m['port']      : NULL,
   
'path'      => isset($m['path'])      ? $m['path']      : '',
   
'query'     => isset($m['query'])     ? $m['query']     : '',
   
'fragment'  => isset($m['fragment'])  ? $m['fragment']  : '',
  );

  switch (
$component) {
    case
NULL:
      return
$return;
    case
PHP_URL_SCHEME:
      return
$return['scheme'];
    case
PHP_URL_HOST:
      return
$return['host'];
    case
PHP_URL_PORT:
      return
$return['port'];
    case
PHP_URL_USER:
      return
$return['user'];
    case
PHP_URL_PASS:
      return
$return['pass'];
    case
PHP_URL_PATH:
      return
$return['path'];
    case
PHP_URL_QUERY:
      return
$return['query'];
    case
PHP_URL_FRAGMENT:
      return
$return['fragment'];
  }
}
?>

Karakter alapú szöveg-összehasonlítás PHP-vel

Tartalom

Bevezető

Készülve a csütörtöki diplomavédésre, megnéztem a bíráló által feltett kérdéseket. Diplomatervem egy adatbázis séma alapú PHP kódgenerátor. (Később majd írok erről egy részletes post-ot.) A bíráló egyik kérdése volt, hogy a generált forráskód hány százalékát kell átírni egy valós környezetben.

Ez egy nagyon jó kérdés, bennem is felmerült már. Forráskód bázis rendelkezésre áll, úgyhogy van kód amin meg lehet mérni. Első ötlet lehet a diff parancs. De ebben az esetben problémás lehet, hogy a diff soronként vizsgálja a forráskódot. Ez két dolog miatt gond:

  • A generált kódban vannak felesleges blokkok, amelyeket nem töröltem hanem a // jelekkel kommenteztem ki.
  • Minden táblához létrejön egy konfigurációs fájl, amelynek az a célja, hogy testreszabáskor módosítsák. Minden sorát!

Ez a két eset nagyon gyakori, ezért a soronként összehasonlítás alapján megítélni a forráskód-generátor jóságát félrevezető lenne.

Egy karakter alapú összehasonlítás ennél sokkal pontosabb információt adna. Kicsit kutattam az interneten és találtam egy megoldást, amit kicsit átírva született a lenti kód.

Karakter alapú szöveg-összehasonlító PHP szkript

A lenti szkript definiál egy CharDiff osztályt, amit a PEAR Text_Diff csomagban található Text_MappedDiff osztályból öröklődik. A Text_MappedDiff pedig a Text_Diff-ből öröklődik, tehát a lenti osztály egyben Text_Diff osztályú is. Ez azért jó, mert a fent említett csomagban van jónéhány renderer, amelyekkel különböző szabványos patch kimeneteket lehet generálni.

De szerettem volna vizualizálni is a dolgot, ezért az osztály része egy render metódus ami HTML kimenetet ad, és grafikusan ábrázolja a a különbséget a két szöveg között.

Eredeti kód: www.hawkee.com

Íme a kód, CharDiff.php:

<?php
/**
* Karakter alapú szövegösszehasonlító
* -----------------------------------
* Használat:
* $text1 = 'árvíztűrő tükörfúrógép';
* $text2 = 'árvíztörő tükörfúrógép';
*
* $diff = new CharDiff($text1, $text2);
*
* $diff->render();
*/

require_once 'Text/Diff.php';

class
CharDiff extends Text_MappedDiff {

  function
CharDiff ($text_src, $text_tgt) {

   
$chars_src = str_split($text_src, 1);
   
$chars_tgt = str_split($text_tgt, 1);

   
$chars_src_mapped = $chars_src;
   
$chars_tgt_mapped = $chars_tgt;

     
parent::Text_MappedDiff($chars_src, $chars_tgt, $chars_src_mapped, $chars_tgt_mapped);
  }

  function
getStat() {
   
$stat = array();

   
$stat['copy']  = 0;
   
$stat['add']  = 0;
   
$stat['del']  = 0;
   
$stat['change']  = 0;
   
$stat['change-del']  = 0;
   
$stat['change-add']  = 0;

    foreach(
$this->getDiff() as $op) {
      if (
is_a($op, 'Text_Diff_Op_copy')) $stat['copy'] += $op->norig();
      if (
is_a($op, 'Text_Diff_Op_delete')) $stat['del'] += $op->norig();
      if (
is_a($op, 'Text_Diff_Op_add')) $stat['add'] += $op->nfinal();
      if (
is_a($op, 'Text_Diff_Op_change')) { $stat['change-del'] += $op->norig(); $stat['change-add'] += $op->nfinal(); }
    }

    return
$stat;
  }

  function
render($color_delete = 'red', $color_add = 'green') {
    foreach (
$this->getDiff() as $op) {
      if (
is_a(&$op,'Text_Diff_Op_copy')) {
        echo
$this->_implode($op->final);
      }
      elseif (
is_a(&$op,'Text_Diff_Op_delete')) {
        echo
'<span style="background-color: ', $color_delete, ';">', $this->_implode($op->orig), '</span>';
      }
      elseif (
is_a(&$op,'Text_Diff_Op_add')) {
        echo
'<span style="background-color: ', $color_add.';">', $this->_implode($op->final), '</span>';
      }
      elseif (
is_a(&$op,'Text_Diff_Op_change')) {
        echo
'<span style="background-color: ', $color_delete.';">', $this->_implode($op->orig), '</span>';
        echo
'<span style="background-color: ', $color_add.';">', $this->_implode($op->final), '</span>';
      }
    }
   
    return
$return;
  }

  function
_implode($chars) {
    return
nl2br( implode('', array_map( array($this, '_htmlFilter'), $chars) ) );
  }

 
// used with array_map
 
function _htmlFilter($text) {
    return
$text = str_replace( array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $text);
  }

}
?>

A feneti kód letölthető itt: CharDiff.php

Az osztály használata:

<?php
  $text1
= 'árvíztűrő tükörfúrógép';
 
$text2 = 'árvíztörő tükörfúrógép';

 
$diff = new CharDiff($text1, $text2);

 
$diff->render();
?>

Remélem lesz aki hasznosnak találja majd.