Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: widmogrod, dodany: 16.02.2011 22:20, tagi: php

Moja pierwsza prezentacja na KrakSpotTECH, przed tak dużą publiką (ok 200 osób na sali). Dużo się nauczyłem a szczególnie to że jeżeli nie czujesz stresu to nie znaczy że go nie ma :)

Temat mojej prezentacji dotyczył zagadnienia DataGrid w PHP. Dla zainteresowanych umieszczam poniżej prezentację:

Data grid w PHP View more presentations from widmogrod.

Buzz: - http://krakspot.pl/2011/02/01/krakspot-tech-3-agenda/

Autor wpisu: sokzzuka, dodany: 16.02.2011 09:12, tagi: php

Jak niektórzy z nas wiedzą, w innych językach np. C istnieje rodzaj struktury danych zwany popularnie „enumem”. Enum jest skrótem od „enumeracja”. Taka struktura danych może przyjąć tylko kilka, z wcześniej zadeklarowanych wartości. Więcej informacji znajdziecie oczywiście w Wikipedii, natomiast tutaj chciałbym przybliżyć dwie metody jakie można użyć w PHP do osiągnięcia tej samej funkcjonalności. Pierwszą metodą jest użycie wbudowanej klasy SplEnum, tak jak zostało to pokazane w komentarzu na php.net:

class Fruit extends SplEnum
{
  // If no value is given during object construction this value is used
  const __default = 1;
  // Our enum values
  const APPLE     = 1;
  const ORANGE    = 2;
}

$myApple   = new Fruit();
$myOrange  = new Fruit(Fruit::ORANGE);
$fail      = 1;

function eat(Fruit $aFruit)
{
  if (Fruit::APPLE == $aFruit) {
    echo "Eating an apple.\n";
  } elseif (Fruit::ORANGE == $aFruit) {
    echo "Eating an orange.\n";
  }
}

eat($myApple);  // Eating an apple.
eat($myOrange); // Eating an orange.

eat($fail); // PHP Catchable fatal error:  Argument 1 passed to eat() must be an instance of Fruit, integer given

Jak widać idea jest bardzo prosta i kod właściwie mówi wszystko. Jest jednak drugi sposób, chyba troszkę mniej znany, polegający na użyciu systemu klas w php:


abstract class Fruit {}
class Orange extends Fruit {}
class Apple extends Fruit {}

function eat(Fruit $fruit)
{
  if ($fruit instanceof Apple) {
    echo "Eating an apple.\n";
  } elseif ($fruit instanceof Orange) {
    echo "Eating an orange.\n";
  }
}

eat(new Apple); //Eating an apple
eat(new Orange); //Eating an orange
eat(1) // PHP Catchable fatal error:  Argument 1 passed to eat() must be an instance of Fruit, integer given

Oba rozwiązania mają oczywiście ten sam efekt. Warto zauważyć, że rozwiązanie nr. 2 bardzo ładnie prezentuje ideę polimorfizmu i dziedziczenia. Hierarchia klas pokazuje, że zarówno Jabłko jak i Pomarańcza jest Owocem i kierunek tej zależności, tj. Jabłko jest Owocem a nie Owoc Jabłkiem :)

Autor wpisu: matipl, dodany: 16.02.2011 08:53, tagi: php

PHPCon Poland 2011Wczoraj kolejna osoba zapytała się mnie, czy wiem coś o tegorocznej edycji PHPCon, bo w Sieci cicho na ten temat. Dlatego podzielę się z Wami tym co wiem…

W tym roku konferencja dla miłośników PHP nie odbędzie się wiosną, ale dopiero jesienią. Jest to podyktowane m.in. terminami innych konferencji w Polsce i w Europie, ponieważ kilku prelegentów zgłaszało takie uwagi.

Chcieliśmy w tym roku Was zaskoczyć i zrobić konferencję jeszcze bardziej na południu Polski, ale ostatecznie PHPCon 2011 odbędzie się 15 km na wschód od Kielc (czyli nie wiele dalej niż ostatnio) w Hotelu Przedwiośnie (Mąchocice Kapitulne).

A kiedy? W dniach 21-23 października (piątek-niedziela). Teraz zostało tylko czekać na listę prelegentów oraz otwarcie zapisów :) Będę informował.

Autor wpisu: sokzzuka, dodany: 16.02.2011 08:45, tagi: php

Johannes Schlüter (release manager dla brancha 5.3.x)  zapowiedział dzisiaj wydanie PHP 5.3.6 w wersji Release Candidate na czwartek 17-tego lutego. Wszyscy chętni do testowania otrzymają więc jutro świeżą porcję kodu :)

Autor wpisu: batman, dodany: 16.02.2011 08:00, tagi: php

Windows Azure oferuje trzy podstawowe mechanizmy przechowywania danych. Każdy z nich przeznaczony jest dla innego typu danych i każdy z nich oferuje inne możliwości. Dzisiaj skupimy się na niestandardowym zastosowaniu blobów, czyli pojemników na dane binarne. Jeśli nie wiecie czym są bloby, możecie zapoznać się z ich opisem tutaj.

Problem

Problem z jakim się dzisiaj zmierzymy znany jest wszystkim, którzy mieli do czynienia z aplikacją przechowującą pliki wgrywane przez użytkowników. Najwięcej kłopotu w tego typu aplikacji przysparza przechowywanie informacji o zmianach jakie użytkownik wprowadził do pliku. Najpopularniejszym rozwiązaniem tego problemu jest przechowywanie poprzednich wersji pliku w osobnych katalogach, ewentualnie zmiana nazwy pliku i dodanie do niego znacznika czasu. Do tego dochodzi jeszcze baza danych, w której przechowywane są informacje o użytkowniku wprowadzającym zmiany (czasami więcej niż jeden użytkownik mają możliwość nadpisania pliku), dacie wprowadzenia zmian oraz szereg innych niezbędnych informacji.

Rozwiązanie

Azure Storage, a dokładniej bloby, oferują interesującą funkcjonalność nazwaną snapshot. Dzięki niej możemy stworzyć migawkę pliku wraz z jej dokładnym opisem. Następnie jeśli zajdzie taka potrzeba możemy odwołać się do dowolnej migawki oraz informacji z nią związanych. W takim modelu baza danych wymagana jest do przechowywania jedynie identyfikatora migawki. Cała reszta siedzi zaszyta w blobie.

Przygotowanie środowiska

W dzisiejszym przykładzie wykorzystamy Windows Azure jedynie jako magazyn danych. Aplikacja uzyskująca dostęp chmury będzie znajdować się w innej lokalizacji. Podobnie jak ostatnim razem zaprezentowany zostanie jedynie szkielet aplikacji, który został maksymalnie uproszczony.

Nasze środowisko będzie się składać z jednego kontenera oraz jednego bloba. Blob ten będzie posiadał dwie migawki wraz z informacją o użytkowniku, który ją wykonał. Do przygotowania środowiska wykorzystamy prosty skrypt.

require_once 'Microsoft/WindowsAzure/Storage.php';
require_once 'Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php';
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';

// Dane wymagane do zalogowania się na konto Windows Azure
// W przykładzie logujemy się do konta lokalnego
$host = Microsoft_WindowsAzure_Storage::URL_DEV_BLOB;
$accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT;
$accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY;

$storageBlob = new Microsoft_WindowsAzure_Storage_Blob($host, $accountName, $accountKey);

// Usuń kontener i stwórz nowy
if($storageBlob->containerExists('wersjonowanie')) {
	$storageBlob->deleteContainer('wersjonowanie');
}
$storageBlob->createContainer('wersjonowanie');

// Ustawienie kontenera jako publiczny
$storageBlob->setContainerAcl('wersjonowanie', Microsoft_WindowsAzure_Storage_Blob::ACL_PUBLIC_CONTAINER);

// Kowalski uploadował plik
$storageBlob->putBlob('wersjonowanie', 'plik.jpg', '/ulopadowany/plik/1.jpg', array('user' => 'Kowalski'));

// Nowak uploadował plik
// Wykonujemy migawkę pliku. W prawdziwej aplikacja jej identyfikator powinien trafić do bazy.
echo $storageBlob->snapshotBlob('wersjonowanie', 'plik.jpg') . PHP_EOL;

// Nadpisujemy bloba
$storageBlob->putBlob('wersjonowanie', 'plik.jpg', '/ulopadowany/plik/2.jpg', array('user' => 'Nowak'));

// admin uploadował plik
// Wykonujemy kolejną migawkę pliku i zapisujemy jej identyfikator
echo $storageBlob->snapshotBlob('wersjonowanie', 'plik.jpg') . PHP_EOL;

// Nadpisujemy bloba
$storageBlob->putBlob('wersjonowanie', 'plik.jpg', '/ulopadowany/plik/3.jpg', array('user' => 'admin'));

W powyższym kodzie na uwagę zasługują dwa elementy. Pierwszym jest dodawanie bloba. W tym miejscu (a dokładniej w czwartym argumencie metody pubBlob), mamy możliwość dodania do bloba metadanych w postaci tablicy klucz –> wartość. Metadane nie mogą zawierać więcej niż 8KB informacji, a klucz nie może być dłuższy niż 1024 znaki. Mimo niewielkiego rozmiaru, metadane w zupełności wystarczą do przechowania wszystkich niezbędnych informacji o blobie (np. nazwa użytkownika).

Drugim elementem jest moment wykonania migawki. Odpowiedzialna za to metoda snapshotBlob, zwraca unikalny w obrębie bloba identyfikator w postaci wartości DateTime. Aby móc później odwołać się do konkretnej migawki, musimy ten identyfikator zapisać, np. w bazie danych.

Wyświetlanie historii pliku

require_once 'Microsoft/WindowsAzure/Storage.php';
require_once 'Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php';
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';

$host = Microsoft_WindowsAzure_Storage::URL_DEV_BLOB;
$accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT;
$accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY;

$storageBlob = new Microsoft_WindowsAzure_Storage_Blob($host, $accountName, $accountKey);

// pobrane z bazy identyfikatory migawek
$snapshotId1 = '2011-01-25T08:15:14.7130000Z';
$snapshotId2 = '2011-02-01T16:09:04.8730000Z';

// pobranie metadanych z bloba oraz migawek
$meta = $storageBlob->getBlobMetadata('wersjonowanie', 'plik.jpg');
$metas1 = $storageBlob->getBlobMetadata('wersjonowanie', 'plik.jpg', $snapshotId1);
$metas2 = $storageBlob->getBlobMetadata('wersjonowanie', 'plik.jpg', $snapshotId2);

// wyświetlenie zdjęć oraz ich autorów
echo 'Aktualne zdjęcie (autor: ' . $meta['user'] . ')<br />';
echo '<img src="zdjecie.php" width="300" />';
echo '<br /><br />';

echo 'Snapshot 1 (autor: ' . $metas1['user'] . '):<br />';
echo '<img src="zdjecie.php?snapshotid=' . urlencode($snapshotId1) . '" width="300" />';
echo '<br /><br />';

echo 'Snapshot 2 (autor: ' . $metas2['user'] . '):<br />';
echo '<img src="zdjecie.php?snapshotid=' . urlencode($snapshotId2) . '" width="300" />';
echo '<br /><br />';

Jak widać na powyższym kodzie, operacje na migawkach przeprowadza się w identyczny sposób jak na aktualnej wersji bloba. Jedyną różnicą jest konieczność użycia zapisanego wcześniej identyfikatora migawki.

Ostatnim elementem układanki jest skrypt pobierający zawartość bloba i zwracającego go jako obrazek (zdjęcie.php).

require_once 'Microsoft/WindowsAzure/Storage.php';
require_once 'Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php';
require_once 'Microsoft/WindowsAzure/Storage/Blob.php';

$host = Microsoft_WindowsAzure_Storage::URL_DEV_BLOB;
$accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT;
$accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY;

$storageBlob = new Microsoft_WindowsAzure_Storage_Blob($host, $accountName, $accountKey);

header('Content-Type: image/jpg');

// jeśli nie ma identyfikatora migawki, pobierz zawartość aktualnego bloba
if(!isset($_GET['snapshotid'])) {
	echo $storageBlob->getBlobData('wersjonowanie', 'plik.jpg');
}
else {
	// pobierz zawartość migawki
	echo $storageBlob->getBlobData('wersjonowanie', 'plik.jpg', urldecode($_GET['snapshotid']));
}

Voila!

W ten oto sposób stworzyliśmy proste i skuteczne zarazem wersjonowanie plików uploadowanych przez użytkownika. Nie musimy się na tym zatrzymywać. W przypadku większej ilości informacji, które powinny znaleźć się w opisie bloba, można skorzystać z tabel. Metadane zawierałyby jedynie klucz partycji oraz klucz wiersza.

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

Autor wpisu: JoShiMa, dodany: 15.02.2011 23:24, tagi: jquery, javascript

Pracuję ostatnio nad dość ciekawym projektem, który realizuję wykorzystując kohana 2. Mimo mojej szczerej niechęci (ciągle) do JavaScript oraz zupełnej nieznajomości (nie powinnam się przyznawać?) mechanizmów AJAX musiałam się zmierzyć z pewnymi zagadnieniami, których puki co inaczej zrealizować się nie da. Opis problemu W serwisie, który tworzę będzie znajdowała się lista obrazków do których użytkownicy [...]

Autor wpisu: batman, dodany: 14.02.2011 08:00, tagi: javascript, jquery

Wraz z nadejściem jQuery 1.5, programiści otrzymali do swoich rąk szereg funkcjonalności usprawniających pracę z AJAXem. Jedną z nich są obiekty wstrzymane (deferred objects). W dużym skrócie dzięki deferred object możemy przypisać callback do AJAXowego requestu w dowolnym momencie, a nie jak to miało miejsce do tej pory, w momencie tworzenie requestu. Co więcej nie musimy ograniczać się tylko do jednej funkcji zwrotnej.

Jak to się robiło kiedyś…

Przed nastaniem jQuery 1.5 typowy request AJAXowy wyglądał następująco.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Insert title here</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.js"></script>
        <script>
        $(document).ready(function() {
        	$.ajax({
        		url: "ajax.php",
        		type: "POST",
        		success: function(data) {
        			$("#content").append(data);
        		}
        	});
        });
        </script>
    </head>
    <body>
        <div id="content"></div>
    </body>
</html>

W efekcie działania tego nieco uproszczonego przykładu, do diva o identyfikatorze content dodana zostanie zawartość odpowiedzi serwera. Jeśli chcielibyśmy wykonać więcej operacji na zwróconych przez serwer danych oraz uzależnić niektóre operacje od wyniku działania innych funkcji, nieźle byśmy się napocili.

A jak to się robi dziś?

Na szczęście z pomocą przychodzi nam najnowsza odsłona jQuery. W wersji 1.5 opisany powyżej problem rozwiążemy w bardzo prosty sposób

$(document).ready(function() {
	var req = $.ajax({
		url: "ajax.php",
		type: "POST",
		success: function(data) {
			$("#content").append(data);
		}
	});

	/* dużo innych operacji, które muszą się wykonać niezależnie od AJAXa */

	req.success(function(data) {
		/* korzystamy z danych przetworzonych powyżej */

		// zrób coś z danymi z serwera
		$("#content").append(data);
	});
});

Drugi callback success wykona się dopiero w momencie, gdy zakończą się operacje znajdujące się bezpośrednio przed nim. Zmienna data zawierać będzie dokładnie te same dane, co w przypadku pierwszej funkcji callback. W podobny sposób możemy dodać callbacki error oraz complete.

Magia?

Obiekty wstrzymane (deferred object) wykorzystują wzorzec Promises/A. Zakłada on istnienie bytu nazwanego obietnicą (promise), który określa potencjalną wartość zwróconą w wyniku działania jakiejś operacji. Obietnica może znajdować się w jedenym z trzech stanów – niespełniona, spełniona, zakończona niepowodzeniem, przy czym zmiana stanu może nastąpić tylko raz: z niespełnionej na spełnioną lub z niespełnionej na zakończoną niepowodzeniem. W momencie gdy obietnica znajdzie się w stanie spełniona lub zakończona błędem, zmiana stanu nie może już mieć miejsca. Dzięki takiemu zachowaniu obietnic, dane zwrócone do callbacka pozostają niezmienne niezależne od miejsca, w którym do tych danych się odwołujemy.

W celu umożliwienia korzystania z wspomnianej przed chwilą funkcjonalności, jQuery zostało wyposażone w obiekt Deferred. To co się dzieje “behind the scenes”, wygląda łudząco podobnie do typowego wywołania metody ajax.

function funkcja1()
{
	var dfd = $.Deferred();
	dfd.resolve("ok");
	return dfd.promise();
}

function funkcja2()
{
	var dfd = $.Deferred();
	dfd.reject("my bad");
	return dfd.promise();
}

$.when(funkcja1(), funkcja2())
	.fail(function() {
		console.debug("co najmniej jedna funkcja sie wywaliła");
	})
	.done(function() {
		console.debug("wszystkie funkcje są ok");
	})
	.then(function() {
		console.debug("ok");
	}, function() {
		console.debug("coś poszło nie tak");
	});

Powyższy przykład nie jest może zbyt funkcjonalny, ale idealnie pokazuje zasadę działania obiektu Deferred. Metoda when przyjmuje jako argumenty dowolną ilość funkcji, których stan chcemy monitorować. Do obiektu zwróconego przez metodę when dodajemy handlery uruchamiane w momencie gdy wszystkie funkcje zakończą swoje działanie sukcesem (handler dome) lub co najmniej jedna z nich zakończy się niepowodzeniem (fail). Handler then przyjmuje dwa parametry. Pierwszym jest funkcja wykonywana w przypadku sukcesu, drugim funkcja wykonywana w momencie niepowodzenia.

Skąd metoda $.when wie czy monitorowane funkcje zakończyły się sukcesem lub porażką? Informuje ją o tym obiekt Deferred, który zwraca opisaną wcześniej obietnicę. Nim obietnica zostanie zwrócona, należy ustawić jej stan przy pomocy jeden z dwóch metod – resolve dla poprawnego sukcesu oraz reject dla porażki.

Słowo końcowe

Przedstawione powyżej informacje na temat deferred objects to tylko wierzchołek góry lodowej, której cały obraz ujrzycie po lekturze dokumentacji. Warto również zapoznać się z tym wpisem. Znajdziecie w nim szereg interesujących przykładów.

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

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