Gå til innhold

Oppsett av OOP side med inkludering


Anbefalte innlegg

Hei,

 

Jeg har kodet PHP i en god stund nå, og har hittil kun brukt oppsett av nettsidene jeg har skrevet utifra hva jeg selv føler har vært mest naturlig og praktisk, men føler meg usikker i min sak om dette er best practice. Jeg skriver mer eller mindre all min kode som OOP, utenom noen få sider som tar i bruk objektene. Nylig lurt litt på å kanskje også gjøre om selve index-siden til oop også, men er litt usikker.

 

Per dags dato så består altså systemet mitt av noe slik:

 

Indexfil

All sidevisning går igjennom en index.php-fil. Denne filen setter opp instillinger som error_reporting, starter session, henter get-variablene tilsvarende 'f' for folder og 'p' for page. Deretter sjekker den om de ikke er tommme, om det finnes en fil tilsvarende $p i mappe $f, hvis ikke 404, evt. ikke satt så require("home.php") som er standardtekst (forside). Med andre ord er www.example.com?f=foo&p=bar require av /foo/bar.php.

 

Head

Inkluderes ovenfor biten i index som sjekker get-variablene, og inneholder alt som måtte finne seg av html-kode som er ovenfor hva en side inneholder. Ender med en div som starter som heter content.

 

Footer

Etter inkluderingen av eventuell fil via get. Ender content-div, printer ut eventuell footer og slutter body og html.

 

Klasser

Prøver å skrive de så generelle som mulige, og ikke å skrive ut noen særlig med output. F. eks om det skal skrives ut en tabell, så returnerer jeg heller en array, og lager tabellen i siden som tar i bruk funksjonen i den aktuelle klassen.

 

I hver klasse så har jeg på de siste sidene jeg har laget brukt en $this->errorMsg, som blir satt utifra en eventuell feilmelding som måtte oppstå underveis i utførelsen av en funksjon. $this->errorMsg blir satt til 0 om ok. hvis noe noe feiler, så returnerer klassen false i tillegg. Dermed kan jeg gjøre slik: (utsnitt av en kode som printer ut gallerier)

 

if(false !== $arr = $media->getGalleries()) // getGalleries() ga ikke false, altså den returnerte en array
{
   echo '<table>';

   foreach($arr as $row)
   {
       ?>

       <tr>
           <th>Tittel</th><td><?=$row['tittel'];?></td>
           <!-- osv -->
       </tr>

       <?php
   }

   echo '</table>';
}
else // getGalleries() ga false, mao. $media->errorMsg er satt
{
   switch($media->errorMsg)
   {
       case 1:
           echo "An error occured with [...];
           break;
       case 2:
           echo "Another error occured with [...];
           break;
   }
}

 

Do

Om det er snakk om noe som krever post, som f. eks at jeg har addet et galleri med et bilde, så kjøres det igjennom en mappe kalt "do", hvor det er pure PHP-kode (oop). Dermed kan et form være action="do/add_picture.php" f.eks. Her hentes post, og sendes til en funksjon i aktuell klasse. Deretter blir man redirected til der man kom fra (HTTP_REFERER) med aktuell kode (errorMsg heter den). Her et eksempel hvor man skal endre tittel på et bilde.

 


require("../classes/db_connect.php");
require("../classes/media.php");

$media = new Media();
$id = $_GET['id'];
$title = $_POST['title'];

$media->editTitle($id);

header("Location: ".$_SERVER['HTTP_REFERER']."&errormsg=".$media->errorMsg); // errormsg blir senere for aktuell tilbakemelding

 

Deretter blir det en bit på siden hvor formen er som sjekker om $_GET['errorMsg'] er satt. Hvis den er 0, gir melding om ok, hvis ikke aktuell feilmelding. Grunnen til at det er gjort slik er pga. da blir det enklere å endre feilmeldinger uten å være avhengig av hvordan klassen fungerer, prøvd å skikke de forskjellige delene.

 

Konklusjon

Alt i alt er systemet med andre ord ganske dypt, og jeg kan se for meg at en utenforstående skal slite litt med å sette seg inn i systemet. Dessuten vet jeg ikke om dette er fremgangsmetoden når man helst skal skille business logic osv. eller hva uttryket går ut på. Er jo ikke akkurat plain HTML-sider. Er jo egentlig blandet.

 

Rekkefølgen blir altså slik:

  1. Index
  2. require head.php
  3. $_GET['f'] og ['p']
  4. Henter side utifra $f og $p
  5. Side utfører funksjon i klasse, hvis false, gir ut $class->errorMsg
  6. Hvis ok, printer ut f. eks tabell utifra array som funksjon ga
  7. Eventuell mer html-kode som måtte være igjen
  8. Footer

Systemet fungerer greit nok, også på mellomstore sider, men jeg føler det er allikevel er litt rotete. Har ikke fulgt noen guider av noe slag, men koden min i seg selv er ikke feil eller noe, men som sagt, strukturen føler jeg meg usikker på.

 

Kan selvsagt lære meg et rammeverk, men er interessert i å kunne dette her fra bunn av så bra som mulig også.

 

Saklige svar og tips tas imot med glede! Hadde vært interessant å se andres systemer (forhåpentligvis bedre hvis mulig :))

Om dette er en vanlig (og grei) måte å gjøre det på så vil jeg veldig gjerne høre det også.

Endret av Occi
  • Liker 2
Lenke til kommentar
  • 4 uker senere...
Videoannonse
Annonse

Hadde vært interessant om noen hoppet på emnet og beskrev hvordan de satt opp sider med inkludering! :) Som nevnt i forrige innlegget så går det ut på å ha noe á www.example.com?page=foo osv.

 

Har også en oppdatering; har laget en side (elks.no) hvor jeg har skrevet også hva som skjer i index-fila til en egen klasse. Kan godt se for meg at det kan være treigere enn å ha alt i en smørje index.php-fil, men poenget er at da kan jeg bruke samme kode igjen på nye sider uten å endre noe særlig, jeg får bedre struktur og lærer mer PHP! :)

 

Er interessert i å høre hvor god idé dette egentlig er. Siden er veldig liten, og serveren er ikke treig, så performanceloss har jeg ikke merket noenting til, men selvsagt vil et par forearch-løkker gjøre ting treigere osv.

 

Her er en skissering av hvordan det fungerer, har lagt til masse fine kommentarer som forklarer alt steg for steg og hvorfor ditt og datt. Merk at dette ikke er et fungerende eksempel, men en skissering.

 

Bare å spørre om det er noe du lurer på!

 

index.php

<?php
   require("classes/index.php");

   $index = new Index();

   // inkluderer klasser, case sensitive
   $classes = array('DB_Connect', 'IPLog', 'Cart', 'Project'); 

   // skriver inn hvilke ?f= som er godtatt (dvs. som ikke gir 404)
   $fAllow = array();

   // skriver inn hvilke ?p= som er godtatt
   $pAllow = array('foo', 'bar'); 

   $session = false; // lagt opp til bruk av sessions for seinere bruk, se klasse

   // ender til slutt opp i <title><?= $this->title; ?></title>
   $title = "A cat is fine too"; 
   $titleArray = array('foo' => "Foo the foo",
                       'bar' => "Bar the bar"); // brukes for å endre tittel

   // sender med all nødvendig info til klassen index, etter det her er siden ferdig    
   $index->init($classes, $fAllow, $pAllow, $session, $title, $titleArray);
?>

 

classes/index.php

<?php 
   class Index
   {
       // lister opp interne variabler, brukes på tvers av funksjoner,
       // og må derfor bruke $this->foo
       public $title;
       private $titleArray;
       private $db_connect, $iplog;

       public function init($classes, $fAllow, $pAllow, $session, 
                                         $title, $titleArray)
       {
           error_reporting(E_ALL ^ E_NOTICE); // error-konfigurering
           header("Content-Type: text/html; charset=UTF-8"); // force UTF8 

           $this->classes($classes); // inkluderer og oppretter klassene

           // legger tittel og titleArray i $this-> pga. brukes i flere funksjoner
           $this->title = $title;
           $this->titleArray = $titleArray;

           $pAllow[] = '404'; // legger til 404 som standard

           if($session) // hvis man vil bruke sessions
           {
               session_start();
           }

           // eksempel på hvor man kan plassere ip-logging
           $this->iplog->logIP();

           $this->page($fAllow, $pAllow); // går videre til å faktisk opprette siden
       }

       private function classes($classes)
       {
           foreach($classes as $class)
           {
               // merk strtolower pga. den er sendt inn med casesensitive
               // !!! mangler en sjekk på om fil eksisterer, har ikke laget enda !!!
               require("classes/" . strtolower($class) . ".php");
           }

           foreach($classes as $class)
           {
               // ikke optimal løsning enda, krever manuell innskriving 
               // av klasser i toppen av filen, tanken er at det skal være 
               // mer eller mindre kun avhengig av parameter (fremtidsrettet!)
               $tempClass = strtolower($class);

               // $this->$tempClass vil gi f. eks $this->iplog
               $this->$tempClass = new $class();
           }
       }

       private function page($fAllow, $pAllow)
       {
           // henter ?f= og ?p=
           $f = $_GET['f'];
           $p = $_GET['p'];

           // home.php er forsideteksten, 
           // kan derfor like godt redirectes til DocumentRoot
           if($p == 'home')
           {
               header("Location: /");
           }
           else if(!empty($f)) // test for fil i mappe
           {
               if(in_array($f, $fAllow)) // mappe godtatt? hvis ikke 404
               {
                   if(!empty($p))
                   {
                       if(in_array($p, $pAllow)) // side er godtatt, hvis ikke 404
                       {
                           if(file_exists($f."/".$p.".php")) // finnes filen?
                           {
                               // manipulerer tittel etter hva som er hentet
                               $this->title($p, $f);

                               // henter fil $p i mappe $f
                               $require = $f."/".$p;
                           }
                           else
                           {
                               $require = '404';
                           }
                       }
                       else
                       {
                           $require = '404';
                       }
                   }
                   else
                   {
                       $require = "home";
                   }
               }
               else
               {
                   $require = '404';
               }
           }
           else if(!empty($p)) // test for kun fil
           {
               if(in_array($p, $pAllow))
               {
                   if(file_exists($p . ".php"))
                   {
                       $this->title($p);
                       $require = $p;
                   }
               }
               else
               {
                   $require = '404';
               }
           }
           else // ingenting satt, skriver forside
           {
               $require = "home";
           }

           // <html>, <head>, start på <body>, nav/header
           require("includes/head.php"); 

           // sidecontent
           require($require . ".php"); 

           // footer, slutt på <body> og <html>
           require("includes/footer.php"); 
       }

       private function title($page)
       {
           // isset() er faktisk raskere enn array_key_exists()
           // gir FALSE hvis array['foo'] == NULL
           // ikke et problem for oss, da vi selv har laget arrayen
           if(isset($this->titleArray[$page]))
           {
               $this->appendTitle($this->titleArray[$page]);
           }
       }

       private function appendTitle($prestring)
       {
           if(!empty($prestring))
           {
               // legger til noe á 'Foo the foo' foran hovedtittel
               $this->title = $prestring . " - " . $this->title;
           }
       }
   }
?>

Endret av Occi
  • Liker 1
Lenke til kommentar

Du kunne jo laget et MVC-basert når du først er i gang :D

Veldig enkelt og videreutvikle systemet da, legge til nye sider med få tastetrykk.

 

Kan poste litt utdrag fra systemet mitt:

 

Index:

<?php
header('Content-type: text/html; charset=ISO-8859-15');

/**
* Definerer nødvendig info
*/
require('www/system/config/config.define.php');


/**
* Inkluderer og konfigurer nettsiden slik at den fungerer
* som den skal
*/
require('www/system/includes/systemStart.php');

/**
* Lager en ny instance av hoved-controlleren 
*/
$index = SystemKontroll::gtInstance();


/**
* Setter aktuell controller og action
*/
$index->route();


/**
* Printer ut HTML
*/
echo $index->gtBody();

 

Del av systemstart.php

if(!in_array(__GET_SL, Includesystem::$gyldige))
$fil = __PT_SYSTEM . '/modules/system/error404/controller/error404Controller.php';
else
$fil = __PT_SYSTEM . '/modules/' . $cnf_atl_vars[0] . '/' . $cnf_atl_vars[2] . '' . ucfirst(__GET_SL) . '/controller/' . __GET_SL . 'Controller.php';

 

 

<?php

class Includesystem {

private $sti;

public static $gyldige = array( 'index');

public static $gyldige_index = array('index', 'registrer', 'glemtpassord');

public function __construct($var, $var3) {
	$this->sti = trim($var);
	$this->sti = str_replace('\\', '/', $this->sti);
	$this->gyldige = array_merge($this->gyldige, $var3);
	return $this;
}

public function filter() {
	if(!strpos($this->sti, '.') && !strpos($this->sti, '/')) {
		if(in_array($this->sti, $this->gyldige)) {
			return true;
		}
		else {
			return false;
		}
	}
	else {
		return false;
	}
}

public function incxFil() {
	if($this->filter()) {
		if(APP_DIR . APP_ROOT . 'controller/' . $this->sti) {
			if(!strpos($this->sti, '/') && !strpos($this->sti, '  ) && !strpos($this->sti, "'") && !strpos($this->sti, chr(0)) && !strpos($this->sti, '.')) {
				return true;
			}
			else {
				return false;
			}
		}
		else {
			return false;
		}
	}
	else {
		return false;
	}
}

}

 

Layout og settes utifra om brukeren er logget inn eller ei:

   /**
	* @__destruct: Setter layout som skal brukes
	* @return Systemkontroller -> settLayoutFil
	*/
public function __destruct() {
	if(!is_null($this->innhold)) {
		$this->view->innhold = $this->innhold;
		if(Bruker::isInnlogget()) {
			$res = $this->view->fetch(__PT_HOVED . '/html/layout/index.phtml');
		}
		else {
			switch(__GET_SL) {
				case 'registrer':	$res = $this->view->fetch(__PT_HOVED . '/html/layout/Registrer/index.phtml'); break;
				case 'glemtpassord': $res = $this->view->fetch(__PT_HOVED . '/html/layout/Registrer/index.phtml'); break;
				default:              $res = $this->view->fetch(__PT_HOVED . '/html/layout/LoggInn/index.phtml');
			}
		}
		$i = SystemKontroll::gtInstance();
		$i->settLayoutFil($res);
	}
}

 

F.eks en side ser slik ut:

<?php

class indexController extends FasKontroll implements iMa {

public function __construct() {
	parent::__construct();
}

public function index() {
	$tpl = new View;
	$tpl->setTemplateDir(__PT_SYSTEM . '/modules/root/RootIndex/views');
	$this->view->tittel = 'Logg Inn'; /** Setter tittel på siden **/
	$this->innhold = $tpl->fetch('index.phtml');
}

}

?>

 

Så inneholder da index.phtml php og htmlkode for denne siden ($_GET['sl'] == index (navnet på funksjonen)/default).

Endret av Thomas.
  • Liker 1
Lenke til kommentar

Nice, fint å se hvordan andre har løst det! Har leste bittelitt om hvordan et MVC er satt opp men har aldri brukt et selv eller prøvd å kode det. Vet ikke helt hva man kan kalle det jeg bruker nå jeg men, et rammeverk av en eller annen form kanskje. Skal prøve å se om jeg får noe ut av koden din til mitt system :)

 

Er litt ting som jeg føler meg litt usikker på når det gjelder f. eks hvordan man burde sette opp parametre ved bruk av et egenutviklet MVC som du har der. Det er vel kanskje ikke riktig å sende inn parametre i index.php da det blander controller(?) og view slik jeg har forstått det.

 

Uansett så er jeg ganske fornøyd med systemet mitt pdd, men kommer til å fortsette å utvikle det mot en MVC etterhvert merker jeg når jeg leser koden din. Allerede når kjenner jeg fordelene av et slikt system i den form av at det er bare å plotte inn i paramtrene så vips har du en helt ny side klart :)

 

Har også fikset mod_rewrite så ser jo nesten ut som om det er brukt et "ordentlig" rammeverk haha harhar.gif

Lenke til kommentar

Personlig så bruker jeg CodeIgniter. Bruker da å ha en hoved-template som har en $header, $footer, $meny som lastes inn via et eget lib jeg har skrevet.

 

Syns dette er greit pga. jeg liker CodeIgniter med MVC, og at ikke er for mye 'automagic behind the scenes'.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...