[PHP, MVC] Test

0

Witam, napisałem taki krótki kod, żeby zobaczyć, jak powinna być zbudowana aplikacja na zasadzie MVC. I mam takie małe pytanie: czy powinno to być zrobione na takiej zasadzie, jak zrobiłem to w kodach poniżej? Czy może trzeba to robić inaczej?

index.php (widok):

<!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=iso-8859-2" />
</head>
<body>
<form method="post" action="search.php">
<input type="text" name="szukaj" /><br />
<input type="submit" />
</form>
<?php
   if(isset($_GET['zmienna'])) {
     echo $_GET['zmienna'];
   }
?>
</body>
</html>

search.php (kontroler):

<?php
   require_once('request.php');
   if(isset($_POST['szukaj'])) {
      $reqObj = new Request();
   } else echo('Źle wpisane dane');
?>

request.php (model):

<?php

     class request {
     
         private $_get;
         private $_post;

         function __construct() {
             $this->_post = $_POST['szukaj'];
             $this->szukaj();
         }
         
         function szukaj() {
             $abc = $this->_post;
             header('Location:index.php?zmienna='.$abc);
         }
     }
     
?>
0

Chyba nie miałeś jeszcze do czynienia z frameworkami?
Moim zdaniem schemat który zaprezentowałeś mija się z MVC :)

0

Od biedy można to nazwać MVC, straasznie naciągane :)
Szczególnie jeśli chodzi o model. Co robi model? Zajmuje się obsługą danych. A u Ciebie pojawiła się funkcja header, która nie ma z danymi nic wspólnego. To powinno być w kontrolerze.

Zobacz jak działają frameworki MVC, np. Kohana, CakePHP, CodeIgniter ( i Zend Framework, aczkolwiek jest bardziej złożony ) i porównaj :)

0

Z kolei w kontrolerze nie powinno być echo -- to rzecz dla widoku.

0

W sumie jestem zdania że najpierw trzeba choć spróbować własnego MVC, a przynajmniej poznać jak powinno wyglądać od kuchni MVC w PHP, a później się rzucić na frameworkim. Także zrozumienia MVC na podstawie fw będzie bardzo trudne, jak się wcześniej chociaż jednej uproszczonej, ale jednak prawidłowej implementacji nie poznało.
Zawsze polecam tą książkę:

http://apress.com/book/view/9781590593806

Ostatnio ciężko o polskie wydanie.

Tak na "pałę" do MVC nie ma co podchodzić. To tak jak adept boksu na pierwszym treningu od razu rzucony sparing, nie dość że dostanie mocno po głowie, to jeszcze złych nawyków nabierze.

Generalnie trochę własnej inicjatywy, a nie tak wszystko za rączkę, przeczytać najpierw choć jedną dobrą książkę odnośnie MVC (chociażby tą co wymieniłem wyżej) i innych wzorcach a dopiero później zadawać pytania.

0

Dzięki. GhostDog, co do tej książki którą mi podałeś...wolałbym na razie poszukać jej w internecie, a za darmo jej tam nie znalazłem :P Czytałem o MVC w PHP zaawansowane programowanie, ale jest tam wielki kod na kilka stron, którego na prawdę nie chce mi się analizowć tylko po to, żeby zrozumieć jak powinien wyglądać kontroler, widok i model (a zresztą coś mi się wydaje, że ten kod jest kiepski, używa zmiennych globalnych). Mógłby ktos wkleić jakiś krótki, przykładowy kod, działający zgodnie z zasadami MVC, żebym wiedział mniejwięcej jak to wszystko powinno wyglądać?

0

Źle szukałeś, sam mam ją w pdf.

0

Jak Ci się nie chce to odpuść sobie całkiem MVC...
Ten kod nie jest ani kiepski, ani nie używa zmiennych globalnych, poza tymi, które musi używać, $_POST etc

Jedyne co mnie w nim irytuje to że autor zaczyna nazwy metod z dużej litery, a że to długie nazwy bo chciał żeby były właśnie opisowe, czytelniejsze.

0

Czasami piszą książki Ci, którzy na prawdę nie powinni tego robić ;)

0

Poczytałem trochę o MVC, przeanalizowałem kody, nawet wyklepałem swój własny. Wszystko działa, tylko że przy wpisaniu niedozwolonych znaków nie wyświetla błędu, lecz przekierowuje na stronę startową. Kod jest na podstawie tego z PHP Zaawansowane Programowanie, klasa request jest taka sama.

Sam nie lubię jak ktoś na forum wkleja ogromne kody, ale ufam, że większość ludzi zna chociażby klasę request właśnie z tej książki ;) Na wszelki wypadek ją wkleję:

(może od razu powiem, że kod tylko zwiększa o 1 liczbę wpisywaną do pola tekstowego [rotfl] )

klasa request:

<?php

     require_once('constants.phpm');
     require_once('constraint.phpm');
     require_once('constraintfailure.phpm');

     class Request {
     
         private $GetVars; // tablice GET
         private $PostVars; // tablice POST
         private $CookieVars; // tablice COOKIES
         private $RequestVars; // tablice REQUEST
         private $OriginalRequestObject; // kopia parametrów REQUEST w przypadku, gdy nastąpiło przekierowanie na pierwotną strnę
         
         private $RedirectFollowingFailure; // okresla, czy obiekt OriginalRequest zostal utworzony przez przekierowanie na strone pierwotną
         
         private $RedirectOnFailure; // okresla, czy w przypadku nieprawidlowosci przekierowanie nastapilo na pierwotną stronę czy na inny adres URL
         private $FailureRedirectURL; // gdy powyższa zmienna ma wartosc true, zwraca adres przekierowania
         private $FailureDefaultRedirectURL; // gry powyzsza zmienna ma pusta wartosc, a OnFC ma wartość TRUE
         
         private $ParameterMethodHash; // tablica ograniczeń, zawiera nazwę parametru, sposób, w jaki parametr ma zostać przesłany oraz obiekt
                                       // ograniczenia reprezentujący test, jak ma zostać wykonany
         private $HasRunTests; // czy na danym obiekcie przeprowadzono już testy prawidłowości
         private $Failures; // tablica obiektów reprezentujących tetsty, które wypadły negatywnie

         function __construct($check_for_cookie = true) {
             global $_GET;
             global $_POST;
             global $_COOKIE;
             global $_REQUEST;
             $this->GetVars = $_GET;
             $this->PostVars = $_POST;
             $this->CookieVars = $_COOKIE;
             $this->RequestVars = $_REQUEST;
             if ($check_for_cookie) {
                 if ($this->CookieVars["phprqcOriginalRequestObject"]) {
                     $cookieVal = $this->RequestVars["phprqcOriginalRequestObject"];
                     $this->RedirectFollowingFailure = true;
                     if (strlen($cookieVal) > 0) {
                         $strResult = setcookie("phprqcOriginalRequestObject", "", time() - 3600, "/");
                         $origObj = unserialize(stripslashes($cookieVal));
                         $this->OriginalRequestObject = &$origObj;
                         $this->RequestVars["phprqcOriginalRequestObject"] = "";
                         $this->GetVars["phprqcOriginalRequestObject"] = "";
                         $this->PostVars["phprqcOriginalRequestObject"] = "";
                     }
                     $this->RedirectOnFailure = true;
                 } else {
                     $this->RedirectOnFailure = false;
                 }
             } else {
                 $this->RedirectOnFailure = false;
             }
             $this->ParameterMethodHash = array(); // rozdzielenie zmiennej na tablicę
             $this->Failures = array(); // rozdzielenie zmiennej na tablicę
             $this->HasRunTests = false; // nie zaczęto testó tworząc obiekt klasy request
         }

         function IsRedirectFollowingFailure() {
             return($this->RedirectOnFailure); // zwraca informacje, czy ma zostac wywolane automatyczne przekierowanie na inny adres URL
         }

         function GetOriginalRequestObject() {
             if($this->RedirectOnFailure) {
                 return($this->OriginalRequestObject); // zwraca oryginalne zmienne $_REQUEST jeśli nastąpiło przekierowanie na pierwotną stronę
             }
         }

         function SetRedirectOnFailure($TrueOrFalse) {
             $this->RedirectOnFailure = $TrueOrFalse; // okresla, czy ma zostac wywolane automatyczne przekierowanie na inny adres URL, czy na stronę pierwotną
         }

         function SetRedirectTargetURL($URL) {
             $this->FailureRedirectURL = $URL; // ustala adres przekierowania
         }

         function SetDefaultRedirectURL($URL) {
             $this->FailureDefaultRedirectURL = $URL; // ustala adres przekierowania, jesli poprzednia funkcja jest pusta
         }

         function GetParameterValue($Parameter) {
            return($this->RequestVars[$Parameter]); // zwraca określoną wartosc $_REQUEST
         }

         function GetParameter() {
             return($this->RequestVars); // zwraca bezposrednia kopie $_REQUEST
         }

         function AddConstraint($Parameter, $Method, $Constraint) {
             $newHash["PARAMETER"] = $Parameter;
             $newHash["METHOD"] = $Method;
             $newHash["CONSTRAINT"] = $Constraint;
             $this->ParameterMethodHash[] = $newHash; // nadaje ograniczenia
         }

         function TestConstraints() {
             $this->HasRunTests = true;
             $anyFail = false;
             for ($i = 0; $i <= sizeof($this->ParameterMethodHash)-1; $i++) {
                 $Parameter = $this->ParameterMethodHash[$i]["PARAMETER"];
                 $Method = $this->ParameterMethodHash[$i]["METHOD"];
                 $Constraint = $this->ParameterMethodHash[$i]["CONSTRAINT"];
                 $ActualValue = "";
                 if($Method == VERB_METHOD_GET) {
                     $ActualValue = $this->GetVars[$Parameter];
                 }
                 if($Method == VERB_METHOD_POST) {
                     $ActualValue = $this->PostVars[$Parameter];
                 }
                 $ConstraintType = $Constraint->GetConstraintType();
                 $ConstraintOperand = $Constraint->GetConstraintOperand();
                 
                 $Fail = false;
                 $FailureObject = new ConstraintFailure($Parameter, $Method, $Constraint);
                 switch ($ConstraintType) {
                     case CT_MINLENGTH:
                         if(strlen((string)$ActualValue) < (integer)$ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_MAXLENGTH:
                         if(strlen((string)$ActualValue) > (integer)$ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_PERMITTED_CHARACTERS:
                         for ($j = 0; $j <= strlen($ActualValue)-1; $j++) {
                             $Char = substr($ActualValue, $j, 1);
                             if (!(strpos($ConstraintOperand, $Char) === false)) {
                                 $Fail = true;
                             }
                         }
                         break;
                     case CT_NON_PERMITTED_CHARACTERS:
                         for ($j = 0; $j <= strlen($ActualValue)-1; $j++) {
                             $Char = substr($ActualValue, $j, 1);
                             if (strpos($ConstraintOperand, $Char) === false) {
                                 $Fail = true;
                             }
                         }
                         break;
                     case CT_LESSTHAN:
                         if($ActualValue >= $ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_MORETHAN:
                         if($ActualValue <= $ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_EQUALTO:
                         if($ActualValue != $ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_NOT_EQUALTO:
                         if($ActualValue == $ConstraintOperand) {
                             $Fail = true;
                         }
                         break;
                     case CT_MUST_MATCH_REGEXP:
                         if(!(preg_match($ConstraintOperand, $ActualValue))) {
                             $Fail = true;
                         }
                         break;
                     case CT_MUST_NOT_MATCH_REGEXP:
                         if(preg_match($ConstraintOperand, $ActualValue)) {
                             $Fail = true;
                         }
                         break;
                 }
                 if($Fail) {
                     $anyFail = true;
                     $this->ConstraintFailure[] = $FailureObject;
                 }
             }
                 if($anyFail) {
                     if($this->RedirectOnFailure) {
                         $targetURL = $_ENV["HTTP_REFERER"];
                         if(!$targetURL) {
                             $targetURL = $this->FailureDefaultRedirectURL;
                         }
                         if($this->FailureRedirectURL) {
                             $targetURL = $this->FailureRedirectURL;
                         }
                         if($targetURL) {
                             $objToSerialize = $this;
                             $strSerialization = serialize($objToSerialize);
                             header("Location: $targetURL");
                             exit(0);
                         }
                     }
                 }
                 return(!($anyFail)); // zwraca TRUE, jesli wszystkie testy wypadly pomyslnie, w przeciwnym wypadku zwraca FALSE
         }
         
         function GetConstraintFailures() {
             if(!$this->HasRunTests) {
                 $this->TestConstraints();
             }
             return($this->ObjConstraintFailure);
         }
     }
     
?>

I teraz kod aplikacji. Wszystko zaczyna się od tego pliku:

<?php

 // model, wywoływany jako pierwszy
 
 require_once('constants.phpm');
 require_once('constraint.phpm');
 require_once('constraintfailure.phpm');
 require_once('controller.php');
 
 $templateFile = 'inkrementajka.phtml'; // zdefiniowanie pliku szablonu
 
 $displayHash = array(); // inicjalizacja zmiennej przechowującej ewentualne błędy
 
 $objRequest = new Request();
 $hadProblems = $objRequest->IsRedirectFollowingFailure();
 
 $displayHash["HADPROBLEMS"] = $hadProblems;
 
 if ($hadProblems) { // jeśli pojawiły się błędy
  $failingRequest = $objRequest->GetOriginalRequestObject();
  $failures = $objRequest->GetConstraintFailures();
  $displayHash["PROBLEMS"] = array();
  for ($i = 0; $i < sizeof($failures); $i++) {
    $thisFailure = &$failures[$i];
    $thisFailing = $thisFailure->GetFailedObject();
    $typeOfFailure = $thisFailing->GetConstraintType();
    switch ($typeOfFailure) {
     case CT_PERMITTED_CHARACTERS:
      $displayHash["PROBLEMS"][] = "Wpisane dane nie są liczbą";
      break;
    }
  }
 }
 require_once($templateFile);
 exit(0);
 
?>

inkrementajka.phtml, czyli plik dołączany w poprzednim kodzie:

<html>
<head>
 <title>Inkrementajka Jebajka</title>
</head>
<body>

<-- widok, wywoływany jako pierwszy -->

 <h1>Inkrementajka Jebajka</h1>
 <form method="get" action="inkrementajkaResults.php">
  <input type="text" name="liczba" /><br />
  <input type="submit" value="Jebaj!" />
 </form>
 
 <?php if($displayHash["PROBLEMS"]) { ?>
 Niestety, wystąpiły problemy.<br />
 <?php for ($i = 0; $i < sizeof($displayHash["PROBLEMS"]); $i++) { echo $displayHash["PROBLEMS"][$i]; } } ?>

</body>
</html>

inkrementajkaResults.php, plik do którego następuje przekierowanie po wpisaniu liczby w polu tekstowym w poprzednim pliku:

<?php

 // kontroler, wywoływany jako drugi, po wpisaniu liczby w polu tekstowym
 
 require_once('constants.phpm');
 require_once('constraint.phpm');
 require_once('constraintfailure.phpm');
 require_once('controller.php');
 
 $templateFile = "inkrementajkaResults.phtml";
 
 $displayHash = array();
 
 $objRequest = new Request();
 $objRequest->SetRedirectOnFailure(true);
 
 $objConstraint = new Constraint(CT_NON_PERMITTED_CHARACTERS, "1234567890");
 $objRequest->AddConstraint("liczba", VERB_METHOD_GET, $objConstraint);
 
 $objRequest->SetDefaultRedirectURL("inkrementajka.php");
 $objRequest->TestConstraints();
 
 // w tym miejscu wszystkie testy zakończyły się powodzeniem, można więc rozpocząć inkrementację
 
 $displayHash["RESULT"] = $objRequest->GetParameterValue("liczba") + 1;
 
 require_once($templateFile);
 exit(0);
 
?>

Plik dołączany w poprzednim kodzie:

<html>
<head>
 <title>Inkrementajka Jebajka</title>
</head>
<body>

<-- widok drugi z wynikami, wywoływany jako czwarty i ostatni -->

 <h1>Inkrementajka Jebajka</h1>
 <h3>Wyniki inkrementajki jebajki:</h3>
 
 <?php echo $displayHash["RESULT"]; ?>
 
 <br /><br />
 <a href="inkrementajka.php">Wróć, aby zinkrementować inną liczbę</a>

</body>
</html>

Może jestem ślepy, ale nie wiem, co jest nie tak. Podejrzewam, że to dlatego, ponieważ nic się nie zapisuje do zmiennej RedirectOnFailure w klasie Request, nie wiem czemu.

Z góry dzięki za pomoc i cierpliwość, jeśli chociażby komuś chciało się przewinąć na dół nie załamując rąk, patrząc na taki kod wklejony na forum ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1