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: Spawnm, dodany: 23.04.2009 16:11, tagi: php

Jak można zauważyć na wortalu pojawiły się przyjazne linki.
W przeciwieństwie to tych 'znanych' nie korzystają z mod_rewrite oraz
nie musimy pisać dodatkowych aplikacji.

Autor wpisu: Spawnm, dodany: 22.04.2009 13:07, tagi: php

Myślisz że twoje pliki są bezpieczne ?
Myślisz że póki ich nie zaincludujesz do głównego pliku nic nie zrobią ?
A może jednak ? Może ktoś bez twojej wiedzy właśnie przegląda twój admin panel?

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 $this

dzieki 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: Marcin MySZ Sztolcman, dodany: 17.04.2009 18:59, tagi: php

Dawno tu nie pisałem… No cóż, (bardzo) dużo pracy, życie osobiste i takie tam - to odstrasza od blogowania ;) Jeśli już, to od czasu do czasu coś publikuję jeśli chodzi o zdjęcia, a sprawy “kodowe” to raczej “robię” niż o nich piszę :)

Jako że od kilka dni jestem na L4, to się ostro opierdzielam, ale dopiero dziś jestem w stanie podjąć jakikolwiek intelektualny wysiłek… No to popatrzyłem sobie m.in. na GoldenLine. Dziś na forum PHPowym ktoś poruszył dość banalny problem, ktoś inny podrzucił rozwiązanie (preg_replace_callback (), a ja zacząłem się zastanawiać czemu wszyscy w PHP tak napierają na regexpy (rozumiem w Perlu, ale PHP?). Jak zacząłem się zastanawiać jak to zrobić bez regexpów, to zacząłem się bawić w zakodowanie tego ;)

Najpierw zrobiłem dość banalną wersję, przy użyciu strlen (), strpos () i substr (), i chciałem ją podać jako wersję hardcore ;) Wtedy pomyślałem sobie, że prawdziwa wersja hardcore, to byłaby bez użycia tychże funkcji… najprostsza postać tego to zastąpienie tychże funkcji swoimi ;) I o ile substr () i strpos () są dość banalne, o tyle dla mnie prawdziwym hardcorem jest strlen () ;)

Oczywiście nie są to najbardziej optymalne rozwiązania (a jeśli są to tylko przypadkiem), bo jeśli chodzi o optymalizację, to trzeba by używać wersji natywnych… :) A całość warto potraktować stricte jako zabawę, którą dla mnie było pisanie tego :)

W całym “problemie” chodziło o zastąpienie w tekście wystąpień “[userId]ID[/userId]” tym, co zostanie wyplute przez dodatkową funkcję której podajemy zawartość tego co jest między znacznikami. Użycie preg_replace_callback () jest chyba najbardziej intuicyjnym rozwiązaniem, ale nie jedynym… :) Poniżej obydwie wersje: hardcore i bardziej hardcore - enjoy ;)

hardcore

function replace_user_id ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => strlen ($tags['start']),
        'end'   => strlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = strlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = strpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = strpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= substr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (substr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

bardziej hardcore

class __mstrlen__ErrH {
    private static $error = false;
    private function __construct () {}
    static public function errh ($errno, $errstr, $errfile = '', $errline = 0, $errctx = array ()) {
        if ($errno != E_NOTICE) {
            return false;
        }

        $expected = 'Uninitialized string offset';
        for ($i=0; $i<26; ++$i) {
            if ($expected[$i] != $errstr[$i]) {
                return false;
            }
        }

        self::$error = true;
    }
    public static function isError () {
        return self::$error;
    }
    public static function zero () {
        self::$error = false;
    }
}

function mstrlen ($str) {
    $str = (string) $str;

    $len = -1;
    __mstrlen__ErrH::zero ();
    set_error_handler (array ('__mstrlen__ErrH', 'errh'), E_NOTICE);
    while (__mstrlen__ErrH::isError () === false) {
        ++$len;
        $q = $str[$len];
    }

    restore_error_handler ();
    return $len < 0 ? 0 : $len;
}

function mstrpos ($str, $seek, $offset=0) {
    if (!is_int ($offset) || $offset < 0) {
        $offset = 0;
    }

    $str_len = mstrlen ($str);
    if ($offset > $str_len) {
        return false;
    }

    $seek_len = mstrlen ($seek);
    for ($i=$offset; $i < $str_len; ++$i) {
        for ($j=0; $j < $seek_len; ++$j) {
            if ($str[$i + $j] != $seek[$j]) {
                break;
            }
        }

        if ($j == $seek_len) {
            return $i;
        }
    }
    return false;
}

function msubstr ($str, $start, $length = null) {
    $str_len = mstrlen ($str);
    if (!is_int ($start)) {
        trigger_error ('Incorrect offset');
    }
    else if ($start >= $str_len) {
        return false;
    }
    else if ($start < 0) {
        $start = $str_len + $start;
    }

    if (!is_int ($length)) {
        $length = $str_len - $start;
    }
    else if ($length < 0) {
        $length = $str_len + $length - $start;
    }
    else if ($length + $start > $str_len) {
        $length = $str_len - $start;
    }

    $ret = '';
    for ($i=0; $i < $length; ++$i) {
        $ret .= $str[$i + $start];
    }

    return $ret;
}

function replace_user_id2 ($str, $fn) {
    $tags = array ('start' => '[userId]', 'end' => '[/userId]');
    $tag_len = array (
        'start' => mstrlen ($tags['start']),
        'end'   => mstrlen ($tags['end'])
    );
    $offset = $pos_end = 0;
    $ret    = '';
    $strlen = mstrlen ($str);

    while ($pos_end < $strlen) {
        if (
            ($pos_start = mstrpos ($str, $tags['start'], $pos_end)) !== false &&
            ($pos_end   = mstrpos ($str, $tags['end'], $pos_start)) !== false
        ) {
            $ret .= msubstr ($str, $offset, $pos_start - $offset);
            $pos_start += $tag_len['start'];

            $ret .= $fn (msubstr ($str, $pos_start, $pos_end - $pos_start));

            $pos_end += $tag_len['end'];
            $offset = $pos_end;
        }
        else {
            break;
        }
    }

    return $ret;
}

Autor wpisu: piotrooo89, dodany: 16.04.2009 12:37, tagi: php, css

Zastanawiałeś się jak ułatwić użytkownikom odnalezienie się na stronie? Nie chcesz robić zbyt trudnych map serwisu? Ten artykuł pokaże Ci jak możesz ułatwić użytkownikowi życie w sposób prosty i przystępny.

Na samym początku trzeba przystosować stronę do tego aby można było wyświetlać ową nawigację. Nasz serwis powinien być zbudowany za pomocą tablic super globalnych $_GET, na zasadzie includowania. Właśnie taką obsługę będę pokazywał. Includowanie powinno odbywać się w sposób następujący:

www.jakas-strona.pl/page=home

nas w szczególności będzie interesował fragment:

page=home

jako że to jest potrzebne do includowania plików posłużymy się tym faktem.

Aby odczytać jaką aktualnie stronę przeglądamy należy dodać do odpowiedni wpis, wygląda on tak:

  1. <body id="<?php echo $page ?>">

Teraz aby w zmiennej $page była jakaś wartość (w naszym wypadku nazwa aktualnie przeglądanej strony) musimy skorzystać z PHP aby to odczytać.

Kod:

  1. <?php
  2. $link = $_SERVER['REDIRECT_QUERY_STRING'];
  3. $r = explode('=', $link);
  4. $page = $r[1];
  5. $page = $page ? $page : 'glowna'
  6. ?>
  7.  
  8. <body id="<?php echo $page ?>">

Za pomocą tablicy super globalnej $_SERVER z kluczem REDIRECT_QUERY_STRING odczytujemy wszytko co jest nam potrzebne aby zobaczyć w jakim miejscu się znajdujemy. Następnie explode() “rozwalamy” to aby uzyskać aktualną stronę. Teraz w id będziemy przechowywać dynamicznie nazwę strony którą aktualnie przeglądamy.

Aby obsłużyć te funkcje należy napisać to co ma się dziać po najechaniu i/lub kliknięciu myszką na poszczególny element menu. U mnie jest to tylko dolna krawędź obramowania i wygląda to następująco:

  1. #menu a:hover
  2. {
  3. border-bottom: 2px black solid;
  4. }
  5. body#glowna a#nh,
  6. body#firma a#nf,
  7. body#wyp a#nw,
  8. body#uslugi a#nz,
  9. body#kon a#nk
  10. {
  11. border-bottom: 2px black solid;
  12. }

Należy również pamiętać aby nadać znacznik id linką:
  1. <a href="index.php?link=glowna"  id="nh">Strona główna</a>
  2. <a href="index.php?link=firma" id="nf">O firmie</a>
  3. <a href="index.php?link=wyp" id="nw">Wyposażenie</a>
  4. <a href="index.php?link=uslugi" id="nz">Zakres usług</a>
  5. <a href="index.php?link=kon" id="nk">Kontakt</a>

Tak zaprojektowane menu pozwoli nam cieszyć się ładnym i zarazem prostym efektem.

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.