Dynamischer Content mit "frühem Include" auf der Seite

Meine Umsetzung sieht wie folgt aus:

PHP:
class SearchResult {

	private $linkname;
	private $link;
	
	public function SearchResult($linkname, $link) {
		$this->linkname = $linkname;
		$this->link = $link;
	}
	
	public function getName() {
		return $this->linkname;
	}
	
	public function getLink() {
		return $this->link;
	}
	
}

Meine search.php
PHP:
class inc_search extends IncludeModel {
	
	public function show_content_of_file() {
		
		draw_header('Suche');
		$this->show_search_formular();
		draw_bottom();
		
		$anyresult = false;
		
		draw_header('Suchergebnisse');
		
		if (isset($_POST['searchit'])) {
			// Suche starten
			$search = $_POST['search'];
			
			$pfad="./links/";
			$verz=opendir($pfad);
			
			while ($file = readdir($verz)) {
				
				if (filetype($pfad.$file) != "dir" && substr($pfad.$file, strlen($pfad.$file)-3, 3) == 'php') {
					
					$filename = substr($file, 0, strlen($file)-4);
					
					try {
						$class = IncludeModel::factory($filename);
						$obj = new $class($filename, $this->parameters, $this->sqlconn, $this->user, $this->bbcode);
						
						$results = $obj->search_string($search);
						
						if ($results != null) {
							$anyresult = true;
							
							$this->show_single_line('Ergebnisse im Bereich '.ucfirst($filename));
							draw_devider();
							
							foreach($results as $result) {
								if ($result instanceof SearchResult) {
									$this->show_single_line('<a href="'.$result->getLink().'">'.$result->getName().'</a>');
								}
							}
							
						}
						
					}
					catch (Exception $e) {
						$class = null;
					}
					
				}
				
			}
		}
		
		if (!$anyresult) {
			draw_status('Ihre Suche brachte keine Ergebnisse');
		}
		
		draw_bottom();
		
	}
	
	private function show_single_line($content) {
		echo '
		<tr>
			<td class="content_w">
				'.$content.'
			</td>
		</tr>
		';	
	}
	
	private function show_search_formular() {
		
		$search = $_POST['search'];
		
		echo '
		<tr>
			<td class="content_w">
				<form method="POST" action="./'.$this->filename.'.html">
				<table border="0" cellspacing="0" cellpadding="2" align="center" width="100%">
				<tr>
					<td width="50%">
						Suchbegriff:
					</td>
					<td width="50%"><input type="text" name="search" maxlength="100" value="'.$search.'"></td>
				</tr>
				<tr>
					<td align="center" colspan="2">
						<input type="submit" value="Begriff suchen" name="searchit">
					</td>
				</tr>
				</table>
				</form>
			</td>
		</tr>
		';	
	}
	
}

Funktioniert super ;)
Bei solchen Ergänzungen rentiert sich der etwas kompliziertere Aufbau des Systems ;) Hier noch ein Beispiel meiner videos.php in der ich nun die Suchfunktion überschreibe:
PHP:
	protected function search_string($value) {
		$results = array();
		
		$sql3 = $this->sqlconn->queryResult("SELECT id,title FROM page_video WHERE title LIKE '%$value%' ORDER BY id desc;");
		
		if ($sql3->getNumberOfResults() > 0) {
			while($row3 = $sql3->getObjOfArray()) {
				$obj = new SearchResult($row3->title, './'.$this->filename.'-'.$row3->id.'.html');
				array_push($results, $obj);
			}
		}
		else {
			$results = null;
		}
		
		return $results;
	}

Muss ich mal sehen wie glücklich ich damit bin ;) Mir fällt bestimmt noch was ein!
Aber bisher bin ich schon sehr happy über das Ergebnis!

lg
 
Hi, das sieht doch alles schonmal sehr gut aus so.

Nur der Konstruktor von Klassen heisst seit PHP5 immer(!) __construct()

Ich hätte da noch 2 kleine Anregungen:

1. Eine Factory-Methode dient normalerweise dazu, ein Objekt zu erzeugen, und es zurückzugeben, nicht nur den Klassennamen. Ich hätte da einen kleinen Vorschlag, der noch ein paar Vorteile hat:
PHP:
abstract class IncludeModel
{
...
  protected $params = array();
...
  protected function __construct() { }
...
  public static function factory($page, array $params = array())
  {
    // Code wie bisher, Klassenname steht in $class

    if(!isset($params['filename']))
    {
      $params['filename'] = str_replace('_', '/', $class);
    }

    if(!isset($params['sqlconn']))
    {
      $params['sqlconn'] = get_sql_conn(); // Eine Funktion, die dir dein DB-Objekt zurückgibt...
    }

    if(!isset($params['user']))
    {
      $params['user'] = get_user(); // Eine Funktion, die ein User-Objekt zurückgibt...
    }

    $reflection = new ReflectionClass($class);
    
    $constructor = $reflection->getConstructor();
    
    $constructorParams = array();

    foreach($constructor->getParameters() as $param)
    {
      $name = $param->getName();
      
      if(!isset($params[$name]))
      {
        if(!$param->isOptional())
        {
	      throw new Exception('Parameter ' . $name . ' ist notwendig, um ein Objekt der Klasse ' . $class . ' zu erzeugen');
        }
        
        $constructorParams[] = $param->getDefaultValue();
      }
      else
      {
        $constructorParams[] = $params[$name];

        unset($params[$name]);
      }
    }

    $object = $reflection->newInstanceArgs($constructorParams);
    
    $object->setFilename($params['filename']);
    $object->setSqlConn($params['sqlconn']);
    $object->setUser($params['user']);

    unset($params['filename'], $params['sqlconn'], $params['user']);

    foreach($params as $name => $value)
    {
      $object->setParam($name, $value);
    }

    return $object;
  }
...
  public function setFilename($name)
  {
    $this->filename = $name;
  }
...
  public function setSqlConn($conn)
  {
    $this->sqlconn = $conn;
  }
...
  public function setUser($user)
  {
    $this->user = $user;
  }
...
  public function setParam($name, $value)
  {
    $this->params[$name] = $value;
  }
...
  public function getParam($name, $default = null)
  {
    if(isset($this->params[$name]))
    {
      return $this->params[$name];
    }

    return $default;
  }
...
}
Diese Methode bietet dir die Möglichkeit, beliebige Parameter in den Konstruktoren anzugeben und ausserden ein paar Standardparameter zu setzen, hier: filename, sqlconn und user. Zusätzlich können noch weitere Parameter übergeben werden, die dann auch zur Verfügung stehen. Benutzung sieht z.B. so aus:
PHP:
class inc_comment extends IncludeModel
{
  protected $id;

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

$comments = IncludeModel::factory('comment', $_REQUEST);
Hier gilt folgendes: Der Parameter 'id' ist notwendig, und es lässt sich nur dann ein Objekt erzeugen, wenn er vorhanden ist, ansonsten gibts eine Exception. Alle weiteren Parameter werden im $params Array des Objekts gespeichert.

2. Du könntest auch die gesamte Seite (HTML) als Objekt auffassen, und eine Klasse erstellen, die dann Eigenschaften für den Titel und den Inhalt usw. enthält und bei Aufruf einer Methode das Dokument erzeugt, dann hast du auch alle Zeit der Welt, bevor du den Titel ausgeben musst.
PHP:
class Document
{
  protected $title = '';

  protected $content = '';

  public function __toString()
  {
    return '<html><head><title>' . $this->title . '</title></head><body>' . $this->content . '</body></html>';
  }
}
Die Verwendung könnte z.B. so aussehen (index.php)
PHP:
$doc = new Document();

ob_start();

// Ab hier gehts ganz normal weiter mit deiner index.php...
// Und am Ende steht dann folgendes:

$doc->content = ob_get_clean();

echo $doc;
Das hat den Vorteil, dass du alles im Document Objekt zwischenspeicherst, bevor es gesendet wird, desshalb kannst du auch noch am Ende des Scripts z.B. die header() Funktion benutzen. Weitere Eigenschaften des Document Objekts könnten z.B. sein: scripts (array), stylesheets (array), description (string), author (string), usw. Dann könntest du in der Factory Methode vom IncludeModel jedem neuen Objekt das Document Objekt mitgeben, und alle hätten Zugriff auf Elemente wie title usw., was "title extensions" sehr einfach macht.

So, ich hoffe das war nicht zu viel auf einmal, aber vielleicht gefällt dir ja die ein oder andere Idee. :)
 
Zuletzt bearbeitet:
Achwas ;)

Ich bin ja sehr aufnahmefähig ^^ (Auch wenn ich gerade 1 Stunde draußen stand und mein Abblendlicht gewechselt habe - grrr).

Es macht doch keinen Unterschied ob ich den Klassennamen zurückbekomme (Inclusive aller Fehler) oder ein Objekt (dann muss ich alle Parameter an die Factory übergeben). Also ich seh da nicht so den unterschied.

Allerdings kapiere ich diese Geschichten mitm Konstruktor nicht - das ist in PHP irgendwie sehr komisch! Ich dachte immer der Konstruktor muss genauso heißen wie die Klasse selbst - nun kommst du mir mit __construct. Ist das nicht nur der Aufruf von außen? Ich versteh es nicht...

Ich habe auch schon einen anderen Thread eröffnet indem ich gefragt habe ob Konstruktoren in PHP vererbt werden - was ja schon sehr komisch ist. Denn ich habe bei meiner Konstruktion einen Gedankenfehler gemacht und habe alle Parameterübergaben in den Konstruktor der Basisklasse geschrieben. Hat auch alles wunderbar funktioniert - ist mir erst viel später aufgefallen das es eigentlich komisch ist!

Vllt kannste da ja noch nen paar Takte zu sagen ;) Wär dir sehr dankbar...

Ich finde eh das PHP ne schlampige Programmiersprache ist - nirgends kann man richtige Rückgabeparameter definieren. Man kann also nicht sehr Typsicher Programmieren und muss deswegen dauernd fragen ob das auch wirklich ein Objekt davon ist. Nicht so schön... Ka ob das auch geht - auf jeden Fall geht es sehr gut ohne :D

lg
 
Hi, also PHP ist zwar nicht typsicher, aber es kommt mehr auf den Programmierstil an, ob es "schlampig" wird, oder nicht. ;) Gerade die Exceptions ermöglichen zumindest eine gute Fehlerbehandlung.

Zu der Konstruktorgeschichte: Ab PHP5 heisst der Konstruktor immer "__construct()", er wird also auch vererbt und kann in jeder abgeleiteten Klasse überschrieben werden (da heisst er natürlich ebenfalls "__construct()"). Man kann ihn zwar momentan auch so benennen, wie die Klasse, doch das wird vermutlich spätestens in PHP6 abgeschafft und man sollte sich da möglichst an die "neue" Regel halten. Du kannst das nochmal hier nachlesen, da ist auch dein Vererbungsproblem direkt oben auf der Seite erklärt.

Hier mal eine Erklärung zur Factory-Methode im allgemeinen.

Die Vorteile meiner Factory-Methode sind eigentlich ganz einfach:

- Die Konstruktorparameter werden automatisch geprüft.
- Objekte wie die Datenbankklasse müssen nicht als Parameter übergeben werden, sondern werden automatisch erzeugt / berechnet und an das Objekt zugewiesen. Du sparst also alle Parameter ein, die für alle inc_* Klasse gelten ein.
- Alle weiteren Parameter werden automatisch übernommen und sind per getParam(name, default) verfügbar
- Die Factory gibt garantiert ein Objekt zurück, das sich von IncludeModel ableitet.

Das mag nicht alles auf den ersten Blick ersichtlich sein, hat aber Vorteile, da man z.B. die Datenbankklasse nicht immer selbst übergeben muss.

Für manche Klassen (z.B. Datenbank) eignet sich auch hervorragend das Singleton-Pattern, dass auch sehr schön in der Factory-Methode benutzt werden kann, um das Datenbankobjekt zu erstellen.
PHP:
if(!isset($params['sqlconn']))
{
  $params['sqlconn'] = SqlConn::getInstance(); // Oder wie man seine Klasse halt nennt :)
}
 
Zuletzt bearbeitet:
Zurück