Forum forumweb.pl Strona Główna  
Oficjalne forum serwisu: kurshtml.boo.pl
Konkurs
Konkurs
   Regulamin
Regulamin
   FAQ
FAQ
   Szukaj
Szukaj
   Użytkownicy
Użytkownicy
   Grupy
Grupy
   IRC/czat
IRC/czat
   Facebook
Facebook
   Rejestracja
Rejestracja
 
Zmień swój profil  ::  Zaloguj się, by sprawdzić wiadomości  ::  Zaloguj



Zobacz następny temat
Zobacz poprzedni temat
Odpowiedz do tematu  Forum forumweb.pl Strona Główna » Porady i tutoriale
Autor Wiadomość
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 16.02.2010 17:56
[PHP] PHP Light MVC
Zacytuj zaznaczone   ^

Czasem zdarza się, że musimy wykonać jakiś mało skomplikowany projekt. Zastanawiamy się wtedy, czy nie wystarczyłoby napisać prostego szkieletu strony przy użyciu instrukcji include. Bo czy warto wytaczać na muchy armatę w postaci jakiegoś zaawansowanego frameworka, jak np. Zend Framework?

Problem w tym, że proste projekty w przyszłości lubią się rozrastać. Początkowo ciągniemy wcześniejszy pomysł z użyciem include, ale w końcu dochodzimy do wniosku, że najlepiej to byłoby teraz to wszystko przepisać od nowa. Rozwiązanie, które tutaj zaproponuję, jest niemal tak samo niewielkie, jak proste dołączanie plików za pomocą include. Pozawala jednak stworzyć szkielet aplikacji według najlepszych praktyk programowania zorientowanego obiektowo opartego o wzorzec projektowy MVC (ang. Model-View-Controller). Co więcej, mimo niewielkich rozmiarów, w oparciu o ten framework można stworzyć również naprawdę sporą i złożoną aplikację, co zapewni możliwość rozwoju Twojego projektu w przyszłości.

Wymagana wiedza:


PHP Light MVC

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
/**
 * PHP Light MVC.
 * Extremely small but powerful MVC framework for PHP.
 * @package PHP Light MVC
 * @version 1.4.1
 * @author Sławomir Kokłowski {@link http://www.kurshtml.boo.pl}
 * @copyright Do NOT remove this comment!
 * @license LGPL
 */

/**
 * Auto load function.
 * To autoload class dir_subdir_ClassName, put it in a file "./dir/subdir/ClassName.class.php"
 * Base directory is current directory with this __autoload function.
 * If class was not found "404 Not Found" HTTP header would be sent and script would exit.
 * @param string $className Name of class to autoload
 */
function __autoload($className)
{
    if (
preg_match('/^[a-z][0-9a-z]*(_[0-9a-z]+)*$/i', $className))
    {
        
$path = dirname(__FILE__) . '/' . str_replace('_' , '/', $className) . '.class.php';
        if (
file_exists($path))
        {
            require_once
$path;
            return;
        }
    }
    
_Controller::http404();
}

/**
 * Model.
 * Requirements:
 * - PDO library.
 */
abstract class _Model
{
    
/**
     * Data Source Name.
     * @static string
     */
    
static $dsn;
    
    
/**
     * Database username.
     * @static string
     */
    
static $user;
    
    
/**
     * Database password.
     * @static string
     */
    
static $password;
    
    
/**
     * Database connection.
     * Singleton.
     * @static PDO
     */
    
protected static $db;
    
    
/**
     * DVO class name.
     * @var string
     */
    
protected $className;
    
    
/**
     * SQL array.
     * To implement method i.e. $this->getItems() set "getItems" key and write prepared statement SQL as value.
     * @var array
     */
    
protected $sql = array();
    
    private
$sth = array();
    
    
/**
     * Constructor.
     */
    
function __construct()
    {
        if (empty(
self::$db) && !empty(self::$dsn))
        {
            
self::$db = new PDO(self::$dsn, self::$user, self::$password);
            
self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
    }
    
    
/**
     * Executes database prepared statement.
     * Normally it is not required to call this method, because it is caled internally.
     * @param string $name Key name from $this->sql array
     * @param array $arguments Parameters to fill in prepered statement
     * @return array Result
     */
    
protected function execute($name, $arguments=array())
    {
        if (!
array_key_exists($name, $this->sql)) throw new Exception('Execute of undefined sql ' . $name);
        if (!
array_key_exists($name, $this->sth)) $this->sth[$name] = self::$db->prepare($this->sql[$name]);
        foreach (
$arguments as $key => $value)
        {
                    switch (
gettype($value))
                    {
                        case
'boolean':
                            
$type = PDO::PARAM_BOOL;
                            break;
                        case
'integer':
                            
$type = PDO::PARAM_INT;
                            break;
                        case
'NULL':
                            
$type = PDO::PARAM_NULL;
                            break;
                        default:
                            
$type = PDO::PARAM_STR;
                    }
                    
$this->sth[$name]->bindValue($key, $value, $type);
                }
        
$this->sth[$name]->execute();
        
$result = array();
        if (
preg_match('/^[^A-Z_]*SELECT[^A-Z_]/i', $this->sql[$name]))
        {
            while ((
$object = $this->className ? $this->sth[$name]->fetchObject($this->className) : $this->sth[$name]->fetchObject())) $result[] = $object;
        }
        else
        {
            
$object = (object)array('count' => $this->sth[$name]->rowCount());
            if (
preg_match('/^[^A-Z_]*(INSERT|REPLACE)[^A-Z_]/i', $this->sql[$name])) $object->id = self::$db->lastInsertId();
            
$result[] = $object;
        }
        return
$result;
    }
    
    function
__call($name, $arguments)
    {
        if (!
array_key_exists($name, $this->sql)) throw new Exception('Call to undefined method ' . get_class($this) . '::' . $name . '()');
        return
$this->execute($name, array_key_exists(0, $arguments) ? $arguments[0] : array());
    }
}

/**
 * View.
 * Usually it isn't necessary to extend this class.
 * To visualize template print object itself.
 * In template file you have access to special variables:
 * - array $_config: Configuration reference,
 * - string $_dir: Base directory with template files.
 */
class _View
{
    
/**
     * Base directory with template files.
     * @static string
     */
    
static $dir = '';
    
    
/**
     * Global variables passed to every template file.
     * @static array
     */
    
static $var = array();
    
    
/**
     * Template file name.
     * @var string
     */
    
protected $file;
    
    
/**
     * Template assigned variables.
     * @var array
     */
    
protected $data = array();
    
    
/**
     * Constructor.
     * @param string $file Template file name.
     */
    
function __construct($file)
    {
        
$this->file = $file;
    }
    
    function
__get($name)
    {
        return
array_key_exists($name, $this->data) ? $this->data[$name] : null;
    }
    
    function
__set($name, $value)
    {
        
$this->data[$name] = $value;
    }
    
    function
__toString()
    {
        if (!
file_exists(self::$dir . $this->file)) return '';
        foreach (
array_merge(self::$var, $this->data) as $name => $value)
        {
            if (
$name != 'this') $$name = $value;
        }
        unset(
$name, $value);
        
$_config = _Controller::$config;
        
$_dir = self::$dir;
        
ob_start();
        require
$_dir . $this->file;
        
_Controller::$config = $_config;
        return
ob_get_clean();
    }
}

/**
 * Controller.
 */
abstract class _Controller
{
    
/**
     * Confiruration data.
     * @var static
     */
    
static $config;
    
    
/**
     * 404 Not Found action.
     * Sends HTTP header and exits.
     */
    
static function http404()
    {
        
header('HTTP/1.1 404 Not Found');
        exit;
    }
    
    
/**
     * HTTP redirect action.
     * Sends HTTP header and exits.
     * @param string $location Absolute or relative URL
     * @param int $status HTTP response status code
     */
    
static function httpRedirect($location, $status=302)
    {
        
$location = preg_replace(array('/^([^\r\n]+)/', '/(^|\/)\.(\/|$)/', '/[^\/]*\/\.\.(\/|$)/'), array('$1', '$1', ''), $location);
        
header('Location: ' . (preg_match('/^[0-9a-z.+-]+:/i', $location) ? '' : 'http://' . $_SERVER['SERVER_NAME'] . (preg_match('/^\//', $location) ? '' : rTrim(dirName($_SERVER['SCRIPT_NAME']), '/') . '/')) . $location, true, $status);
        exit;
    }
}
?>


...i to wszystko! Po usunięciu komentarzy, kod będzie miał ok. 100 linii, a oferuje całkiem sporo:
  • Automatyczne ładowanie kodu klas - już nie musisz pamiętać o wstawianiu kilkudziesięciu instrukcji require_once, żeby aplikacja w ogóle mogła wystartować; zostanie załadowany tylko ten kod, który rzeczywiście jest potrzebny i dokładnie wtedy, kiedy jest potrzebny
  • Wsparcie dowolnej bazy danych, do której został zaimplementowany sterownik PDO
  • Wbudowana najskuteczniejsza ochrona przed atakami SQL injection
  • Obsługa PHP View - systemu szablonów tak naprawdę dającego największe możliwości (nie musisz się uczyć żadnego kolejnego metajęzyka - jeśli znasz PHP, znasz PHP View)
  • Wsparcie dla kontrolerów MVC oraz konfiguracji aplikacji


Przykład

Najlepszym dowodem na prostotę, łatwość i szybkość tworzenia aplikacji przy użyciu tego frameworka, będzie chyba przykład. Wspólnie zbudujemy stronę, która będzie wyświetlać listę artykułów oraz pozwoli użytkownikowi przeczytać dowolny z nich.

Baza danych

Przykładowa aplikacja opiera się na bazie danych MySQL.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
CREATE TABLE `articles` (
  `
id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `
title` varchar(255) NOT NULL,
  `
content` text NOT NULL,
 
PRIMARY KEY (`id`)
);

INSERT INTO `articles` (`id`, `title`, `content`) VALUES(1, 'Artykuł 1', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
INSERT INTO `articles` (`id`, `title`, `content`) VALUES(2, 'Artykuł 2', 'Integer vel nisi quis risus imperdiet bibendum.');
INSERT INTO `articles` (`id`, `title`, `content`) VALUES(3, 'Artykuł 3', 'Morbi sem leo, porta vel tristique vitae, bibendum vel felis.');


Pliki

Teraz utworzymy strukturę katalogów. Poniższy opis to tylko przykład. W swojej aplikacji możesz wykorzystać zupełnie inny układ plików - taki, jak będzie Ci najbardziej odpowiadał. Framework nie wymusza tutaj jakiejś specjalnej struktury.

  • lib
    • controller
      • Index.class.php
    • model
      • Article.class.php
    • view
      • layout
        • index.phtml
      • article.phtml
      • index.phtml
    • config.php
    • index.php
  • index.php


lib/index.php

W tym pliku umieszczamy kod frameworka, przestawiony wcześniej.

lib/config.php

Konfiguracja naszej aplikacji - w tym dane dostępowe do bazy danych.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
return array(
    
'_db' => array(
        
'dsn' => 'mysql:host=localhost;dbname=test',
        
'user' => 'root',
        
'password' => ''
    
),
    
'title' => array('PHP Light MVC')
);
?>


Warto zauważyć, że choć konfiguracja domyślnie jest zwykłą tablicą asocjacyjną, to poprzez implementację interfejsu ArrayAccess może stać się obiektem. Dzięki temu można zaimplementować dodatkowe metody oraz przeprowadzić walidację wprowadzanych wartości zmiennych konfiguracyjnych.

lib/model/Article.class.php

W tym pliku umieścimy nasz model, oparty o wzorzec projektowy DAO.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class model_Article extends _Model
{
    protected
$sql = array(
        
'getItems' => 'SELECT id, title FROM articles ORDER by title',
        
'getItem' => 'SELECT * FROM articles WHERE id = :id'
    
);
}
?>


...i to wszystko! Od razu mamy zaimplementowane dwie metody pobierające dane z bazy: getItems i getItem.

Standardowo każda metoda DAO zwraca tablicę obiektów klasy stdClass. Można również zaimplementować własną klasę DVO - tzn. pojedynczy element "tablicy" danych - wystarczy podać jej nazwę w chronionej własności $className - np.:
Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
    protected $className = 'Article';


lib/view/layout/index.phtml

Domyślny szkielet HTML dla całej strony.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<!DOCTYPE html
    
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
<
head>
    <
meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <
title><?php echo htmlspecialchars(implode(' - ', array_reverse($_config['title']))); ?></title>
</
head>
<
body>

<?php echo $main; ?>

</body>
</
html>


PHP jako język szablonów? Czemu nie! Nie zapominajmy, że PHP pierwotnie powstał właśnie jako zaawansowany język szablonów. Dzisiaj powoli wraca się do tego. Systemy takie jak np. Smarty mają sporo przeciwników. Po co tworzyć nowy język, mieć problemy z podświetlaniem i podpowiadaniem składni w edytorze, skoro znacznie większe możliwości daje sam PHP? To prawda, że Smarty można skonfigurować w taki sposób, aby niedouczony programista nie wywołał w pliku szablonu np. zapytania SQL. W przypadku PHP View to sami musimy się troszczyć o zachowanie wytycznych jakie powinien spełniać poprawnie zaimplementowany widok MVC, ale czy tylko z tego powodu warto przekreślać możliwości, jakie daje ten rodzaj widoku MVC?

A jeżeli nie podoba nam się rozwlekła składnia <?php echo ...; ?>, to jeśli tylko dyrektywa short_open_tag jest włączona dla naszej instalacji PHP, można skrócić zapis:

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?=$main?>


lib/view/index.phtml

Zawartość strony głównej, tzn. lista wszystkich artykułów.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<ul>
<?php foreach ($data as $item): ?>
<li><a href="?action=article&amp;id=<?php echo $item->id; ?>"><?php echo $item->title; ?></a></li>
<?php endforeach; ?>
</ul>


W szablonach PHP View korzystniej jest używać alternatywnej składni struktur kontrolnych. Pamiętajmy, że ten plik powinien wyglądać jak szablon wizualizujący HTML, a nie plik PHP z jednym dużym blokiem kodu i wieloma porozrzucanymi w tym kodzie instrukcjami echo lub print.

lib/view/article.phtml

Treść wybranego artykułu.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<h1><?php echo $data[0]->title; ?></h1>
<?php echo $data[0]->content; ?>


lib/controller/Index.class.php

Kontroler MVC, obsługujący dwie akcje: index (strona główna z listą artykułów) i article.

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class controller_Index extends _Controller
{
    protected
$layout;
    protected
$model;
    
    function
__construct()
    {
        
$this->layout = new _View('layout/index.phtml');
        
$this->model = new model_Article;
    }
    
    function
index()
    {
        
$view = new _View('index.phtml');
        
$view->data = $this->model->getItems();
        
$this->layout->main = $view;
        return
$this->layout;
    }
    
    function
article()
    {
        if (empty(
$_GET['id'])) self::http404();
        
$data = $this->model->getItem(array('id' => $_GET['id']));
        if (empty(
$data[0])) self::http404();
        
self::$config['title'][] = $data[0]->title;
        
$view = new _View('article.phtml');
        
$view->data = $data;
        
$this->layout->main = $view;
        return
$this->layout;
    }
}
?>


index.php

Na koniec pozostało tylko zainicjalizować aplikację:

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
require_once './lib/index.php';    // biblioteka frameworka

_Controller::$config = include './lib/config.php';    // wczytanie konfiguracji aplikacji
_View::$dir = './lib/view/';    // ustawienie katalogu bazowego dla plikow z szablonami widoku
_Model::$dsn = _Controller::$config['_db']['dsn'];    // konfiguracja bazy danych dla modelu
_Model::$user = _Controller::$config['_db']['user'];
_Model::$password = _Controller::$config['_db']['password'];

if (empty(
$_GET['controller'])) $_GET['controller'] = 'Index';    // przypisanie domyslnego kontrolera
if (empty($_GET['action'])) $_GET['action'] = 'index';    // przypisanie domyslnej akcji

$controller = 'controller_' . $_GET['controller'];
$controller = new $controller;
if (!
method_exists($controller, $_GET['action'])) _Controller::http404();    // kontroler nie ma takiej akcji
echo $controller->$_GET['action']();    // wyswietlenie kodu zrodlowego HTML
?>


Historia zmian

  • 1.0.0 - pierwsza publiczna wersja
  • 1.0.1 - ujednolicone wyrażenie regularne autolodera oraz kod HTTP 404
  • 1.1.0 - "leniwe" ładowanie danych; nieistniejące pliki szablonów widoku są pomijane
  • 1.1.1 - klasa rezultatu dziedziczy po modelu, aby nie było konieczność udostępniania publicznie metody execute
  • 1.1.2 - poprawka w implementacji iteratora przez klasę rezultatu w celu wyeliminowania nieprawidłowego dodatkowego pustego, zwracanego elementu na końcu danych
  • 1.2.0 - dane dostępowe bazy danych nie muszą być przechowywane w konfiguracji
  • 1.2.1 - zapytania DML nie są ładowane "leniwie"; prawidłowa obsługa danych zwracanych przez zapytania DML
  • 1.3.0 - zapytania INSERT/REPLACE zwracają identyfikator wstawionego rekordu; globalne zmienne widoku _View::$var, które raz ustawione przekazywane są później do każdego pliku szablonu; akcja przekierowania HTTP _Controller::httpRedirect
  • 1.3.1 - możliwość podania względnego adresu URL przy przekierowaniach _Controller::httpRedirect
  • 1.4.0 - usunięcie klasy _Result (leniwe ładowanie danych - odroczone wykonywanie zapytań DQL) z podstawowej wersji biblioteki
  • 1.4.1 - obsługa klauzuli LIMIT dla MySQL w zapytaniach przygotowanych

 

_________________
stop-ie6.png


Ostatnio zmieniony przez kurshtml dnia 29.08.2010 14:20, w całości zmieniany 23 razy
Użytkownik otrzymał punkt pomocy za ten post od: arve_lek, SkyMan
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
CapaciousCore
Użytkownik
CapaciousCore

Płeć: Mężczyzna
Wiek: 21
Dołączył(a): 30 Sty 2009
Posty: 3991
Pomocy: 161
Skąd: Chełm
Post Wysłany: 16.02.2010 18:19
Zacytuj zaznaczone   ^

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
'/^[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*$/i'

Nie mozna tego uproscic?

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
header('HTTP/1.1 404 Not Found');

Powtarza sie, a celem programisty jest napisanie kodu tak zeby sie nie powtarzal.

Niby wszystko ok tylko moim zdaniem lepiej uzywac jakiegos mechanizmu tpl anizeli takie cos:
Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<ul>
<?php foreach ($data as $item): ?>
<li><a href="?action=article&amp;id=<?php echo $item->id; ?>"><?php echo $item->title; ?></a></li>
<?php endforeach; ?>
</ul>

Conajmniej o polowe mozna zapis skrocic gdyby to byly tpl'e.

- za ' zamiast " jak juz sie czepiac szczegolow.
 

_________________
PHP Freelancer / falowniki
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
 
 
 
 
 
 
OperaWinXP1440x900
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 16.02.2010 20:11
Zacytuj zaznaczone   ^

CapaciousCore napisał(a):
Nie mozna tego uproscic?

Nie Smile Chyba, że coś zaproponujesz.

CapaciousCore napisał(a):
Niby wszystko ok tylko moim zdaniem lepiej uzywac jakiegos mechanizmu tpl

Widzę, że nie czytałeś uważnie Wink http://nosmarty.net/
Wiesz, że Zend Framework używa czegoś podobnego, tzn. "PHP View" (klasa nazywa się Zend_View)? Świat zaczyna wracać do PHP jako języka szablonów wizualizacji widoku. Poza tym spróbuj napisać inny system szablonów o takich możliwościach w niecałych 40 liniach kodu.

O ile skrócisz taki zapis?
Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<ul>
<?foreach($data as $item):?>
<li><a href="?action=article&amp;id=<?=$item->id?>"><?=$item->title?></a></li>
<?endforeach?>
</ul>

W moim przykładzie nie użyłem skróconego zapisu, aby mieć pewność, że kod uruchomi w każdej konfiguracji PHP.

CapaciousCore napisał(a):
' zamiast "

Możesz rozwinąć myśl?
 

_________________
stop-ie6.png


Ostatnio zmieniony przez kurshtml dnia 16.02.2010 20:30, w całości zmieniany 1 raz
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
CapaciousCore
Użytkownik
CapaciousCore

Płeć: Mężczyzna
Wiek: 21
Dołączył(a): 30 Sty 2009
Posty: 3991
Pomocy: 161
Skąd: Chełm
Post Wysłany: 16.02.2010 20:28
Zacytuj zaznaczone   ^

Dostep do rzeczy napisanych w " jest szybszy anizeli tych w '. Roznica niewielka (3-5%) ale przy duzych projektach moze wiele znaczyc. Chce zauwazyc, ze dostep do zmiennych z uzycie ' jest wolniejszy.

A ja nie mowilem o Smarty... Co malo masz mechanizmow tpl lepszych i szybszych od smarty? Wiem, ze takie cos jest w Zend ale nie jestem jego zwolennikiem.

Z ptk tpl bedzie skrocony z ptk kodu wynikowego bedzie taki sam.

Chodzi o latwosc modyfikacji. No juz wystarczy zobaczyc WordPress'a.
 

_________________
PHP Freelancer / falowniki
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
 
 
 
 
 
 
OperaWinXP1440x900
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 16.02.2010 20:58
Zacytuj zaznaczone   ^

CapaciousCore napisał(a):
Dostep do rzeczy napisanych w " jest szybszy anizeli tych w '

Parsowanie interpolowanych stringów (") jest szybsze w przypadku podstawiania wielu zmiennych. Tak czy inaczej są to na tyle pomijalne różnice, że chyba nie warto o tym dyskutować.

CapaciousCore napisał(a):
Co malo masz mechanizmow tpl lepszych i szybszych od smarty?

I konieczność nauki kolejnego metajęzyka? Problemy z kolorowaniem i podpowiadaniem składni w edytorze. Poza tym zwróć uwagę, że jakikolwiek system szablonów nie weźmiesz, to jego kod będzie wielokrotnie większy niż cała biblioteka, którą zaprezentowałem, a wtedy to nie miałoby żadnego sensu, bo gdybym musiał i tak dołączyć tak obszerny kod, to wolałbym już skorzystać np. z Zenda lub innego znanego frameworka. To nie miał być kolejny pełnowymiarowy framework - konkurencja dla Zenda czy Symfony, tylko rozwiązanie na tyle "lekkie", żeby warto było go zastosować, kiedy wahamy się, czy nie zrobić strony na prostych include'ach. Ważnym argumentem jest również, że nie trzeba się uczyć żadnego kolejnego języka szablonów ani obsługi skomplikowanej biblioteki. Od razu można przystąpić do pracy i szybko zakończyć taki prosty projekt, mając jednocześnie możliwość rozbudowy go w przyszłości.

Łatwość modyfikacji zależy od programisty - czy ma jakiekolwiek pojęcie co powinien, a czego nie powinien robić widok. Jak sobie zrobisz np. mysql_query w szablonie, to sam sobie zaszkodzisz na przyszłość. Nie widzę żadnego powodu, aby dobrze napisany PHP View był trudny do modyfikacji w przyszłości. A WordPress jest właśnie przykładem nieprawidłowo napisanego widoku. Są w nim takie kwiatki, jak np. bezpośrednie odwoływanie się do modelu, wizualizacja danych poza widokiem, a widok zamiast pasywnie wyświetlać dane, samodzielnie aktywnie odwołuje się po dane, tzn. sam nie wiadomo skąd wie, które funkcje powinien wywołać, aby pobrać dane, które musi wyświetlić. Widok nie powinien robić takich rzeczy. Widok nie wie, skąd ma pobrać dane. Wizualizacja nie powinna się odbywać nigdzie poza widokiem. Widok może skorzystać tylko z tych danych, które przekazał mu kontroler.
 

_________________
stop-ie6.png
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
CapaciousCore
Użytkownik
CapaciousCore

Płeć: Mężczyzna
Wiek: 21
Dołączył(a): 30 Sty 2009
Posty: 3991
Pomocy: 161
Skąd: Chełm
Post Wysłany: 16.02.2010 22:07
Zacytuj zaznaczone   ^

3-5% robi swoje moim zdaniem :] jak pisac to dobrze. Zreszta w artykule masz na uwadze, ze projekt sie ma rozrosnac :] no wiec sory.

A tam wiekszosc jezykow tpl jest bardzo podobna do siebie. Ma podobne mechanizmy. Jezeli edytor bylby wbudowany w system np. jak WP to przeciez z odpowiednia implementacja mozna dodac kolorowanie jak i podpowiedzi.

Skoro mowisz, ze takie kwiatki to z pewnoscia ktos taki jak Ty zwrocil juz na to uwage i dlaczego to jeszcze nie zostalo zmienione, co ?

kurshtml napisał(a):
które funkcje powinien wywołać, aby pobrać dane, które musi wyświetlić.

Wystarczy pare dni poobcowac i zwykly uzytkownik bedzie mial oglad co i jak. Zreszta bardzo dobra moim zdaniem maja dokumentacje tlumaczaca jak uzywac poszczegolnych funkcji/fragmentow kodu.


kurshtml napisał(a):
Jak sobie zrobisz np. mysql_query w szablonie, to sam sobie zaszkodzisz na przyszłość.

Nie wiem skad trzasnoles taki pomysl ale to jest polityczne samobojstwo.
 

_________________
PHP Freelancer / falowniki
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
 
 
 
 
 
 
OperaWinXP1440x900
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 16.02.2010 22:57
Zacytuj zaznaczone   ^

CapaciousCore napisał(a):
3-5% robi swoje moim zdaniem

Napisałem również, że interpolacja jest szybsza tylko w pewnym szczególnym przypadku, a nie zawsze Smile

CapaciousCore napisał(a):
wiekszosc jezykow tpl jest bardzo podobna do siebie

Większość języków programowania jest podobna do siebie. Wystarczy poznać instrukcje sterujące, kilka funkcji i już można zacząć pisać... tylko, że najpierw trzeba poświęcić czas, żeby to poznać, a potem jeszcze zdobyć doświadczenie, żeby pisać kod szybko i w optymalny sposób. Wybacz, ale jeśli szukam prostego rozwiązania na projekt, który skończy się np. za 3 dni, to nie mam ochoty cały dzień grzebać w dokumentacji jakiegoś systemu szablonów.

CapaciousCore napisał(a):
Jezeli edytor bylby wbudowany w system np. jak WP to przeciez z odpowiednia implementacja mozna dodac kolorowanie jak i podpowiedzi.

A ja mam swój ulubiony edytor i nie mam zamiaru używać innego Wink Dlaczego ktoś ma mnie do tego zmuszać?

CapaciousCore napisał(a):
dlaczego to jeszcze nie zostalo zmienione, co ?

Bo programiści WP być może (powtarzam: być może, a nie na pewno) nie do końca czują, jak powinien wyglądać prawidłowy podział warstw w aplikacji Web? Bo żeby to poprawić, trzeba by przepisać wszystko od zera, gdyż tak bardzo jest to fundamentalne założenie obecnego kodu WP?

CapaciousCore napisał(a):
Wystarczy pare dni poobcowac i zwykly uzytkownik bedzie mial oglad co i jak.

Co nie zmienia faktu, że do MVC ta koncepcja pasuje jak pięść do nosa Wink

CapaciousCore napisał(a):
Nie wiem skad trzasnoles taki pomysl ale to jest polityczne samobojstwo.

Daleko trzeba szukać? Widziałem coś takiego w PHP-Nuke lub Post-Nuke. WordPress bezpośrednio nie wykonuje co prawda zapytań SQL w szablonach widoku, ale robi za to coś innego: widok sam wywołuje funkcję, która pobiera dane z bazy. Na dodatek ta funkcja jeszcze ubiera pobrane dane w znaczniki HTML. To gdzie tutaj właściwie jest kontroler, a gdzie widok? Widok przejmuje rolę kontrolera, a przy tym oddaje część swoich zadań w inny obszar aplikacji Rolling Eyes Spróbuj teraz napisać alternatywny widok, który wyświetla dane np. w formacie PDF, RTF, XML lub innym, bez przepisywania połowy kodu lub wstawiania setek if-ów w wielu miejscach kodu.

W sumie to bardzo dobrze, że wywiązała się ta dyskusja, bo można na konkretnych przykładach poznać, jak nie należy pisać aplikacji.
 

_________________
stop-ie6.png
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
minchal
Użytkownik
minchal

Płeć: Mężczyzna
Dołączył(a): 18 Sty 2005
Posty: 903
Pomocy: 15
Skąd: Złotoryja
Post Wysłany: 17.02.2010 01:24
Zacytuj zaznaczone   ^

logeen, a załóżmy teraz, że w szablonie lib/view/layout/index.phtml chcesz wyświetlić nazwę zalogowanego użytkownika, zawsze.

Dochodzą więc dodatkowe założenia:
1. użytkownika trzymamy jako instancję model_User w sesji
2. controller nie musi wiedzieć, czy użytkownik jest zalogowany, ale jak potrzebuje, uzyskuje takie info.
3. jeśli chcemy wygenerować np. RTF czy PDF aplikacja w ogóle nie musi wykorzystywać sesji, bo ani controller ani widok nie potrzebuje informacji o użytkowniku.

czyli w skrócie: fajnie byłoby inicjować dane o użytkowniku leniwie.

Możesz pokazać, jak wg Ciebie "semantycznie" będzie wpleść takie zarządzanie użytkownikiem do obecnego kodu?

Pytam z czystej ciekawości, jak ty byś to zrobił w ogólnym MVC (a ten prosty kod wyżej wydaje się OK do tego celu).

--
PS. bardzo dobre dwa artykuły Smile
 
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
Numer Gadu-Gadu
6170208
 
 
Jabber
 
 
 
 
OperaLinux1280x800
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 17.02.2010 04:03
Zacytuj zaznaczone   ^

Dopisane: Przeczytaj najpierw ten post.

Na przykład tak:

MySQL

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
CREATE TABLE `users` (
  `
id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `
login` varchar(255) NOT NULL,
  `
password` char(40) NOT NULL,
 
PRIMARY KEY (`id`),
 
UNIQUE KEY `login` (`login`)
);

INSERT INTO `users` (`id`, `login`, `password`) VALUES(1, 'admin', 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3');


login: admin
hasło: test

lib/Model.class.php

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
/**
 * PHP Light MVC data lazy loading extension.
 * Executes DQL queries exactly when it is needed.
 * @package PHP Light MVC
 * @version 1.0.0
 * @since 1.4.0
 * @author Sławomir Kokłowski {@link http://www.kurshtml.boo.pl}
 * @copyright Do NOT remove this comment!
 * @license LGPL
 */

/**
 * Model with data lazy loading.
 */
abstract class Model extends _Model
{
    
/**
     * Lazy executes DQL query.
     * Normally it is not required to call this method, because it is caled internally.
     * @param string $name Key name from $this->sql array
     * @param array $arguments Parameters to fill in prepered statement
     * @return Result Result object
     */
    
protected function execute($name, $arguments=array())
    {
        return
preg_match('/^[^A-Z_]*SELECT[^A-Z_]/i', $this->sql[$name]) ? new Result($this, 'executeSql', array($name, $arguments)) : $this->executeSql($name, $arguments);
    }
    
    
/**
     * Executes DQL query immediately.
     * Normally it is not required to call this method, because it is caled internally.
     * @param string $name Key name from $this->sql array
     * @param array $arguments Parameters to fill in prepered statement
     * @return Result Result object
     */
    
protected function executeSql($name, $arguments=array())
    {
        return new
Result(parent::execute($name, $arguments));
    }
}

/**
 * Model result.
 * Lazy loads data exactly when it is needed.
 */
class Result extends Model implements ArrayAccess, Iterator, Countable
{
    
/**
     * Result data.
     * @var array
     */
    
protected $data = array();
    
    private
$model;
    private
$method;
    private
$arguments = array();
    private
$executed = false;
    private
$valid;
    
    
/**
     * Constructor.
     * @param mixed $model Model instance or result data if $method parameter is empty
     * @param string $method Model method name
     * @param array $arguments Parameters to be passed to the model method, as an indexed array
     */
    
function __construct($model, $method=null, $arguments=array())
    {
        if (empty(
$method))
        {
            
$this->data = $model;
            
$this->execute = true;
        }
        else
        {
            
$this->model = $model;
            
$this->method = $method;
            
$this->arguments = $arguments;
        }
    }
    
    
/**
     * Checks if data is empty.
     * @return bool
     */
    
function isEmpty()
    {
        
$this->executeData();
        return empty(
$this->data);
    }
    
    function
offsetExists($offset)
    {
        
$this->executeData();
        return
array_key_exists($offset, $this->data);
    }
    
    function
offsetGet($offset)
    {
        
$this->executeData();
        if (isset(
$this->data[$offset])) return $this->data[$offset];
    }
    
    function
offsetSet($offset, $value)
    {
        
$this->data[$offset] = $value;
    }
    
    function
offsetUnset($offset)
    {
        unset(
$this->data[$offset]);
    }
    
    function
current()
    {
        
$this->executeData();
        return
current($this->data);
    }
    
    function
key()
    {
        
$this->executeData();
        return
key($this->data);
    }
    
    function
next()
    {
        
$this->executeData();
        
$this->valid = next($this->data) !== false;
    }
    
    function
rewind()
    {
        
$this->executeData();
        
reset($this->data);
        
$this->valid = !$this->isEmpty();
    }
    
    function
valid()
    {
        return
$this->valid;
    }
    
    function
count()
    {
        
$this->executeData();
        return
count($this->data);
    }
    
    protected function
executeData()
    {
        if (!
$this->executed && is_object($this->model) && is_a($this->model, '_Model'))
        {
            
$this->data = call_user_func_array(array($this->model, $this->method), $this->arguments);
            if (
is_object($this->data) && is_a($this->data, 'Result'))
            {
                
$this->data->executeData();
                
$this->data = $this->data->data;
            }
            
$this->executed = true;
        }
    }
}
?>


lib/model/User.class.php

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class model_User extends Model
{
    protected
$sql = array(
        
'login' => 'SELECT id, login FROM users WHERE login = :login AND password = :password'
    
);
    
    function
login($params)
    {
        
$result = $this->execute('login', array('login' => $params['login'], 'password' => sha1($params['password'])));
        if (!
$result->isEmpty())
        {
            
self::init();
            
$_SESSION['user'] = $result[0];
        }
        return
$result;
    }
    
    function
logout()
    {
        
self::init();
        
session_destroy();
        unset(
$_SESSION['user']);
    }
    
    function
getCurrentUser()
    {
        return new
Result($this, 'getCurrentUserData');
    }
    
    function
getCurrentUserData()
    {
        
self::init();
        return new
Result(empty($_SESSION['user']) ? array() : array($_SESSION['user']));
    }
    
    private static function
init()
    {
        if (!
session_id()) session_start();
    }
}
?>


lib/view/layout/index.phtml

Dochodzi następujący kod:

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php if (isset($user->login)): ?>
    
Zalogowany: <?php echo htmlspecialchars($user->login); ?> - <a href="?action=logout">wyloguj</a>
<?php else: ?>
    
<a href="?action=login">Zaloguj</a>
<?php endif; ?>


lib/view/login.phtml

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<form action="?action=login" method="post">
<
input type="text" name="login" />
<
input type="password" name="password" />
<
input type="submit" value="OK" />
</
form>


lib/controller/Index.class.php

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class controller_Index extends _Controller
{
    protected
$layout;
    protected
$model;
    protected
$modelUser;
    
    function
__construct()
    {
        
$this->layout = new _View('layout/index.phtml');
        
$this->model = new model_Article;
        
$this->modelUser = new model_User;
        
$this->layout->user = $this->modelUser->getCurrentUser();
    }
    
    function
login()
    {
        if (!isset(
$_POST['login']) || !isset($_POST['password']) || !$this->modelUser->login($_POST))
        {
            
$this->layout->main = new _View('login.phtml');
            return
$this->layout;
        }
        return
$this->index();
    }
    
    function
logout()
    {
        
$this->modelUser->logout();
        return
$this->index();
    }
    
    
// ...reszta tak jak wczesniej
}
?>


A jeśli chodzi np. o widok PDF, który nie potrzebuje danych o zalogowanym użytkowniku, to są co najmniej dwa sposoby, aby niepotrzebnie nie inicjalizować sesji:
  1. Można utworzyć osobny kontroler, który nie będzie używał metod login, logout ani getCurrentUser klasy model_User
  2. Można wykorzystać ten sam kontroler, ale nie wywoływać w nim metody login ani logout klasy model_User ani nie korzystać ze w szablonie ze zmiennej $user - mimo, iż obiekt CurrentUser zostanie utworzony, w widoku nie wyświetlimy żadnych jego własności, więc sesja nie będzie zainicjalizowana

 

_________________
stop-ie6.png


Ostatnio zmieniony przez kurshtml dnia 14.03.2010 13:38, w całości zmieniany 3 razy
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
minchal
Użytkownik
minchal

Płeć: Mężczyzna
Dołączył(a): 18 Sty 2005
Posty: 903
Pomocy: 15
Skąd: Złotoryja
Post Wysłany: 17.02.2010 14:24
Zacytuj zaznaczone   ^

Nie liczyłem na pełny kod, ale ok Wink

Tylko dlaczego do sesji nie wrzucić całego użytkownika, tak żeby to sesja martwiła się o jego serializację?

A co myślisz o takim pomyśle, żeby zrobić nową klasę view_Layout, z automatycznie ustawionym szablonem na layout/index.phtml oraz dodanym użytkownikiem:

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz

class view_Layout extends _View {
  function
__construct() {
    
parent::__construct('layout/index.phtml');
    
$modelUser = new model_User;
    
$this -> user = $modelUser->getCurrentUser();
  }
}


W takim przypadku, mając kilka controllerów korzystających z głównego szablonu nie trzeba w każdym dodawać użytkownika.
(Bo może oprócz użytkownika w sidebarze strony będziemy chcieli pokazać "popularne artykuły", "ostatnio dodane" itd.)

Czy przeniesienie takiej podstawowej logiki do widoku uważasz za prawidłowe?
 
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
Numer Gadu-Gadu
6170208
 
 
Jabber
 
 
 
 
OperaLinux1280x800
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 17.02.2010 17:09
Zacytuj zaznaczone   ^

minchal napisał(a):
Czy przeniesienie takiej podstawowej logiki do widoku uważasz za prawidłowe?

No właśnie nie do końca jestem co do tego przekonany. W takim przypadku chyba lepiej by było utworzyć drugi kontroler, który dziedziczy po pierwszym. W ten sposób nie trzeba by było kolejny raz pobierać danych bieżącego użytkownika i przekazywać je do layoutu, a przy tym nie powstanie "aktywny" widok, który sam wywołuje model, a więc w zasadzie powinien być kontrolerem. Zwróć uwagę, że jeśli w przyszłości szukałbyś miejsca, gdzie są pobierane dane użytkownika, a zapomniałbyś, jak to zostało zaimplementowane, to raczej skierowałbyś się do kontrolera, a nie to widoku. I właśnie o to chodzi - żeby logika biznesowa aplikacji nie była porozrzucana w wielu miejscach, a tylko tam, gdzie jej miejsce - czyli w kontrolerze MVC.

Myślałem jeszcze nad poprzednim problemem z leniwym ładowaniem danych. Rozwiązanie, które podałem wcześniej, rozwiązuje sprawę, ale tylko dla tego konkretnego przypadku. W rzeczywistym projekcie analogiczny problem powstanie np. w przypadku menu - również ma być na każdej stronie w widoku HTML, ale np. w PDF już niekoniecznie. Z tego właśnie powodu, rozbudowałem poprzedni kod frameworka. Teraz do widoku nie jest przekazywana tablica obiektów, tylko obiekt nowej klasy Result. Implementuje on jednak odpowiednie interfejsy, dzięki czemu możemy go w widoku używać prawie tak samo, jak zwykłej tablicy indeksowanej. W przeciwieństwie do tablicy, potrafi on w sposób przezroczysty pobrać dane w momencie, kiedy próbujemy uzyskać do nich dostęp, czyli np. wyświetlić je w widoku. Jeśli tego nie zrobimy, to dane nigdy nie zostaną pobrane, a więc zaoszczędzimy na zapytaniach SQL.

Zastanawiałem się, czy to nie stanowi znowu próby przeniesienia logiki kontrolera do widoku, ale według mnie - nie. Widok sam nie może pobrać tych danych. Nie wie nawet, że są one doładowywane w momencie, kiedy chce je wyświetlić. Widok nie musi wywoływać żadnej specjalnej metody na danych, aby to zrobić. Według mnie nie stanowi to również próby przeniesienia kompetencji kontrolera do modelu ani zadań modelu do jakiejś oddzielnej klasy Result, ponieważ podczas leniwego ładowania danych nie zawiera się żadna ukryta logika biznesowa. Sam obiekt rezultatu co prawda wywołuje metodę modelu, co teoretycznie powinien wykonywać tylko kontroler, ale sam nie decyduje, jaką metodę wykonać. Jest mu to przekazane z zewnątrz w modelu, który został wywołany przez kontroler. Nie stanowi to zatem przeniesienia logiki poza kontroler ani dostępu do danych poza modelem, a jedynie odroczenie na nieco później pobrania danych.

Nowa wersja frameworka już znajduje się w pierwszym poście tego wątku. Udoskonaliłem w niej również jeszcze jedną rzecz. Mianowicie teraz, jeśli widok nie znajdzie pliku szablonu, nie wygeneruje żadnego błędu - po prostu go pominie. Dzięki temu wystarczy w pliku startowym zainicjalizować inny katalog bazowy _View::$dir i mamy gotowy nowy rodzaj widoku, z możliwością wykorzystania z tymi samymi kontrolerami. Jeśli np. w widoku PDF nie znajdzie się szablon wyświetlający użytkownika, to po prostu nie będzie wywołany. Jako zadanie samodzielne można sobie zaimplementować rozszerzony widok - pochodną klasy _View, który w przypadku braku pliku szablonu w aktualnym widoku, pobierze ten plik z jakiejś wersji domyślnej. Możliwości jest sporo i nie trzeba w tym celu modyfikować kodu frameworka.

A oto jak będzie teraz wyglądało rozwiązanie problemu z wyświetlaniem danych użytkownika:

lib/model/User.class.php

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class model_User extends _Model
{
    protected
$sql = array(
        
'login' => 'SELECT id, login FROM users WHERE login = :login AND password = :password'
    
);
    
    function
login($params)
    {
        
$result = $this->execute('login', array('login' => $params['login'], 'password' => sha1($params['password'])));
        if (!
$result->isEmpty())
        {
            
self::init();
            
$_SESSION['user'] = $result[0];
        }
        return
$result;
    }
    
    function
logout()
    {
        
self::init();
        
session_destroy();
        unset(
$_SESSION['user']);
    }
    
    function
getCurrentUser($execute=false)
    {
        if (!
$execute) return new Result($this, 'getCurrentUser', array(true));
        
self::init();
        return new
Result(empty($_SESSION['user']) ? array() : array($_SESSION['user']));
    }
    
    private static function
init()
    {
        if (!
session_id()) session_start();
    }
}
?>


lib/view/layout/index.phtml

Zamiast poprzedniej wstawki, będzie teraz:

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php if ($user->isEmpty()): ?>
    
<a href="?action=login">Zaloguj</a>
<?php else: ?>
    
Zalogowany: <?php echo htmlspecialchars($user[0]->login); ?> - <a href="?action=logout">wyloguj</a>
<?php endif; ?>


lib/controller/Index.class.php

Kod:   Zaznacz   Podgląd (X)HTML   Uruchom   Zapisz
<?php
class controller_Index extends _Controller
{
    protected
$layout;
    protected
$model;
    protected
$modelUser;
    
    function
__construct()
    {
        
$this->layout = new _View('layout/index.phtml');
        
$this->model = new model_Article;
        
$this->modelUser = new model_User;
        
$this->layout->user = $this->modelUser->getCurrentUser();
    }
    
    function
login()
    {
        if (!isset(
$_POST['login']) || !isset($_POST['password']) || $this->modelUser->login($_POST)->isEmpty())
        {
            
$this->layout->main = new _View('login.phtml');
            return
$this->layout;
        }
        return
$this->index();
    }
    
    function
logout()
    {
        
$this->modelUser->logout();
        return
$this->index();
    }
    
    
// ...reszta bez zmian
}
?>

 

_________________
stop-ie6.png


Ostatnio zmieniony przez kurshtml dnia 14.03.2010 13:35, w całości zmieniany 2 razy
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
CapaciousCore
Użytkownik
CapaciousCore

Płeć: Mężczyzna
Wiek: 21
Dołączył(a): 30 Sty 2009
Posty: 3991
Pomocy: 161
Skąd: Chełm
Post Wysłany: 17.02.2010 17:13
Zacytuj zaznaczone   ^

Mam pytanko. Ty szukujesz pod cos grunt czy tak sobie piszesz o MVC czy tam wzorcach projektowych?
 

_________________
PHP Freelancer / falowniki
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
 
 
 
 
 
 
OperaWinXP1440x900
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 17.02.2010 17:23
Zacytuj zaznaczone   ^

Pisałem o wzorcach projektowych i o MVC właśnie po to, żeby przygotować grunt pod wątek, który właśnie czytasz Smile Zdarzyło mi się po prostu przy okazji takiego niewielkiego projektu napisać prosty framework (to już chyba szósty w mojej historii programisty Wink ) i stwierdziłem, że może się on jeszcze komuś przydać - właśnie dlatego, że jest mały i prosty w obsłudze, a przy tym ma spore możliwości, jak na taką miniaturkę. Wahałem się, czy dokonywać w nim dzisiaj modyfikacji, ale stwierdziłem, że funkcjonalność "leniwego" ładowania danych może się przydać niemal w każdym projekcie, a dzięki temu wzrośnie wydajność. A przy tym kod jest bardziej obiektowy.

Całe wprowadzenie teoretyczne było po to, żeby to co tutaj napisałem było zrozumiałe.... nie, nie planuję tworzyć kursu PHP Wink
 

_________________
stop-ie6.png
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
CapaciousCore
Użytkownik
CapaciousCore

Płeć: Mężczyzna
Wiek: 21
Dołączył(a): 30 Sty 2009
Posty: 3991
Pomocy: 161
Skąd: Chełm
Post Wysłany: 17.02.2010 17:26
Zacytuj zaznaczone   ^

Dobrze przeczytales moje intencje Smile

To moze sie rozpedz Razz CMS, Framework no i wypromuj to Very Happy Kto wie Smile moze wypali.
 

_________________
PHP Freelancer / falowniki
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
 
 
 
 
 
 
OperaWinXP1440x900
kurshtml
Administrator
kurshtml

Płeć: Mężczyzna
Wiek: 30
Dołączył(a): 02 Mar 2004
Posty: 4462
Pomocy: 43
Post Wysłany: 17.02.2010 17:37
Zacytuj zaznaczone   ^

Tworzenie kolejnego pełnowymiarowego frameworka uważam za co najmniej nierozsądne, a na pewno mało sensowne. Dzisiaj na rynku mamy tyle gotowych rozwiązań, że raczej nie warto tworzyć nowego. Gotowe rozwiązanie, takie jak np. Zend Framework - oprócz oczywistej zalety, że jest tworzone przez całą grupę programistów - ma jeszcze coś, co często się bagatelizuje, a jest niezmiernie ważne. Znany framework Open Source staje się niepisanym standardem w branży. Przychodząc pracować do jakiejś nowej firmy, albo poprawiając po kimś innym kod, nie musisz poświęcać czasu na studiowanie dokumentacji nowego frameworka - bo już ją znasz. Do tego wszyscy trzymają się jakiegoś ustalonego standardu tworzenia kodu, dzięki czemu łatwiej jest przejąć pracę po kimś.

Framework, który zaproponowałem nie ma na celu rywalizować z "gigantami", a być jedynie alternatywą raczej w małych projektach, kiedy dzięki jego prostocie nie trzeba będzie poświęcać za dużo czasu na jego naukę. Może się również przydać dla osób, które nie znają zbyt dobrze np. Zenda i nie mają czasu lub ochoty w danej chwili się go uczyć. Mój framework pozwoli im względnie szybko stworzyć aplikację, a przy tym mieć możliwość swobodnego jej rozwoju w przyszłości.
 

_________________
stop-ie6.png
  
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora  
 
 
Jabber
 
 
 
 
OperaLinux1280x800
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Szybka odpowiedź
Kod potwierdzający
Użytkownik
Temat
Very Happy Smile Sad Surprised Shocked Confused Cool Laughing Mad Razz Embarassed Crying or Very sad Evil or Very Mad Twisted Evil Rolling Eyes Wink Exclamation Question Idea Arrow Neutral Mr. Green + - *
  

  Zamknij Tagi
 
 

Zobacz następny temat
Zobacz poprzedni temat
Nie możesz pisać nowych tematów
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach

RSS Przełącz do wersji mobilnej

[trening.net.pl]
[www.olympiquem.pl] [www.anno.xon.pl]
Powered by phpBB © 2001, 2005 phpBB Group
Uruchamianie kodu dzięki Sphere Research Labs w ramach ideone.com
Style created freely by Cyber-MX :: Modified by logeen :: Sponsor: Biuro Rachunkowe
katalog stron
katalog stron
kbkteam.net
bajkar

www.bajkar.sitpchem…
Klimatyzacja
Clima Cool
www.climacool.pl
systemy CMS
Profesjonalne systemy CMS !
www.govern.pl
Sklep odżywki
Sklep odżywki
www.megapower.pl