CakePHP: Usuwanie rekurencyjne (kaskadowe)

Jeżeli chcemy skasować rekord z bazy danych, wraz z wszystkimi powiązaniami rekordami z innych modeli wystarczy ustawić odpowiednie parametry w modelu(dla danego powiązania dependent = true a następnie wywołać metodę delete() na modelu. Nazwijmy to usuwanie rekurencyjne, lub usuwanie kaskadowe. Załóżmy, że mamy model User, który posiada powiązanie hasOne z modelem Account, hasAndBelongsToMany z modelem Tag, oraz powiązanie hasMany z modelem Photo. Dodatkowo model Account posiada powiązanie hasMany z modelem Information. Pomijam powiązanie belongsTo, gdyż nie wyobrażam sobie sytuacji, że chcemy usunąć model z takim powiązaniem. Nasze modele wyglądają następująco.

class User extends AppModel {
  var $hasOne = array('Account');
  var $hasMany = array('Photo');
  var $hasAndBelongsToMany = array('Tag');
}
 
class Account extends AppModel {
  var $hasMany = array('Information');
}

Wywołując w kontrolerze users $this->User->delete($id); skasujemy rekord z modelu User oraz wszystkie rekordy z tabeli tags_users, czyli z tabeli łączącej model User z modelem Tag. Dzieje się tak dlatego, że relacje HABTM są domyślnie zależne od siebie. Co zrobić aby skasować powiązanie rekordy z modeli Account, Photo, Information? Wystarczy określić, że modele są zależne od siebie. Nasze modele wyglądają teraz następująco.

class User extends AppModel {
  var $hasOne = array('Account' => array('dependent' => true));
  var $hasMany = array('Photo' => array('dependent' => true));
  var $hasAndBelongsToMany = array('Tag');
}
 
class Account extends AppModel {
  var $hasMany = array('Information' => array('dependent' => true));
}

Tak określone modele tworzą zależności pomiędzy modelami. Kasując użytkownika kasujemy wszystkie jego zdjecia, konto, oraz informacje należące do konta. Bardzo prosta i przydatna procedura.

PHP: zmienne zmiennych – zmienne dynamiczne

Spotkałem się ostatnio z problemem dostępu do zmiennej w PHP, której nazwa nie jest znana do chwili uruchomienia skryptu. Rozwiązanie okazuje się banalne. Dla przykładu załóżmy że chcemy wyświetlić zmienną o nazwie $nieznana_nazwa. Należy skorzystać z następującej składni.

$name = 'nieznana_nazwa';
echo ${$name};

Jest to równoznaczne z napisaniem echo $nieznana_nazwa. Sytuacja kiedy nie znamy nazwy zmiennej nie wydaje się częsta, istnieje prawdopodobnie milion innych sposobów aby to obejść, np. skorzystać z tablicy. Ten sposób wydaje się ciekawy, dlatego nie chciałbym o nim zapomnieć. 😉

CakePHP: Linki w array

Dzisiaj krótki, ale bardzo przydatny wpis dotyczący tworzenia linków w CakePHP za pomocą tablic.
Na początek przedstawię ideę linków w array. W szablonach strony możemy tworzyć odnośniki w zwyczajny sposób, ale korzystanie z tablic niesie za sobą liczne korzyści, w szczególności jeśli chcemy korzystać z funkcjonalności reverse routing. Pozwala to na łatwe, szybkie i sprawne operowanie linkami. Nie musimy się martwić „treścią” linku, a jedynie kontrolerem/akcją jaką mamy obsłużyć, oraz danymi jakie chcemy przekazać.
W ogóle struktura linków wygląda następująco:

<?php echo $html->link(
    'Tekst linku',
    array('controller'=>'nazwa_kontrolera', 'action'=>'akcja', id),
    array('class'=>'klasa1','inny_atrybut_html'=>'jakaś_wartość'),
    "Komunikat pytający czy chcieliśmy kliknąć w link?"
);?>

Wymagane są oczywiście tylko pierwsze dwa parametry. Pierwszy parametr to treść linku, tekst który widzi użytkownik. Parametr nr 2 to jest „Nasz” array, zawiera on informacje najistotniejsze czyli nazwę kontrolera oraz akcję do której kieruje link. Możemy również podać id które CakePHP przekazuje do akcji. Aby zobaczyć korzyści płynące z tego rozwiązania ponownie odsyłam do wpisu o przyjaznych linkach. Parametr nr 3 to atrybuty html, np. class, id. Parametr nr 4 to javascript’owy komunikat pytający czy aby na pewno chcieliśmy kliknąć w link. Mówiąc fachowo ostatni parametr dodaje do linku onclick="confirm("Nasza wiadomość");".

W celu zgłębienia wiedzy odsyłam do:
1. Cookbook
2. API 1.3

CakePHP: Przyjazne linki

Tak jak obiecywałem, postanowiłem napisać małą serię artykułów o CakePHP, w wersji 1.3, chociaż znaczna większość ma identyczne zastosowanie w wersji 1.2. Zacznę od wyjaśnienia się co to są przyjazne linki, znane szerzej jako Search Engine Friendly URLs.

Przyjazne linkowanie służy głównie do lepszego indeksowania naszej strony przez wyszukiwarki internetowe, np. Google. Efekt uboczny to taki, że linki lepiej oddają swoją treść. Najlepiej pokazać to na przykładzie.
Tutaj mała dygresja, w każdym z artykułów zakładam, że Czytelnik jest zapoznany z podstawami CakePHP, jeżeli tak nie jest to odsyłam do najlepszego źródła: CakePHP Cookbook. Dodatkowo, trzymam się konwencji angielskiego nazewnictwa.
Załóżmy, że mamy kontroler Posts, i model Post, który jest oczywiście postem, bądź w moim przypadku artykułem. Nie pytajcie dlaczego nie nazwałem tego Article. 😉 Chcąc stworzyć link do konkretnego artykułu, w kontrolerze tworzymy metodę view. Zapełniamy ją dość oczywistym kodem:

$this->Post->id = $id;
$post = $this->Post->find('first');
$this->set('post', $post);

Stosujemy find, zamiast read, gdyż nie ma potrzeby zapełniać kontroler danymi. Teraz możemy utworzyć widok naszego artykułu, dla naszego przykładu wystarczy najprostszy z możliwych:

<?php echo $post['Post']['body']; ?>

Teraz możemy się odwołać do Naszego artykułu poprzez link: http://localhost/posts/view/1. Oczywiście jest to link, który kompletnie nic nie mówi użytkownikowi o treści jakiej prezentuje, oraz nie jest przyjazny dla wyszukiwarek. W moim przypadku chciałem osiągnąć następującą postać linku: http://localhost/artykul/id_artykulu-tytul_artykulu. Aby to osiągnąć musimy skorzystać z router’a CakePHP.

Otwieramy plik /app/config/routes.php. W tym pliku będzie się dziać cała magia. Robiąc to krok po kroku, najpierw chcemy uzyskać postać http://localhost/artykul/id. Osiągamy to poprzez dodanie następującego kodu:

Router::connect(
        '/artykul/:id',
        array(
            'controller' => 'posts',
            'action' => 'view'),
        array(
            'pass' => array('id'),
            'id' => '[0-9]+'
        )
);

Zakładamy tutaj, że pole id przyjmuje wartości numeryczne. Chcąc uzyskać postać końcową zamieniamy ten fragment kodu na następujący:

Router::connect(
        '/artykul/:id-:slug',
        array(
            'controller' => 'posts',
            'action' => 'view'),
        array(
            'pass' => array('id', 'slug'),
            'id' => '[0-9]+',
            'slug'=>'.+'
        )
);

Teraz pojawia się pytanie, jak z poziomu CakePHP uzyskać następujące linki. W widoku w którym chcemy wyświetlić link piszemy:

<?php echo $html->link('Link',
   array(
      'controller' => 'posts',
      'action' => 'view',
      'id'=>$id,
      'slug'=>$slug
   )
); ?>

Część z Was może się spytać co to jest to tajemnicze $slug. Jest to krótki ciąg znaków, najlepiej oddający treść linka. Nie może zawierać spacji, ani znaków specjalnych; zamieniamy je najlepiej na myślnik. Dodatkowo slug jest zoptymalizownay pod względem SEO. W Naszym przypadku najlepszym kandydatem na slug‚a będzie tytuł artykułu. Musimy go jednak odpowiednio obrobić. Na szczęście CakePHP posiada do tego odpowiednie narzędzie.
Posługujemy się metodą Inflector::slug('tytuł pierwszego artykułu','-');. Pierwszy argument to ciąg znaków do ‚oczyszczenia’, a kolejny to znak, na jaki zamieniamy znaki niedozwolone. Wynikiem będzie tytuł-pierwszego-artykułu. Nie jest to do końca poprawne, nie możemy posługiwać się znakami specjalnymi w adresie, jest to niezgodne z formatem URI. Niestety na dzień dzisiejszy CakePHP w wersji 1.3 nie zamienia znaków diaktrycznych na ich łacińskie odpowiedniki. Aby dodać taką funkcję, możemy stworzyć własną funkcję do tego celu, bądź też dokonać zmiany w pliku /cake/libs/inflector.php. Zmiany dokonujemy w metodzie slug, zamieniając wartość zmiennej $default na:

$default = array(
        '/?|á|?|â|ą/' => 'a',
        '/?|é|?|?|ë|ę/' => 'e',
        '/?|í|î/' => 'i',
        '/?|ó|ô|?|ó/' => 'o',
        '/?|ú|ů|?/' => 'u',
        '/ç|ć/' => 'c',
        '/ł/'=>'l',
        '/ś/'=>'s',
        '/?|ń/' => 'n',
        '/ż|ź/'=>'z',
        '/ä|?/' => 'ae',
        '/ö/' => 'oe',
        '/ü/' => 'ue',
        '/Ä/' => 'Ae',
        '/Ü/' => 'Ue',
        '/Ö/' => 'Oe',
        '/ß/' => 'ss',
        '/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
        '/\\s+/' => $replacement,
        sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
);

Spowoduje to poprawne tworzenie slugów z polskimi znakami. Musimy jednak pamiętać o dokonywanie takiej modyfikacji przy każdej aktualizacji CakePHP. Liczę na to, że w przyszłych wersjach ta funkcjonalność będzie w oficjalnych źródłach. Odpowiedni ticket został już złożony. 😉 Pozdrawiam i mam nadzieję, że się przyda.

Wyśrodkowywanie w pionie

1. Wprowadzenie

Dzisiaj zajmiemy się technikami wyśrodkowania elementów strony w pionie. Użyjemy do tego celu styli CSS. Zacznijmy od przypadku wręcz trywialnego.

2. Elementy tabeli

Mając tabelę wystarczy do danej komórki(lub całej tabeli) dodać: vertical-align:middle

Przykład zastosowania:

<table>
   <tr>
      <td style="border:2px solid #c33333;height:50px;vertical-align:middle">
         <p>Przykładowy tekst</p>
      </td>
   </tr>
</table>

3. Element o znanej wysokości

Aby skorzystać z tej metody, element który chcemy wyśrodkować musi mieć znaną nam wysokość. Element, który chcemy wyśrodkować otaczamy elementem blokowym z własnościąposition: relative co sprawi, że elementy wewnątrz tego bloku będą się pozycjonować względem tego elementu; sam element natomiast bottom:0;margin:auto;position:absolute;top:0. Zobaczmy jak to wygląda w praktyce.

<div style="border:2px solid #c33333;height:200px;position:relative;width:200px">
   <p style="bottom:0;height:20px;margin:auto;position:absolute;top:0">Przykładowy tekst</p>
</div>

4. Pojedyncza linia

Jeśli mamy do wyśrodkowania element, który mieści się w jednej linii to polecam skorzystanie z tej metody. Polega ona na tym, że elementowi nadrzędnemu nadajemy style CSSline-height: xxpx;, gdzie „xx” to wysokość elementu.

<div style="line-height:50px;border:2px solid #c33333;">
    <p>tekst</p>
</div>

5. Używanie marginesów

Metoda najczęściej używana, polega na odpowiednim ustawieniu marginesów, musimy znać wysokość elementu, którego chcemy wyśrodkować. Dla naszego przykładu załóżmy, że chcemy wyśrodkowaćparagraf o wysokości 20px w elemencie blokowym o wysokości 40px.

<div style="line-height:50px;border:2px solid #c33333;"><p>tekst</p></div>

W skrócie mówiąc, jeśli mamy element o wysokości (height) 20px, zawarty w elemencie o wysokości 40px, to aby był wyśrodkowany w pionie musi mieć 10 pikseli wolnej przestrzeni na gorze i dole. Uzyskujemy to wpisując stylmargin-top:xxpx co sprawi, że nasz element będzie odsunięty od nadrzędnego elementu o 10px. Metoda ta jest najczęściej stosowana w przypadku statycznych elementów strony.