Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: singles, dodany: 14.04.2011 00:30, tagi: javascript

Devmeetings to seria warsztatów dla software developerów, podczas których w ciągu kilkunastu godzin powstaje kilka wersji tej samej (niebanalnej!) aplikacji napisanej przez kilka grup. Każde szkolenie posiada swój temat przewodni i jest prowadzone przez wykwalifikowanego specjalistę. Miałem okazję uczestniczyć już w dwóch takich, dlatego z przyjemnością informuje o następnym evencie z tej serii – mianowicie JavaScript na serwerze: RingoJS, V8CGI i NodeJS.

Szkolenie poprowadzi David de Rossier. Więcej informacji na jego temat znajdziecie na stronie Devmeetings.pl, ja dodam tylko, że miałem okazję posłauchać wykładu przez niego prowadzonego. David zdecydowanie jest pasjonatem – widać to po sposobie w jaki opowiada, czy też w jaki sposób wyjaśnia zagadnienia. Dodatkowo – ma bardzo dobry kontakt ze słuchaczami.

Tak więc od siebie szkolenie to jak najbardziej polecam – same plusy:

  • jest darmowe
  • ciekawy temat (zwłaszcza dla PHPowców, którzy głownie pracują po stronie backendu)
  • świetny klimat
  • ogrom wiedzy
  • kilka możliwych lokalizacji.
  • niespodzianki ;)

Liczba miejsc jest ograniczona! Dokładniejsze informacje znajdziecie na stronie Devmeetings.pl, a mi nie pozostaje nic innego jak zaprosić Was do Poznania 14 maja, gdzie i ja planuje się pojawić. Jestem przekonany, że nie pożałujecie :)

Autor wpisu: Tomasz Kowalczyk, dodany: 12.04.2011 23:08, tagi: php

Dzisiejszy wpis po raz kolejny [poprzednio pisałem o flagach bitowych] zabiera nas w świat manipulacji niskopoziomowymi danymi, odzierając nieco PHP z jego wygodnej, wysokopoziomowej abstrakcji. Skupimy się w nim na wewnętrznym sposobie reprezentacji liczb i odczytywaniu informacji o wartościach ich kolejnych bajtów. Fotografia: Nic McPhee, CC-BY-SA. Wstęp: Liczby. Liczby w PHP można przedstawić na wiele [...]

Autor wpisu: Tomasz Kowalczyk, dodany: 10.04.2011 22:02, tagi: css

W sieci znajduje się dosyć dużo materiałów dotyczących możliwości języka CSS w wersji trzeciej. Zapraszam do zapoznania się z listą tych najciekawszych, zebranych specjalnie dla Czytelników niniejszego blogu. Fotografia: growdigital, CC-BY. Linkdump: CSS3. 1. CSS3 3D Slideshow. Przesuwające się slajdy w CSS. 2. Creating a Slideshow using CSS3 3D Transforms. Tworzenie prezentacji opartej na slajdach [...]

Autor wpisu: Śpiechu, dodany: 10.04.2011 19:54, tagi: php, mysql

Tytuł zabrzmiał jak w Matriksie. Chodzi oczywiście o łączenie aplikacji PHP z bazą danych. Dzisiaj pokażę w jaki sposób w niewielkich projektach radzę sobie z przygotowaniem obiektu PDO do pracy z bazą danych. Trudno żebym w niewielkiej „stronce” zaprzęgał jakiś Zend Framework.

Napisałem sobie dawno temu klasę narzędziową do tworzenia obiektu PDO. Implementuję w niej wzorzec projektowy singleton, a więc mam pewność, że gdziekolwiek w kodzie żądam PDO, zawsze dostaję ten sam obiekt. Jeżeli chodzi o sam singleton, to na jego temat można przeczytać zarówno we Wzorcach Projektowych1 jak i w Design Patterns.2 Zresztą to w Googlu wyskoczy pierdylion wyników ;-)

Używanie klasy jest dziecinnie proste. Należy sobie jednorazowo przeedytować stałe klasy dotyczące połączenia z bazą, a następnie w kodzie wywoływać metodę DBHandler::getPDO()

Poniżej podaję kod klasy. Bierzcie i jedzcie ;-)

<?php
class DBHandlerException extends PDOException {
}
 
/**
 * @author Dawid 'Spiechu' Spiechowicz
 * @license see http://spiechu.pl/o-publikowanym-kodzie/
 */
class DBHandler {
 
  /**
   * Dane bazy danych
   */
  const DB_HOST = 'localhost';
  const DB_NAME = 'nazwa bazy';
  const DB_USER = 'nazwa usera';
  const DB_PASS = 'haslo';
 
  /**
   * Sterownik bazy danych
   */
  const DB_DRIVER = 'mysql';
 
  /**
   * Czy wyswietlac dokladne komunikaty bledow
   */
  const DEBUG_MODE = true;
 
  /**
   * @var PDO singleton PDO
   */
  private static $pdo = null;
 
  /**
   * Zwraca singleton PDO lub wyswietla komunikat bledu i zwraca null.
   * @return PDO|null
   */
  public static function getPDO() {
    try {
      if (self::$pdo === null) {
        self::$pdo = self::createPDO();
      }
      return self::$pdo;
    }
    catch (DBHandlerException $e) {
      echo $e->getMessage();
      return null;
    }
  }
 
  /**
   * @return PDO zwraca nowa instancje PDO
   * @throws DBHandlerException
   */
  private static function createPDO() {
    if (!extension_loaded('PDO')) throw new DBHandlerException('Brak modulu PDO');
    try {
      $pdo = new PDO(
         self::DB_DRIVER . ':host=' . self::DB_HOST . ';dbname=' . self::DB_NAME, 
         self::DB_USER, 
         self::DB_PASS,
         array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
      return $pdo;
    }
    catch(PDOException $e) {
      if (self::DEBUG_MODE == true) {
        throw new DBHandlerException("Blad bazy danych : {$e->getMessage()}");
      }
      else {
        throw new DBHandlerException('Blad bazy danych');
      }
    }
  }
 
  /**
   * Zapobiega tworzeniu obiektu.
   */
  private function __construct() {
    throw new Exception('Nie mozna stworzyc tego obiektu!');
  }
 
  /**
   * Zapobiega klonowaniu obiektu.
   */
  private function __clone() {
    throw new Exception('Nie mozna klonowac tego obiektu!');
  }
}

Powyżej widać kilka sztuczek. Przede wszystkim konstruktor ma zasięg prywatny, co zapobiega stworzeniu instancji klasy z zewnątrz. Mało tego, próba wywołania go z wnętrza klasy spowoduje wyrzucenie wyjątku. To samo z metodą __clone().

Przy konfiguracji obiektu PDO ustawiam tryb błędów na wyjątki, które wyłapuję i w zależności od ustawionej stałej DEBUG_MODE wyświetlam komunikaty błędów PDO lub nie. Fragment $pdo->query('SET NAMES utf8') ustawia kodowanie znaków na Unicode. Niestety nie znalazłem lepszej metody. Rezultaty zapytań domyślnie będą dostępne w postaci tablicy asocjacyjnej.

  1. E. Gamma (i in.) : Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku. Gliwice : Helion, 2010, s. 130–136.
  2. E. Freeman (i in.) : Head First Design Patterns. Gliwice : Helion, 2005, s. 197–216.

Autor wpisu: singles, dodany: 09.04.2011 23:18, tagi: php, zend_framework, doctrine

Zend Framework składa się z wielu komponentów, a jednym z nich jest ten odpowiedzialny za komunikację z bazą danych – Zend_Db. Jednakże, celem tego wpisu nie jest opisywanie Zend_Db – to zostało zrobione już w dokumentacji. Celem tego wpisu jest wyrażenie mojej opinii na temat tego co mi się w Zend_Db podoba, a co nie – jest to oczywiście wpis czysto subiektywny. Traktuje ten wpis także jako przyczynek do dyskusji na temat, czy Zend_Db jest naprawdę tak złym komponentem, za jakiego ma go wielu programistów PHP – m.in patrz komentarze do wpisu u batmana. Chciałbym się także odnieść do podanych tam „zarzutów”. Niektóre z przedstawionych przeze mnie zalet bądź wad mogą Wam się wydawać śmieszne bądź banalne, ale kilka takich rzeczy połączonych ze sobą wpływa na wygodę korzystania z danego rozwiązania. Tak więc zaczynamy!

Zalety

Oparty głównie na PDO

Coraz więcej frameworków idzie tą drogą, co uważam za niewątpliwy plus. PDO de facto jest standardem w PHP i bardzo dobrze, że twórcy zdecydowanej większości frameworków się tego trzymają. Dzięki temu, kiedy przychodzi potrzeba napisania bardziej zaawansowanego zapytania możemy skorzystać ze znanych nam metod i oczekiwać tego samego, czego oczekiwaliśmy korzystając z czystego PDO.

Wygoda podczas stosowania klauzuli WHERE

Kwestia oczywiście w pełni subiektywna. Mam na myśli korzystanie głównie z metody fetchAll i automatycznego bindowania parametrów jako odpowiedni typ danych. Przykład:

$model->fetchAll(array(
    'item_id = ?' => 12, //bind as PDO::PARAM_INT, cast it using (string)12 to automatically bind as PDO::PARAM_STR
    'name = ?' => 'foobar', //PDO::PARAM_STR
    'category_id IN (?)' => arrray(1, 2, 4, 7) // bind each array element separately as PDO::PARAM_INT -> gives you: category_id IN (?, ?, ?, ?)
));

Stosunkowo mała liczba plików

Zend_Db w obecnej wersji frameworka (1.11.5) waży ok. 600KB i mieści się w 53 plikach – z czego 17 z nich to puste klasy wyjątków Exception.php. Dla porównania – Doctrine2 DBAL (czyli sama warstwa abstrakcji bazy danych) to 144 pliki, w tym 10 od wyjątków. Oczywiście, w obu przypadkach można te liczby jeszcze bardziej zmniejszyć, wyrzucając niepotrzebne adaptery.

ActiveRecord

Podoba mi się fakt, że mogę zdefiniować własne metody odnoszące się bezpośrednio do rekordu O ile twórcy ZF piszą o Zend_Db_Table_Row jako o implementacji Row Data Gateway, jednakże z punktu widzenia używającego go programisty niedaleko mu do ActiveRecord. Mam na myśli możliwość definiowania własnych metod odnoszących się do konkretnego rekordu. Banalny przykład:

// /application/models/Product.php
class Model_Product extends Zend_Db_Table_Abstract
{
    protected $_name = 'product';
    protected $_rowClass= 'Model_ProductRow'; //use Model_ProductRow instead Zend_Db_Table_Row
}
 
// application/models/ProductRow.php
class Model_ProductRow extends Zend_Db_Table_Row_Abstract
{
    public function getPriceWithTax()
    {
        return $this->price * 0.23; //where price is column in database defining price without VAT tax rate
    }
}

To samo tyczy się obiektów kolekcji – w przypadku Zend Frameworka dziedziczących po klasie Zend_Db_Table_Rowset. Mogę ustawić własną klasę, gdzie zaimplementuje potrzebne mi metody kolekcji.

Wspracie dla interfejsów ArrayAccess oraz Iterable w przypadku obiektów i kolekcji

Kolejna rzecz, która wpływa na wygodę. Mogę odnosić się do właściwości obiektu używając notacji tablicowej. Mogę także iterować po obiekcie kolekcji używając foreach, bez wykonywania za każdym razem toArray().

Zend_Db_Select == QueryBuilder

O ile na początku korzystanie z Zend_Db_Select sprawiało mi sporą trudność (moim kolegom z zespołu także), tak po pewnym czasie jest to dla nas natywny sposób pisania bardziej skomplikowanych zapytań podczas korzystania z ZF. Właśnie dzięki jego obiektowej naturze i wykorzystaniu fluent interface mogę dowolnie łączyć warunki zapytania bądź zmieniać je korzystając z metody reset(). Przykład:

class Model_Foo extends Zend_Db_Table_Abstract
{
    private $_name = 'foo';
 
    // use fluent interface and add condition
    public function fetchWithLeftJoinWhereBarIsntNull()
    {
        $select = $this->_getBaseSelect();
        $select->where('bar IS NOT NULL');
        return parent::fetchAll();
    }
 
    // user reset() and remove LEFT JOIN
    public function fetchWithoutLeftJoin()
    {
        $select = $this->_getBaseSelect();
        $select->reset(Zend_Db_Select::LEFT_JOIN);
        return parent::fetchAll($select);
    }
 
    private function _getBaseSelect()
    {
        $select = $this->select();
        $select->from('table1')
               ->setIntegrityCheck(false) // allow to join another tables
               ->joinInner('table2', 'table1.id = table2.table1_id')
               ->joinLeft('table3', 'table1.id = table3.table1_id');
 
        return $select;
    }
}

Wady

Brak nazwanych relacji

O używaniu relacji w Zend Framework pisał już batman we wpisie Zend_Db i relacje. Jednak mi nie odpowiada fakt, że korzystając domyślnej metody opisywanej praktycznie wszędzie muszę odnosić się do rekordów podrzędnych po nazwie klasy, a nie nazwie zdefiniowanej relacji. Chciałbym, abym mógł napisać tak:

$params = $userRow->findDependentRowset('UserParamsRelationWithCustomName'); //instead of specifying model class

Nazwa klasy zawsze może się zmienić, a to ułatwia refactoring. Dodatkowo, chciałbym móc w ramach relacji zdefiniować dodatkowe parametry dotyczące połączenia – nie tylko kolumnę, po jakiej ma się ono odbyć, ale także warunki do kolumn dodatkowych. Istnieje co prawda Zend_Db_Table_Definition, jednak rozwiązanie to ma dwie wady. Po pierwsze wymaga osobnej definicji dla każdej klasy modelu, co jest niewygodne. Po drugie, nadal nie pozwala na definiowanie dodatkowych warunków dla połączeń.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Tomasz Kowalczyk, dodany: 08.04.2011 18:46, tagi: symfony, framework, php

Realizuję w tym momencie bardzo przyjemny projekt - przyjemny dlatego, że powstaje "od zera" i mam możliwość wyboru narzędzi, w jakich będę go tworzył. Chciałem spróbować wykorzystać do tego testowany od pewnego czasu framework Symfony2, jednak idąc za radą udzieloną mi przez batmana podczas konferencji 4Developers wracam na "stare śmieci", czyli stabilną wersję symfony. Jak [...]

Autor wpisu: sokzzuka, dodany: 08.04.2011 13:50, tagi: php

Pewnie kilka razy w życiu każdy z nas zetknął się albo i też używał operatora trójargumentowego znanego też jako „ternary operator” bądź „operator Elvisa” (skrócona wersja w Groovym, ciekawe kto wymyślił tą nazwę). Jest to skrócona składnia dla prostego przypadku „if” i wygląda on mniej więcej tak:

$foo = 5;
$bar = ($foo==5) ? "Foo równa się 5" : "Foo nie równa się 5";
echo $bar;

Najczęściej chyba operatora Elvisa używa się by sprawdzić czy jakaś zmienna jest ustawiona, czyli:

$bar = (isset($foo)) ? $foo : 666;
echo $bar; //666

Ostatnio na grupie php.internals toczy się dyskusja czy aby nie uczynić drugiego przypadku domyślnym tj:

$bar = $foo ? $foo: 666;
echo $bar; //666

Dzięki takiej zmianie jest krócej o te kilka uderzeń w klawiaturę by ustawić domyślna wartość jakiej zmiennej. Jest zarówno wielu zwolenników jak i przeciwników tej zmiany. Najważniejsze jednak jest, że Rasmus Lerdorf (BDFL php) uważa, że nie należy zmieniać już istniejącego zachowania ponieważ zrywa to wsteczną kompatybilność kodu. Wobec tego, zaproponowany został kolejny operator w postaci „??” mający to samo zastosowanie co poprzedni oprócz tego, że sprawdza tylko, czy jakaś wartość istnieje:

$value = $a[$key] ?? : 'Not set';

Niektórych też już poniosła fantazja i zaproponowali wersję:

$value = 'Not set' unless $a['key'];

Ciekaw jestem, czy często używacie operatora trójargumentowego, oraz jakie macie zdanie nt. ww. propozycji ?

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.