Workery w CodeIgniter

Workery to bardzo poręczne rozwiązanie, które pozwala nam na przyspieszenie działania naszego serwisu. Wszystko przez to, że niektóre zadania mogą być przez nas oddelegowane do procesu, który działa w tle. Dzięki temu, użytkownik nie będzie musiał czekać np. aż faktycznie jakiś email zostanie wysłany. Wystarczy, że taki email zostanie zakolejkowany do wysłania. W ten sposób, nasze aplikacje mogą działać bardziej płynne – bez niepotrzebnego oczekiwania na dłuższe procesy.

Read moreWorkery w CodeIgniter

Elixir, czyli wygodne zarządzanie assetami

Elixir to bardzo przyjemna nakładka na Gulp, która sprawia, że zarządzanie naszymi assetami staje się o wiele prostrze i przyjemniejsze. Możemy w bardzo łatwy sposób łączyć, minifikować oraz wersjonować nasze statyczne pliki. Używasz Less, Sass, CoffeeScript lub chcesz czerpać garściami z dobroci EcmaScript 6? Nie ma sprawy. Elixir ma to wszystko w małym palcu.

Read moreElixir, czyli wygodne zarządzanie assetami

Testy z Codeception w CodeIgniter

Kiedyś wspominaliśmy już o tym czemu warto pisać testy dla swoich aplikacji. Dzisiaj chciałbym pokazać, jak można zintegrować CodeIgniter z Codeception. Czym jest Codeception? W uproszczeniu można powiedzieć, że to taki „kombajn” do testów – dzięki czemu możemy przeprowadzać różne rodzaje testów (jednostkowe, funkcjonalne i akceptacyjne). Mam nadzieję, że brzmi to zachęcająco.

Read moreTesty z Codeception w CodeIgniter

Dobre praktyki programistyczne – Testy Jednostkowe

Ponieważ pracuję z programistami i z kodem już ponad 10 lat, pomyślałem sobie że warto opisać trochę dobrych praktyk programistycznych. Oczywiście niektóre pochodzą z moich przyzwyczajeń i opinii, niektóre udało mi się nabyć od moich szacownych kolegów które wynieśli je zachodnich firm (Nokia & Siemens).

Jest to pierwszy artykuł z serii, które postaram się tutaj opublikować. Oczywiście w ramach dostępnego czasu.

Przekonany też jestem, że pojawią trole które napiszą „jesteś głupi i się znasz” – ale chciałbym  żeby poparte było to otwartą konstruktywną dyskusją. Tutaj, lub na forum.

Zaczynamy… Na pierwszy ogień – Testy Jednostkowe zwane w oryginale: Unit Testing

Read moreDobre praktyki programistyczne – Testy Jednostkowe

Git Deployment i CodeIgniter

Dzisiaj chciałbym Wam przedstawić w jaki sposób możemy sobie skonfigurować projekt, tak aby łatwo nam się współpracowało z repozytorium Git. Czym jest Git? W skrócie ujmując, jest to system kontroli wersji. Jeśli nie mieliście jeszcze z nim do czynienia, to zapraszam np. na Wikibooks, gdzie możecie uzupełnić swoją wiedzę w tym zakresie. Nie oczekujcie więc, jakiegoś specjalnego wprowadzenia do Git, ponieważ będę zakładał, że macie o tym jakieś pojęcie – tak więc przedstawione zostaną raczej tylko „suche” komendy. Dodatkowo zakładam, że Git jest już zainstalowany na Waszym komputerze (oraz skonfigurowany). Jeśli chcielibyście poznać Gita, to swoją przygodę możecie rozpocząć w tym miejscu.

Zaczniemy od tego, że potrzebne nam będzie repozytorium. Ja skorzystam z usług firmy Atlassian i ich projektu Bitbucket. Czemu? Dlatego, że oferuje darmowe prywatne repozytoria (a oprócz tego jest bardzo dobrym produktem). Tak więc rejestrujemy się i tworzymy repozytorium (może być prywatne). Teraz musimy dodać nasz klucz publiczny (używany na lokalnej maszynie) do Bitbucket. W tym celu musimy wejść do zakładki „Manage account”, a później „SSH keys”.

Jeśli mamy to już za sobą, możemy pobrać repozytorium do utworzonego wcześniej folderu na naszym komputerze. Będąc w folderze, wykonujemy polecenie:

git clone git@bitbucket.org:nazwa_uzytkownika/nazwa_repozytorium.git .

Możemy to również zrobić z poziomu naszego IDE (o ile posiada taką opcję) lub za pośrednictwem zewnętrznego klienta np. SourceTree (również ze stajni Atlassian).

Skoro repozytorium jest już na naszym komputerze, możemy przejść na serwer zewnętrzny. Potrzebny nam będzie oczywiście dostęp do SSH i zainstalowany Git. Po zalogowaniu na serwer musimy skonfigurować Gita (wygenerować klucze). W tym celu wykonamy polecenie:

ssh-keygen

Kiedy zostaniemy zapytani o passphrase po prostu wciśnijmy klawisz Enter i nic więcej (innymi słowy zostawiamy wyjątkowo pustą wartość). Kolejnym krokiem będzie skopiowanie zawartości pliku publicznego, który został wygenerowany (powinien znajdować się w /.ssh/id_rsa.pub). Klucz ten musimy dodać do naszego repozytorium na Bitbucket. W tym celu wchodzimy do repozytorium i klikamy na „trybik” po prawej stronie, który przeniesie nas do ustawień administracyjnych. Następnie wybieramy zakładkę „Deployment keys” i dodajemy nasz klucz publiczny. Teraz możemy wrócić z powrotem na serwer i wykonać polecenie:

ssh -T git@bitbucket.org

które sprawdzi, czy klucz się zgadza oraz doda domenę do rozpoznawalnych hostów.

To tyle. Możemy przejść do folderu na serwerze, w którym ma się znajdować nasz projekt i wykonać znaną nam już komendę:

git clone git@bitbucket.org:nazwa_uzytkownika/nazwa_repozytorium.git .

No dobrze, jeśli już mamy to za sobą, to możemy przystąpić do przygotowania samego CI. Wracamy na nasz lokalny serwer developerski i do folderu gdzie ma się znajdować nasz projekt wgrywamy „czysty” framework CodeIgniter. Teraz czeka nas znowu kilka zmian. Najpierw edytujemy plik .gitignore w głównym katalogu i dodajemy na końcu:

application/config/development/*

Ten plik informuje Gita, które pliki mają zostać pominięte w procesie synchronizacji. Nie chcemy przecież aby pliki cache i logi były udostępniane dalej z naszej maszyny developerskiej. Dodana linijka mówi rownież o ignorowaniu wszystkich plików z katalogu application/config/development, który będzie przez nas wykorzystywany do przechowywania ustawień konfiguracyjnych wyłącznie na naszej lokalnej maszynie developerskiej. Będziemy mogli w ten sposób łatwo odseparować dane dostępowe do bazy danych oraz inne ustawienia. Tak więc od razu możemy stworzyć katalog development i przekopiować tam plik application/config/database.php (oraz inne jeśli będzie taka potrzeba), a następnie odpowiednio zmodyfikować ich zawartość, tak aby odpowiadała ustawieniom naszego lokalnego serwera.

Domyślnie CodeIgniter uruchamia się w trybie developerskim, dlatego podczas pracy na lokalnym serwerze, zostaną użyte pliki z utworzonego przez nas przed chwilą folderu development. Pojawia się jednak problem, ponieważ na naszym serwerze docelowym (produkcyjnym) będziemy chcieli uruchamiać aplikację w trybie „production”. Na szczęście jest na to prosty sposób. Edytujemy plik index.php i zamieniamy linijkę o numerze 21 na następującą (nazwa domeny, to oczywiście tylko przykład i należy ją zmodyfikować do własnych potrzeb):

define('ENVIRONMENT', $_SERVER['SERVER_NAME'] === 'naszprojekt.pl' ? 'production' : 'development');

Dzięki temu, kiedy CI będzie uruchamiany na naszym serwerze produkcyjnym, zostanie uruchomiony w odpowiednim trybie.

No dobrze, pora na gwóźdź programu, czyli plik, który pozwoli nam na pobieranie zmian z repozytorium na serwer produkcyjny. Możemy zrobić to na kilka sposobów: utworzyć specjalny kontroler, albo osobny plik. Tym razem zdecydujemy się na utworzenie osobnego pliku, ponieważ jest to rozwiązanie bardziej uniwersalne i do tego pozwala na rożne podejście – umieszczenie pliku bezpośrednio w projekcie lub pod inną domeną lub subdomeną. Właśnie z tego ostatniego rozwiązanie skorzystamy, ponieważ jest bardziej eleganckie. Pora więc utworzyć plik deploy.php o następującej treści:

<?php

class Deploy 
{
	/**
	 * Funkcja zwrotna, która zostanie wywołana po pobraniu zmian.
	 */
	public $post_deploy;

	/**
	 * Ścieżka do deployu
	 */
	public $deploy_path;

	/**
	 * Ścieżka do logów
	 */
	public $log_path;

	/**
	 * Nazwa dla branch.
	 */
	private $_branch = 'master';

	/**
	 * Nazwa dla remote.
	 */
	private $_remote = 'origin';

	/**
	 * __construct
	 */
	public function __construct($deploy, $log)
	{
		$this->deploy_path = $deploy;
		$this->log_path = $log;

		$this->log('Deployment rozpoczęty.');
	}

	/**
	 * Wykonanie pobrania z repozytorium
	 */
	public function pull()
	{
		try
		{
			chdir($this->deploy_path);

			exec('git pull '.$this->_remote.' '.$this->_branch);
			$this->log('Pobieranie zmian... ');

			if (is_callable($this->post_deploy))
			{
				call_user_func($this->post_deploy);
			}

			$this->log('Deployment zakończony.');
		}
		catch (Exception $e)
		{
			$this->log($e);
		}
	}

	/**
	 * Logowanie wykonywanych czynności
	 *
	 * @param string $message Informacja tekstowa
	 */
	public function log($message) 
	{
		file_put_contents($this->log_path.'deploy.log', '['.date('Y-m-d H:i:s').'] - '.$message.PHP_EOL, FILE_APPEND);
	}

}


// Ustawiamy strefę czasową na potrzeby logów
date_default_timezone_set('Europe/Warsaw');

// Rozpoczynamy deployment
// Jako parametry konstruktora musimy podać bezwzględną ścieżkę
// do repozytorium na naszym serwerze oraz do miejsca gdzie będą zapisywane logi
// poniższe dane to tylko przykład i należy je zmodyfikować do własnych potrzeb
$deploy = new Deploy('/home/nazwa_uzytkownika/public_html/naszprojekt.pl/', '/home/nazwa_uzytkownika/public_html/deploy.naszprojekt.pl/');
$deploy->post_deploy = function() use ($deploy) {
  exec('php '.$deploy->deploy_path.'index.php migrations/latest', $output);
  $deploy->log('Migracja bazy danych... '.implode(' ', $output));
};
$deploy->pull();

To bardzo podstawowe rozwiązanie – z łatwością znajdziemy w sieci bardziej rozbudowane, ale do naszych skromnych potrzeb powinno wystarczyć. Powyższy plik umieścimy w subdomenie np: deploy.naszprojekt.pl. Pamiętajmy również o utworzeniu pliku deploy.log, w którym będą zapisywane rezultaty naszych działań. Do tego wszystkiego dołączymy specjalny plik .htaccess, który pozwoli na dostęp do naszego pliku tylko z określonych adresów IP (z których korzysta Bitbucket):

Deny from all
# Bitbucket Posthook IP
Allow from 131.103.20.165
Allow from 131.103.20.166

Wróćmy jeszcze na chwilę do opcji post_deploy z naszego skryptu. Jest to bardzo fajne rozwiązanie, ponieważ po pobraniu zmian z repozytorium mamy możliwość wykonania dodatkowych operacji (w całkiem elegancki sposób). Jak widać korzystamy z tego, aby wykonać metodę latest z kontrolera migrations. Oczywiście nadeszła pora, aby ten kontroler utworzyć – jest on bardzo podobny do tego, którego używaliśmy kiedyś w jednej z części blog tutorialu:

<?php defined('BASEPATH') OR exit('No direct script access allowed');
 
class Migrations extends CI_Controller
{
	/**
	 * __construct
	 */
    public function __construct()
    {
        parent::__construct();
        if ( ! $this->input->is_cli_request())
        {
            show_404();
        }
        $this->load->library('migration');
    }
 
    /**
     * Migruje bazę danych do ostatniej dostępnej wersji
     */
    public function latest()
    {
        if ( ! $this->migration->current())
        {
            echo $this->migration->error_string();
        }
        else
        {
            echo 'Poprawnie wykonano migracje bazy danych, do ostatniej dostepnej wersji.';
        }
    }
 
    /**
     * Migruje bazę do wersji podanej w parametrze
     *
     * @param int Numer wersji
     */
    public function version($number)
    {
        if ( ! $this->migration->version($number))
        {
            echo $this->migration->error_string();
        }
        else
        {
            echo 'Poprawnie wykonano migracje bazy danych do wersji '. $number;
        }
    }
 
}
/* End of file migrations.php */
/* Location: ./application/controllers/migrations.php */

Oczywiście jeśli nie zamierzamy stosować migracji w swoim projekcie, to możemy tę opcję najzwyczajniej pominąć, chociaż osobiście uważam to za bardzo poręczne rozwiązanie, bez którego wręcz trudno się obyć podczas pracy w kilka osób. Na jakiej zasadzie to działa? Zakładamy, że wszystkie zmiany w strukturze bazy danych (ewentualnie również w przypadku domyślnych danych) odbywają się za pomocą migracji.

W pliku application/config/migration.php mamy zmienną $config['migration_version'], która odpowiada za numer aktualnej migracji. Po przesłaniu zmian do repozytorium, migracje na serwerze zostaną automatycznie zaktualizowane do tego właśnie numeru (za sprawą naszego skryptu). Po więcej informacji na temat migracji odsyłam do tego rozdziału z podręcznika.

W tym momencie pozwolę sobie założyć, że mamy utworzoną naszą przykładową subdomenę deploy.naszprojekt.pl oraz wgrane tam pliki: deploy.php, deploy.log oraz .htaccess. Teraz pozostało nam określenie czegoś co nazywa się Post Delpoyment Hook, czyli inaczej mówiąc, określenie adresu, który ma zostać wywołany w momencie kiedy prześlemy nasze zmiany do repozytorium – pozwoli to na odpalenie pliku deploy.php, którym zajmowaliśmy się powyżej. Aby tego dokonać, na stronie naszego repozytorium na Bitbucket, ponownie przechodzimy do ustawień („trybik” po prawej stronie) i tym razem wybieramy z menu opcję „Hooks”. Następnie w polu select zaznaczamy opcję „POST” i dodajemy adres URL, który ma zostać wywołany, czyli w naszym przypadku: http://deploy.naszprojekt.pl/deploy.php.

Co nam teraz pozostało? Jeśli korzystamy z migracji, to wypadałoby upewnić się, że dobrze skonfigurowaliśmy dane dostępowe do bazy danych na serwerze produkcyjnym (oraz utworzyliśmy bazę) i włączyliśmy obsługę migracji. Jeśli wszystko sprawdzone, to możemy zaczynać. Na naszej lokalnej maszynie, w głównym folderze naszej aplikacji wykonujemy kolejno komendy:

git add .

git commit -m 'Pierwszy commit'

git push origin master

W tym momencie dodaliśmy i wysłaliśmy zmiany do repozytorium na Bitbucket. Jeśli wszystko poszło po naszej myśli, to po tej czynności powinno nastąpić wywołanie adresu http://deploy.naszprojekt.pl/deploy.php. Plik deploy.php wykona następujące czynności: pobierze najnowsze zmiany z repozytorium oraz „odpali” kontroler z migracjami. Dzięki temu zarówno nasz kod jak i baza danych zostaną zsynchronizowane.

To tyle. Mam nadzieję, że tym wpisem udało mi się zachęcić Was do korzystania z Git w codziennej pracy lub chociażby zainteresować tym tematem.