Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Athlan, dodany: 29.04.2009 15:15, tagi: sql

Podobnie jak w PHP, baza danych MySQL ma odpowiednik if, czyli przypadków (inaczej serii warunków, instrukcji warunkowych). Różnicą między implementacją CASE‘a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case’a, a nie wykonuje dowolnej ilości dowolnych akcji.

CASE Syntax:

Najprostsza struktura CASE’aprzedstawia się nastepująco:

CASE WHEN [conditions] THEN … ELSE … END

Składnia powinna rozpocząć się słowem kluczowym CASE, a zakończyć END. Pomiędzy znajdują się warunki WHEN oraz operacja zwrócenia odpowiedniej wartości, która po nich następuje THEN (mamy możliwość uwzględnić nieskończenie wiele warunków). Jeżeli żaden warunek nie zostanie spełniony możemy użyć opcjonalnie ELSE.

Przykłady z życia.

Wyobraźmy sobie, że mamy posortować listę aukcji przedmiotów na Allegro od najtańszych, do najdroższych. Należy założyć, że są 2 typy aukcji: kup teraz i licytacja. Pole licytacji w bazie danych zawiera największą zaproponowaną kwotę przez użytkowników w procesie licytacji, a cena kup teraz ustalana jest przez sprzedającego. Są to dwa różne pola w bazie danych, a jedno kryterium sortowania, dlatego trzeba scalić cenę w jedną, wybierając odpowiednią. Musimy przewidzieć sytuację, w której aukcja jest typu kup teraz oraz licytacji, wówczas jeżeli najwyższa oferta jest większa od ceny kup teraz, wówczas wybieramy pole z największa propozycją:

SELECT (CASE WHEN (auction_type = 'bidding' OR auction_price_bid > auction_price_buynow) THEN auction_price_bid ELSE auction_price_buynow END) AS auction_price

Stworzyliśmy pole auction_price, po którym można sortować aukcje od najtańszej do najdroższej i na odwrót.

Mam nadzieję, że krótki wpis przyda się początkującym. Nic więcej nie trzeba opisywać, temat wydaje się co najmniej trywialny.

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

Autor wpisu: Diabl0, dodany: 25.04.2009 22:56, tagi: zend_framework

tree_7Początkowo jako następny artykuł miało się tutaj pojawić podsumowanie tematu drzew wraz z przykładami praktycznego zastosowania. Jednym z tematów miało być wykorzystanie drzewa i elementu dijit.Tree w formie własnego elementu Zend_Form. Niestety, podczas prac trafiłem na pewien problem który mnie zablokował i za bardzo nie wiem jak do niego podejść w miarę prosty sposób. Tak więc tym razem zamiast gotowego rozwiązania będzie bardziej pytanie i prośba o pomoc.

Uwaga - zawarte fragmenty kodu są wersjami roboczymi, zapewne zawierają sporo błędów i można je napisać znacznie ładniej i zgodniej z standardami. Znajdują się one tutaj aby lepiej zobrazować problem i stanowić tylko i  wyłącznie wskazówki i pomoc, tak więc proszę ich nie wykorzystywać bez zastanowienia i dopracowania, aby nie mieć później pretensji że coś nie działa lub co gorsza działa źle.

Kto interesuje się Dojo wie że w jego skład wchodzi widget dijit.Tree. Naturalna więc wydaje się próba ułatwienia sobie życia i próba stworzenia elementu formy który da użytkownikom możliwość szybkiego i wygodnego wyboru elementu za pomocą rozwijanego drzewa. Początkowo problem wydawał się banalny, i pierwszy “szkic” takiego elementu napisałem w około godzinkę.

Idea działania jest prosta - tworzymy zwykły ukryty element INPUT w którym będzie lądował identyfikator wybranego elementu drzewa. Do tego tworzymy element DIV który następnie zostanie przekształcony w element dijit.Tree.

/**
 * Tree form element
 *
 * @uses Mao_View_Helper_FormDiv
 */

class Mao_Form_Element_Tree extends Zend_Dojo_Form_Element_ComboBox {

    /**
     * Use FormTree view helper
     * @var string
     */
    public $helper = 'FormTree';
}
/**
 * Dojo Tree dijit
 *
 * @uses       Zend_Dojo_View_Helper_Dijit
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
class Mao_View_Helper_FormTree extends Zend_Dojo_View_Helper_Dijit
{
    /**
     * Dijit being used
     * @var string
     */
    protected $_dijit  = 'dijit.Tree';

    /**
     * HTML element type
     * @var string
     */
    protected $_elementType = 'text';

    /**
     * Dojo module to use
     * @var string
     */
    protected $_module = 'dijit.Tree';

    /**
     * dijit.form.ComboBox
     *
     * @param  int $id
     * @param  mixed $value
     * @param  array $params  Parameters to use for dijit creation
     * @param  array $attribs HTML attributes
     * @param  array|null $options Select options
     * @return string
     */
    public function formTree($id, $value = null, array $params = array(), array $attribs = array(), array $options = null)
    {
        $html = '';
        if (!array_key_exists('id', $attribs)) {
            $attribs['id'] = $id;
        }
        if (array_key_exists('store', $params) && is_array($params['store'])) {
            // using dojo.data datastore
            if (false !== ($store = $this->_renderStore($params['store']))) {
                $params['store'] = $params['store']['store'];
                if (is_string($store)) {
                    $html .= $store;
                }
                $html .= $this->_createFormElement($id, $value, $params, $attribs);
                return $html;
            }
            unset($params['store']);
        } elseif (array_key_exists('store', $params)) {
            if (array_key_exists('storeType', $params)) {
                $storeParams = array(
                    'store' => $params['store'],
                    'type'  => $params['storeType'],
                );
                unset($params['storeType']);
                if (array_key_exists('storeParams', $params)) {
                    $storeParams['params'] = $params['storeParams'];
                    unset($params['storeParams']);
                }
                if (false !== ($store = $this->_renderStore($storeParams))) {
                    if (is_string($store)) {
                        $html .= $store;
                    }
                }
            }
            $html .= $this->_createFormElement($id, $value, $params, $attribs);
            return $html;
        }

        throw new Exception('No dojo.data store provided.');
    }

	/**
	 * Create HTML representation of a dijit form element
	 *
	 * @param  string $id
	 * @param  string $value
	 * @param  array $params
	 * @param  array $attribs
	 * @param  string|null $dijit
	 * @return string
	 */
	public function _createFormElement($id, $value, array $params, array $attribs, $dijit = null) {

		if (! array_key_exists ( 'id', $attribs )) {
			$attribs ['id'] = $id;
		}
		$attribs ['name'] = $id;
		$attribs ['value'] = ( string ) $value;
		$attribs ['type'] = $this->_elementType;

		$attribs ['id'] = '_' . $id . '_';
		$attribs = $this->_prepareDijit ( $attribs, $params, 'element', $dijit );
		$attribs ['id'] = $id;

		// atrybuty na potrzeby DIVa reprezentującego dijit.Tree
		$divAttribs = $attribs;

		// Ukrywamy element INPUT
		$attribs ['type'] = 'hidden';

        // Wyrzucamy ukryty input
        $html = '<input'
              . $this->_htmlAttribs($attribs)
              . $this->getClosingBracket();

		// Modyfikujemy atrybuty na potrzeby elementu DIV reprezentującego dijitTree
		$divAttribs ['id'] = '_' . $id . '_';
		$divAttribs ['name'] = '_' . $id . '_';
		unset ( $divAttribs ['name'], $divAttribs ['value'] );

        $html .= '<div '
            . $this->_htmlAttribs( $divAttribs )
            . $this->getClosingBracket()
            . '</div>';

		// Wyrzucamy kod JS odpowiadający za połączenie ukrytego inputa z wyświetlonym drzewkiem
		$this->_renderJsHelper ( $id, $params );

		return $html;
	}

    /**
     * Render data store element
     *
     * Renders to dojo view helper
     *
     * @param  array $params
     * @return string|false
     */
    protected function _renderStore(array $params)
    {
        if (!array_key_exists('store', $params) || !array_key_exists('type', $params)) {
            return false;
        }

        $this->dojo->requireModule($params['type']);

        $extraParams = array();
        $storeParams = array(
            'dojoType' => $params['type'],
            'jsId'     => $params['store'],
        );

        if (array_key_exists('params', $params)) {
            $storeParams = array_merge($storeParams, $params['params']);
            $extraParams = $params['params'];
        }

        if ($this->_useProgrammatic()) {
            if (!$this->_useProgrammaticNoScript()) {
                require_once 'Zend/Json.php';
                $js = 'var ' . $storeParams['jsId'] . ' = '
                    . 'new ' . $storeParams['dojoType'] . '('
                    .     Zend_Json::encode($extraParams)
                    . ");\n";
                $this->dojo->addJavascript($js);
            }
            return true;
        }

        return '<div' . $this->_htmlAttribs($storeParams) . '></div>';
    }

	/**
	 * Render data store element
	 *
	 * Renders to dojo view helper
	 *
	 * @param  string $id
	 * @param  array $params
	 * @return string|false
	 */
	protected function _renderJsHelper($id, array $params) {

		if ($this->_useProgrammatic ()) {
			if (! $this->_useProgrammaticNoScript ()) {
				require_once 'Zend/Json.php';

				$js = '
 dojo.subscribe("_' . $id . '_", "execute", function( data ){
    dojo.byId("' . $id . '").value = ' . $params ['store'] . '.getIdentity( data.item );
 });
 ';
				$this->dojo->addJavascript ( $js );
			}
			return true;
		}

		return '<div' . $this->_htmlAttribs ( $storeParams ) . '></div>';
	}

}

Powyższe 2 klasy załatwiają nam utworzenie wspomnianych elementów INPUT i DIV. Dodatkowo w metodzie _renderJsHelper znajduje się prosty kod JS odpowiedzialny za nasłuch zdarzeń w utworzonym widgecie dijitTree i w po wybraniu jakiegoś elementu wstawienie jego identyfikatora do pola INPUT (to ten fragment z dojo.subscribe).

Od strony formy wykorzystanie tego elementu wygląda mniej więcej tak:

class default_forms_TreeTest extends Mao_Form {

    public function __construct($options = null) {
        parent::__construct ( $options );

        // Dojo-enable the form:
        Zend_Dojo::enableForm ( $this );

        $this->addElement ( 'Tree', 'tree_id',
           array (
              'label'             => 'Tree',
              'storeId'           => 'tstr',
              'storeType'         => 'dojo.data.ItemFileReadStore',
              'storeParams'       => array(
                'url'        => '/mag/categories/categoriesTreeJson.json',
              ),
              'dijitParams'       => array(
                    'labelAttr' => 'name',
              ),
              'value'             => 4,
              'style'   => 'height: 200px; overflow: auto;',
           )
        );

        $this->addElement ( 'SubmitButton', 'submit',
        array (
              'label' => 'Zapisz'
          )
        );

    }

}

Natomiast wynikowy kod HTML:

[sourcecode]
<!-- W części JS generowanej przez Zend_Dojo -->
<script type="text/javascript">
//<![CDATA[
    dojo.require("dijit.Tree");

var tstr = new dojo.data.ItemFileReadStore({"url":"\/mag\/categories\/categoriesTreeJson.json"});
    //

 dojo.subscribe("_tree_id_", "execute", function( data ){
    // console.log( tstr.getIdentity( data.item ) );
    dojo.byId("tree_id").value = tstr.getIdentity( data.item );
 });

//]]>
</script>

<!-- I część formy -->
<dt><label for="tree_id" class="optional">Tree</label></dt>
<dd>
<input style="height: 200px; overflow: auto;" id="tree_id" name="tree_id" value="4" type="hidden">
<div  style="height: 200px; overflow: auto;" id="_tree_id_" type="text"></div>
</dd>
[/sourcecode]

W sumie wszystko teoretycznie działa, brakuje jednak pewnej “małej” ale ważnej funkcjonalności - przy wyświetlaniu formy powinno nastąpić automatyczne zaznaczenie elementu drzewa którego identyfikator znajduje się w polu INPUT, oraz rozwinięcie odpowiedniej gałęzi drzewa. Niestety twórcy dijit.Tree z jakiegoś powodu nie zaimplementowali do tego odpowiednich metod przez co trzeba to zrobić samemu. I tutaj mamy 2 problemy:

  1. lazy loading
  2. znalezienie wybranego elementu, rozwinięcie gałęzi do której on należy i zaznaczenie go

Problem pierwszy wynika z tego że dane do drzewa ładowane są asynchronicznie po stworzeniu elementu. Na szczęście problem ten jest dość prosty do rozwiązania z wykorzystaniem interwałów:

var _tree_id_timer;
dojo.addOnLoad( function () {
    if ( dojo.byId("tree_id").value != "") {
	    _tree_id_timer = setInterval( function(){
	        if ( dijit.byId("_tree_id_").store._loadFinished ) {
                    // Dane do elementu zostały załadowane
	            clearInterval( _tree_id_timer );

	            // Czas znaleźć i zaznaczyć wybrany element

	        }
	    }, 100);
    }
});

W skrócie, jeśli w pole input zawiera jakąś wartość, to tworzymy interwał który co określony czas sprawdza czy źródło danych wykorzystywane przez dijit.Tree zakończyło wczytywanie danych (dijit.byId(”_tree_id_”).store._loadFinished). Jeśli skończyło to czyścimy interwał (już nam nie będzie potrzebny) i przystępujemy do problemu drugiego.

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

Autor wpisu: thejw23, dodany: 20.04.2009 18:45, tagi: php

nowa wersja dostepna na SVN, zmiany, glownie zwiazane z laczeniem metod:- dodane update(), tak dla porzadku skoro jest insert()- dodane select() aby ograniczyc liczbe zwracanych pol (wczesniej zawsze *)- dodane limit(), aby fetch_x mialo mniej parametrow- uwaga: w zwiazku z powyzszym fetch zgubilo parametr $limit- load() zwraca $thisdzieki temu mozna teraz w jednej linijce np. tak:
//pobranie 2 pol z limitem 3 rekordow$users=Simple_Modeler::factory('auth_users')->select('username','email')->limit(3)->fetch_all();//zaladowanie pojedynczego rekordu z bazy, username=janek$user=Simple_Modeler::factory('auth_users')->load('janek','username');

Autor wpisu: Tomasz Sh4dow Budzyński, dodany: 14.04.2009 15:12, tagi: php

Na pewno sporo osób próbowało swoich sił w stworzeniu skryptu do zliczania odwiedzin na stronie na podstawie logów z Apache’a. W sumie nic trudnego, schemat logów jest w miarę prosty, odczytać i po sprawie. A jak wygląda sprawa przy plikach wielkości setek megabajtów lub gigabajtów ? Trzeba sprytnie to odczytywać linia po linii, przeanalizować i wywalić z pamięci. A jak mamy dwa lub więcej rdzeni w procesorze, to może by tak parę linii na raz analizować ? Sama zasada jest dość prosta. Odczytujemy mały blok pliku i wyszukujemy gdzie jest znak końca linii. Jeśli nie znajdujemy to doczytujemy jeszcze kawałek. Jeśli już znaleźliśmy to odcinamy nasz kawałek i po sprawie. Przy wyszukiwaniu usuwamy wszystkie znaki powrotu karetki, jak by się znalazł jakiś plik z „enterami” z Windowsa.

$tresc = ''; //definiujemy zmienna 
$uchwyt = fopen('pliczek.log', "rb");
$tresc .= fread($uchwyt, 300 ); //dopisujemy do zmiennej kawałek pliku
$tresc = str_replace("\r",'',$tresc);
if( strpos( $tresc, chr(10) ) === false ) {
    //doczytujemy jeszcze kawalek i jeszcze raz szukamy i tak aż znajdziemy
} else {
    $strpos = strpos( $tresc, chr(10) ); //znajdujemy pozycje entera
    $linia = substr($tresc, 0, $strpos); //odcinamy interesujący nas odcinek
    $tresc = substr($tresc, $strpos+1, strlen($tresc) ); //i usuwamy odcięty kawałek od pobranej treści wraz z enterem i zostawiamy do następnego odczytu
   funkcjaAnalizujaca( $linia ); //możemy coś zwracać lub nie, to jest obojętne.
}

Oczywiście to trzeba ładnie ubrać w pętelkę gdzie będziemy się kręcić aż otrzymamy EOF (End Of File). Oczywiście można to wszystko ubrać w klasę, konfigurowalne zmienne, w dodatkowe zabawki typu zliczanie ilości linii, statystyka czasów analizy poszczególnych linii i inne wesołe rzeczy. Wszystkie takie rzeczy możecie podejrzeć w skrypcie który ja przygotowałem dla własnych celów, gdzie większość tych rzeczy jest już dodana.

Teraz apropo jednoczesnym przetwarzaniu więcej niż jednej linii jednocześnie. Niestety muszę zmartwić wielu z was, działa to jedynie pod systemami *unix oraz jedynie pod konsolą czyli wywoływane z linii poleceń. Windows oraz mod-php dla apache odpadają. To już jest ograniczenie od strony php. Będziemy korzystać z modułu Process Control, który nie jest domyślnie kompilowany do PHP. Żeby nie było nieścisłości to nie jest wielowątkowość ale fork czyli rozwidlenie procesu. Główny skrypt który jest rodzicem, tworzy dziecko które jest jego kopią. U nas tylko dzieci będą analizować pojedyncze linie logów, a rodzic będzie starał się nad tym „przedszkolem” zapanować. Zasady działania forków nie będę tłumaczył, jest Manual, jest Wikipedia no i Google. Wiec ustalamy sobie maksymalną ilość dzieci. Niestety w zależności od sprzętu możecie zrobić ich więcej lub mniej. Musicie po testować różne ustawienia. Więc przykładowo będziemy pracowali z czwórką dzieci. Jako że procesy się nie komunikują między sobą wykorzystamy funkcję, która obsługuje otrzymane sygnały (pcntl_signal) a dokładniej chodzi nam o sygnał zakończenia procesu dziecka czyli SIGCHLD. Przy tworzeniu dziecka powiększamy licznik o 1 a gdy otrzymamy sygnał zamknięcia pomniejszamy. W ten sposób jesteśmy w stanie jakoś zapanować nad tym wszystkim. a oto przykład (brany gdzieś z manuala ale ten jest w miarę przejrzysty):

$child = 0;
$max=3;
function sig_handler($signo) {
    global $child; //zmienna która trzyma ilość "wyprodukowanych" dzieci
    switch ($signo) {
        case SIGCHLD:
            --$child;
            break;
        //tutaj możemy obsługiwać inne sygnały jak na przykład zamkniecie głównego skryptu, lub dowolnie wybrane przez nas sygnały
    }
}
 
pcntl_signal(SIGCHLD, "sig_handler");
 
for( $a=0; $a < 20; $a++ ) {
	$child++;
	$pid=pcntl_fork();
 
	if ($pid == -1) {
		die("Nie mozna zrobić dziecka");
	} elseif ($pid) {
 
		if ( $child >= $max ) {
			echo "Za dużo dzieci w przedszkolu \n";
			pcntl_wait($status);
		}
	} else {
		sleep( rand(1,10) );
		file_put_contents('./file.log', $a.'.', FILE_APPEND );  //zadanie do wykonania
		//dla przykładu wykonujemy zapis do pliku dla każdego dzieciaka, żeby pokazać że to naprawdę działa
		// a sleep pokaże ze czasami w różnych kolejnościach będzie to wykonywane, ze względu na rożny czas wykonania zadania
 
		exit;
	}
}

Tyle mechanizmu, który czyta plik. Jeśli chodzi o analizę pliku to już zależy co my tam robimy. Jako że kiedyś przymierzałem się do jakiegoś dużego analizatora to wykombinowałem takie małe wyrażenie regularne. Znając życie albo posiada błędy albo można go jeszcze zoptymalizować. Może i kiedyś przy tym usiądę ale chyba nie dziś. A oto ten malutki tasiemiec.

preg_match('/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) ([^\s]+) ([^\s]+) \[(\d{2}\/[a-zA-Z]{3}\/\d{4}:\d{2}:\d{2}:\d{2} [+|-]\d{4})\] "(?:(POST|GET|PUT|DELETE|CONNECT|OPTIONS|HEAD|TRACE) ((?:http:\/\/|\/)?[^\s]*(?:\/[^\/\s]*)?) (HTTP\/\d\.\d))" ([1-5]\d{2}) (-|\d+) "([^"]*)" "([^"]*)"/', $linia, $match);
list($calosc, $ip, $niemampojecia, $http_user, $data, $method, $url, $http_protocol, $http_code, $transfer, $referrer, $user_agent) = $match;

Oczywiście można to po swojemu wykorzystać. Ja osobiście, najczęściej zliczam wykorzystany transfer przez daną domenę. A jeśli chcecie zobaczyć jak tą całą opowieść ubrałem w skrypt to zapraszam do ściągnięcia pliku gdzie jest spakowany skrypt główny oraz przykładowe rozszerzenie do analizy logów ‘Combined’ z Apache. Należy pamiętać, że skrypt który zlicza transfer z logów, nie powinien działać w trybie „pseudo-wielowątkowy”, ponieważ transfer jest zliczany w pamięci php, czyli jest zapisany w zmiennych. Jeśli ktoś ma ochotę to może przerobić tak skrypt aby zliczał transfer w pliku, w bazie danych lub innym zewnętrznym nośniku.

Autor wpisu: Zyx, dodany: 05.04.2009 09:42, tagi: php

Niedawno, przy okazji wpisu o integrowaniu Doctrine z ZF-em obiecałem, że następnym razem napiszę o współdziałaniu Open Power Template'a 2. Dlatego dzisiejszy wpis będzie poświęcony właśnie temu zagadnieniu. Integracja obu tych bibliotek jest o tyle prosta, że rozwijany jest port, który pozwala szybko połączyć jedno z drugim, lecz należy pamiętać, iż w przeciwieństwie do większości innych rozwiązań, nie bazuje on na zwykłym rozszerzeniu klasy Zend_View, lecz na wymianie całej warstwy widoku.
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.