• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Pierwsza implementacja wzorca MVC w PHP

Object Storage Arubacloud
0 głosów
337 wizyt
pytanie zadane 18 marca 2018 w Nasze projekty przez Artek Stary wyjadacz (11,800 p.)

Witam wszystkich. Tak jak w temacie - po raz pierwszy zabrałem się za implementację wzorca MVC w PHP. Poczytałem co nieco i zacząłem pisać. Z racji tego, że robię to pierwszy raz nie mogę być pewny czy zrobiłem to poprawnie dlatego proszę o ewentualne uwagi(na pewno jakieś będą :) ). Oczywiście mile widziane uwagi dotyczące samego posługiwania się językiem PHP. Jeżeli ktoś pisze nie rób tego, nie rób tamtego to prosiłbym o uzasadnienie dlaczego coś jest złe.Tworzę serwis z filmami. Na razie zaimplementowałem wyświetlanie strony głównej i wyświetlanie filmów wedle kategorii. Część kodu musiałem wkleić poza forum bo się nie zmieścił w poście. Używam przepisywania adresów url. Plik htaccess wygląda tak :

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ router.php

Wszystko trafia do router'a. Plik router.php

<?php

function autoloadClass($ClassName)
{
  if(file_exists("php/model/$ClassName.php"))
  {
	require "php/model/$ClassName.php";
  }
  else
  {
	require "php/view/$ClassName.php";  
  }
}

 spl_autoload_register('autoloadClass');
 
 
 
 class Controler
 {
	 private $userAction;   //adres url wygląda tak /sekcja wybrana przez użytkownika/dodatkowe parametry np. /kategorie/horrory
	 public $Parameters;
	 
	 function __construct() //na dzień dobry wyodrębniamy z adresu url sekcje jaka uzytkownik chce odwiedzic i ewentualne dodatkowe parametry
	 {
		$arr = explode("/",$_SERVER['REQUEST_URI']);      //tu wyodrębniam sekcję jaką chce odwiedzić użytkownik
		$UserAction = $arr[1];
		
		$this->userAction = ($UserAction === "" || $UserAction === "strona") ? "main_page" : $UserAction;  
		$arrLength = count($arr);
		
		if($arrLength > 3)
		{
		    $this->Parameters = array();  //tu będę pakował parametry - 
  		
			for($I = 2; $I < $arrLength - 1; ++$I)
            {
              array_push($this->Parameters, $arr[$I]);  //ładuję parametry do tablicy aby potem przekazać je do kontrolera
			}		
				
		}
		
	 }
	 
	 function StartAction()
	 {
		 
	     switch($this->userAction)
		 {
			case "main_page":            //tutaj kod, który pokazuje co ma się dziać gdy wybrana zostanie strona główna
			 $Parameter = $this->Parameters;
             $Movies = ($Parameter === null) ?  new MainPageMovies() : new MainPageMovies($Parameter[0]);   //pobieram informacje o filmach w modelu
			 $View = new MainPageBuilder($Movies);                //przekazuję informacje do widoku
			 require "php/view/template/MainPage.php"; //wstawiam szablon i wypełniam go widokiem
            break;

            case "kategorie":      //tutaj kod gdy użytkownik przechodzi do menu kategorii
			  $CategoryType = $this->Parameters[0];
			  
              if($CategoryType === "wszystkie")
			  {
				require "php/view/template/AllCategories.php"; 
			  }
			  else
			  {
				$Movies = new MoviesByCategory($CategoryType);
                $View = new SelectedCategoryBuilder($Movies);
                require "php/view/template/SelectedCategory.php";				
			  }
            break;			
		 }
	   
	 }
 }
 
 $controler = new Controler();
 $controler->StartAction();


?>

Pobieranie filmów z bazy danych w pliku modelu MainPageMovies.php

<?php

 class MainPageMovies
 {
	public $moviesDataArray;   //tutaj wrzucam dane filmów pobrane z bazy danych
	public $TopIndex;
	public $PageControlIndex1;
	public $ActivePagePosition;
	public $CurrentPage;
	public $MaxPageIndex;
	public $RandomImage1;  //losuję dwa obrazy i wstawiam na stronę główną
	public $RandomImage2;
	
	
	private function CreateQuery($PageNumber)  //w zależności od numeru strony tworzę odpowiednie zapytanie do bazy danych
	{
	  --$PageNumber;
		
	  if($PageNumber == 0)
	  {
		return "SELECT * FROM Pornusy ORDER BY klucz DESC LIMIT 50";   
	  }
	  else
	  {
		$Offset = $PageNumber * 50;
        return "SELECT * FROM Pornusy ORDER BY klucz DESC LIMIT 50 OFFSET $Offset";		
	  }
	    
	}
	
	private function GetRandomImages()
	{
	    $ID1 = rand(1,20);   //wybieram dwa losowo wybrane zdjęcia
        $ID2 = rand(1,20);

        while($ID1 === $ID2)
	   {
	     $ID1 = rand(1,20);
         $ID2 = rand(1,20);	
	    }
	
	   $this->RandomImage1 = "decoration-image-".$ID1;
	   $this->RandomImage2 = "decoration-image-".$ID2;	
	}
	
	private function CalculatePageControls($Total, $PageNumber)   //obliczam wartości dla kontrolek sterujących podstronami
	{
	  $MaxPageIndex = ceil($Total / 50);
	  $this->CurrentPage = $PageNumber;
	  
      if($MaxPageIndex - 5 >= $PageNumber)
      {
        $this->PageControlIndex1 = $PageNumber;
		$this->ActivePagePosition = 1;
	  }
      else
	  {
        $this->PageControlIndex1 = $MaxPageIndex - 4;
		$this->ActivePagePosition = 5 + $PageNumber - $MaxPageIndex;
	  }
	  
      $this->TopIndex = ++$Total - (--$PageNumber * 50); 
      $this->MaxPageIndex = $MaxPageIndex;
    	  
	}
	

    function __construct($PageNumber=1)   //łączenie z bazą danych i wpakowanie danych to tablicy
    {
      $dataBase = mysqli_connect();
	  
	    if(!$dataBase)
	    {
		  $moviesDataArray = null;
		  return;
	    }
		else
		{
		  $this->moviesDataArray = array();
		  $query = $this->CreateQuery($PageNumber);
		  $result = mysqli_query($dataBase,'SELECT COUNT(*) as total FROM Pornusy');
		  $row = mysqli_fetch_assoc($result);
		  $this->CalculatePageControls($row['total'],$PageNumber);
		  mysqli_query($dataBase,"SET CHARSET utf8");
		  $result = mysqli_query($dataBase, $query);
		  
		  while($row = mysqli_fetch_assoc($result))
		  {
			array_push($this->moviesDataArray, new Movie($row['opis'], $row['gwiazdy'],$row['wyswietlenia'], $row['sekundy'],$row['minuty'],$row['godziny'], $row['lektorpl']));
		  }
		  
		  mysqli_close($dataBase);
		  $this->GetRandomImages();
		  
		}
		
		
	}	
 }

?>

Plik widoku MainPageBuilder.php

<?php
 class MainPageBuilder
 {
	 public $Data;
	 
	function __construct(&$MovieData)
	{
		$this->Data = $MovieData;
	}
	
	function CreateBackForwardControls()              //wyświetlanie kontrolek sterujących podstronami
	{
	  $LeftControlNumber = $this->Data->PageControlIndex1;
	  $MaxPageIndex = $this->Data->MaxPageIndex;
	  $ActivePagePosition = $this->Data->CurrentPage;
	  
	     if($LeftControlNumber > 1)
        {
		  $PreviousPageNumber = $ActivePagePosition - 1;
          $LeftAnchor = 'href="/strona/'.$PreviousPageNumber.'/"';
	    }
        else
        {
          $LeftAnchor = "";
	    }

        if($ActivePagePosition >= $MaxPageIndex)
        {
          $RightAnchor = "";
		}
        else
		{
          $NextPageNumber = $ActivePagePosition + 1;
		  $RightAnchor = 'href="/strona/'.$NextPageNumber.'/"';
		}
    
	 echo '<li class="controls-element controls-element-bottom">
     <a '.$LeftAnchor.' class="page-selection page-selection-second-layer">wstecz</a>
   </li>';
   
   echo '<li class="controls-element controls-element-bottom">
     <a '.$RightAnchor.' class="page-selection page-selection-second-layer">dalej</a>
   </li>';
		
	}
	
	function CreatePageNumbers()  //wyświetlanie kontrolek sterujących podstronami
	{
	 $LeftNumber = $this->Data->PageControlIndex1;
     $ActiveControl = $this->Data->ActivePagePosition;
	 
		for($I = 0; $I < 5; ++$I)
		{
			$Class = ($I + 1 == $ActiveControl) ? "active" : "";
			$PageNumber = $I + $LeftNumber;
			
			echo '<li class="controls-element">
                   <a href="/strona/'.$PageNumber.'/" id="PageControl-'.$I.'" class="page-selection page-selection-first-layer '.$Class.'">'.$PageNumber.'</a>
                 </li>';
		}
	}
	
	private function CreateTimeLabel($movie)   //tworzenie etykiety z czasem trwania filmu np. 00:34
	{
	  
	  $seconds = $movie->seconds;
	  $hours = $movie->hours;
      $minutes = $movie->minutes;
	  
	  $seconds = $seconds < 10 ? "0$seconds" : $seconds;
	  $hours = $hours != null ? "0$hours:" : "";
	  
      if($minutes == null)
	  {
         $minutes = "00:";	
	  }
      else
      {
        $minutes = ($minutes < 10) ? "0$minutes:" : "$minutes:";
	  }  
	  
	  return $hours.$minutes.$seconds;
	}
	
	function ShowMovies()  //wyświetlanie filmów
	{
		$CurrentID = $this->Data->TopIndex;
		
		
		foreach($this->Data->moviesDataArray as $movie)
		{
			$Time = $this->CreateTimeLabel($movie);
			$Description = $movie->tittle;
			$Views = $movie->views;
			$stars = $movie->stars;
			
			if($stars != null)
			{
			  $stars = 'data-stars="'.$stars.'"';	
			}
			else
			{
			  $stars = "";	
			}
			
		   echo '<div class="movie-complete">
		       <div class="image-and-duration"><img class="movie-small-image" src="/images/movie/main/'.$CurrentID.'.jpg" /><time class="duration">'.$Time.'</time></div>
			   <div class="movie-description">'.$Description.'</div>
			      <div class="additional-options">
					 <span class="views">'.$Views.' odsłon</span>
					 <img alt="podgląd filmu" title="kiliknij aby podejrzeć film" class="magnifier-icon" '.$stars.' data-id="'.$CurrentID.'" src="/images/controls/magnifier.png"/>
			      </div>
	      </div>';	
		  
		  --$CurrentID;
		}
	}
 }

?>

Pobieranie filmów wedle kategorii w modelu

https://paste.ofcode.org/aBnR5uxTzMtTXfhB8N3ash

Wyświetlanie filmów wedle kategorii w widoku

https://pastecode.xyz/view/231cfd46

 

1 odpowiedź

0 głosów
odpowiedź 20 marca 2018 przez Artek Stary wyjadacz (11,800 p.)

Po przeanalizowaniu tematu doszedłem do wniosku iż to co napisałem nie jest implementacją wzorca MVC i trzeba sporo poprawić. Myślę, że teraz wiem na czym to polega i dla zobrazowania napisałem przykładowy kod, który(według mnie) jest implementacją MVC. Proszę o wskazanie ewentualnych błędów i potwierdzenie lub zaprzeczenie czy dobrze napisałem.

 

Założyłem, że piszemy kod dla sklepu i jako jedną z możliwości napisałem wyszukiwanie według rodzaju produktu. Tak to wygląda

spl_autoload_register('autoloadClass');

 class Router
 {
	 public $ModelName;
	 public $ViewName;
	 public $ControlerName;
	 public $Parameter;
	 
	function __construct()  //tutaj parsujemy adres url i wyodrębniamy akcję
    {
      //jakieś działania na ciągach znaków
	  $this->ModelName = $JakasZmiennaPrzechowujacaNazwe;
	  $this->ViewName = $JakasZmiennaPrzechowujacaNazwe;
	  $this->ControlerName = $JakasZmiennaPrzechowujacaNazwe;
	}	
 }
 
 class SearchByItemModel //klasa modelu
 {
	private $Item;
    
	public function SetItem($Item)
	{
	  $this->Item = $Item;
	}
	
	public function FindItemInDataBase()
	{
	  //łączenie z bazą danych, pobieranie danych itp cała logika tu pracuje
	  return $JakasZmiennaZapewneTablica;
	}
    	
 }
 
 class SearchByItemView
 {
   private $ItemFinder;
	 
   function __construct($ItemFinder)
   {
     $this->ItemFinder = $ItemFinder;
   }

   function Render()
   {
     //tutaj wyświetlane jest wszystko co potrzebne, tutaj jest bezpośredni dostęp do modelu
   }   
 }
 
 class SearchByItemControler
 {
	private $Model;

    function __construct($Model)
    {
      $this->Model = $Model;
	}

    function Search($Item)
	{
     $this->Model->SetItem($Item);
	}	
 }
 
 //tworzymy instancje naszych obiektów;
 
 $router = new Router();
 $model = new $router->ModelName();
 $controler = new $router->ControlerName($model);
 $parameter = $router->Parameter;
 
 $controler->Search($Parameter);
 $view = new SearchByItemView($model);
 $view->render();

 

Podobne pytania

+5 głosów
3 odpowiedzi 1,252 wizyt
pytanie zadane 1 lipca 2015 w PHP przez Hatter Gaduła (3,180 p.)
0 głosów
2 odpowiedzi 304 wizyt
pytanie zadane 7 lutego 2019 w C# przez Antero00 Gaduła (3,670 p.)
0 głosów
1 odpowiedź 592 wizyt
pytanie zadane 4 maja 2015 w PHP przez komputerhk Początkujący (250 p.)

92,567 zapytań

141,420 odpowiedzi

319,617 komentarzy

61,953 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...