Zum Inhalt springen

Ext mit eigenen Klassen erweitern

Erstellt am 15. Juli 2007 · 21 Antworten · letzte Antwort am 20. Juli 2007 · Seite 1 von 2

Tags: Frage

mischa ·

Hallo zusammen,

mit Sicherheit wurde das Thema schon tausendmal durchgekaut und ich versinke vor Scham im Boden, dass ich selber danach fragen muss, aber ich habe einfach ein Problem mit dem Auslagern von Funktionen in externe Klassen meiner Extension.
:o

Was will ich machen? Ich will grundsätzlich die class.tx_meine_ext_pi1.php schlank halten und alle Funktionen, die ich brauche, in externe Klassen aufteilen. Das klappt ja auch wunderbar wunderschön, aber ein kleines Gallisches Dorf will mich unbedingt fertig machen und das ist die pibase.

Meine "Hauptklasse"

class tx_mhdialekte_pi1 extends tslib_pibase {
	var $prefixId      = 'tx_mhdialekte_pi1';
	var $scriptRelPath = 'pi1/class.tx_mhdialekte_pi1.php';
	var $extKey        = 'mh_dialekte';	
	var $pi_checkCHash = true;
...
	function showList($content,$conf){
	    $this->cObj->conf = $this->conf;
	    $ListView = t3lib_div::makeInstanceClassName("tx_mhdialekte_list");
		$list = new tx_mhdialekte_list($this->cObj);

		return $list->showList($cObj);
}

...

	include_once($ext_path.'pi1/class.tx_mhdialekte_list.php');

in class.tx_mhdialekte_list.php steht dann

class tx_mhdialekte_list extends tx_mhdialekte_pi1 {

		var $cObj;

	function showList($cObj){
    	$this->cObj = $cObj; 
		$this->conf = $this->cObj->conf;

		$select_fields = '*';
		$from_table = 'tx_mhdialekte_dict';
		$where_clause = 'word LIKE "%'.$this->piVars['suche'].'%"';


		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select_fields,$from_table,$where_clause,$groupBy='',$orderBy='word',$limit='0,10');

		while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
			$return .= $this->pi_linkToPage($row['word'],8,$target='',$urlParameters=array('tx_mhdialekte_pi1[word]'=>$row['uid']));
		}
		return $return;
	}
}

Probleme macht mir hierbei die Zeile

$return .= $this->pi_linkToPage($row['word'],8,$target='',$urlParameters=array('tx_mhdialekte_pi1[word]'=>$row['uid']));

denn hier meckert php ständig

Fatal error: Call to a member function on a non-object in /srv/www/vhosts/dialekte.org/httpdocs/typo3/sysext/cms/tslib/class.tslib_pibase.php on line 283

Ich habe auch schon versucht, die

require_once(PATH_tslib.'class.tslib_pibase.php');

in die Nebenklasse einzubinden - auch mit direktem Pfad zur Datei - keine Chance.

Weiß jemand, wie ich die pi_base in der Nebenklasse zum laufen kriege?

Harakiri ·

Wo wird denn eigentlich in "class tslib_pibase" die "var $cObj" instanziert?
Finde das nirgendwo in der Klasse.

Harakiri ·

Auszüge aus der PHP-Doku:

Manchmal ist es hilfreich, auf Funktionen in Basisklassen bzw. auf Funktionen in Klassen zuzugreifen, die noch keine Instanzen haben. Dafür wird der :: Operator verwendet.

class A
{
    function example()
    {
        echo "I am the original function A::example().<br>\n";
    }
}

class B extends A
{
    function example()
    {
        echo "I am the redefined function B::example().<br>\n";
        A::example();
    }
}

// Es gibt kein Objekt der Klasse A.
// Dies wird folgendes ausgeben
//   I am the original function A::example().<br>
A::example();

// Erstellt ein Objekt der Klasse B.
$b = new B;

// Dies wird folgendes ausgeben
//   I am the redefined function B::example().<br>
//   I am the original function A::example().<br>
$b->example();

Das obige Beispiel ruft die Funktion example() der Klasse A auf. Nachdem noch kein Objekt der Klasse A existiert, können wir nicht $a->example() oder ähnliches schreiben. Stattdessen rufen wir example() als 'Klassenfunktion' auf, d.h. als Funktion der Klasse selbst, und nicht irgendein Objekt dieser Klasse.

Es gibt Klassenfunktionen, aber keine Klassenvariablen. Tatsächlich gibt es zur Zeit des Aufrufs kein Objekt. Deshalb darf eine Klassenfunktion keine Objektvariablen benutzen (aber sie kann lokale und globale Variablen verwenden), und sie darf $this ebenfalls nicht benutzen.

In dem obigen Beispiel definiert Klasse B die Funktion example() neu. Die ursprüngliche Definition in Klasse A ist überschattet und nicht länger verfügbar, außer Sie verweisen mittels des ::-Operators speziell auf example() in Klasse A. Schreiben Sie A::example(), um dies zu tun (Tatsächlich sollten Sie parent::example() schreiben, wie im nächsten Abschnitt beschrieben).

In diesem Kontext besteht ein Objekt, das Objektvariablen haben kann. Deshalb können Sie auch $this und Objektvariablen verwenden, wenn sie von innerhalb einer Objektfunktion verwendet werden.

mischa ·

Danke für die Antworten.

Problem ist wohl, dass in der Subklasse, die ich selber erzeuge, die Variable cObj nicht vorhanden ist. Die muss - leider - über den Funktionsaufruf übergeben werden. Dann kann in der Subklasse die pi_base auch wieder instantiiert werden. (oder so). Ist zwar nicht gerade komfortabel, aber wenn man es weiß!!

also müsste der passende Teil meines Codes lauten:

return $list->showList($this->cObj);

(habe nur das $this-> vergessen. Dann hats geklappt.

steffenk ·

oder man macht in der Hauptklasse eine Funktion, die die entsprechenden Objekte liefert

function getCobj() { return $this->cObj; }
function getPibase() { return $this; }
Knalltuete ·

Ich versuche momentan auch eine klasse a mit der klasse b zu erweitern.. irgendwie bekomme ich es aber auch nicht hin.

function getCobj() { return $this->cObj; }
function getPibase() { return $this; }

Wie muss ich das einbinden?

Muss ich für die Klasse b extends benutzen?
Wie macht man das denn sauber.. ich hab gestern den ganzen abend gelesen, jedoch keine lösung gefunden.

vielleicht kann einer von euch mir helfen!
momentan sieht mein code ungefaehr genauso aus wie der vom mischa..

mfg tueti

steffenk ·

es gibt immer mehrere Möglichkeiten, hier z.b. eine:

require_once(t3lib_extMgm::extPath('my_ext').'lib/class.tx_myext_views.php');   

class tx_myext_pi1 extends tslib_pibase {
  ...
  $b = t3lib_div::makeInstance('tx_myext_views');
  $b->init($this,$this->conf);
   ...

  function doIt() {

  }
}

class tx_myext_views {
  
  function init(&$conf,&$pibase) {
     $this->conf = $conf;
     $this->pibase = $pibase;
  }
  ...
}

Das ist eine einfache Methode eine weitere Klasse einzubinden und ihr das Hauptobjekt pibase mitzugeben.

Die Funktionen der Hauptklasse erreicht man dann so:

$a = $this->pibase-doIt();

Die pi1-Klasse zu erweitern macht keinen Sinn, diese ist eine Erweiterung der tslib_pibase. Dies aus dem Grund, damit man die Objekte der tslib_pibase zur Verfügung hat. Es ist also viel leichter, diese Objekte durchzureichen.

Knalltuete ·

okaii.. irgendwie steh ich auf schlauch!

was macht diese funktion:

function init(&$conf,&$pibase) {
   $this->conf = $conf;
   $this->pibase = $pibase;
}

und wie kann ich dann aus der hauptklasse a eine funktion aus der unterklasse b ansprechen? zb.

function getFile($file,$errormsg) {
   if (!$this->cObj->fileResource($file)) ;//echo $this->errorwrap($errormsg);
   else return $this->cObj->fileResource($file);
}
steffenk ·

die init dient der Weitergabe der Objekte, die Hauptklasse macht folgendes:

1. einbinden (require_once)
2. instanzieren ($b = t3lib_div::makeInstance('tx_myext_views')😉
3. conf und pibase übergeben ($b->init($this->conf,$this)😉

Und im 3. Schritt siehst Du auch, wie man aus der Hauptklasse auf die eingebundene zugreift. Ist dort also Deine Funktion getFile, so rufst Du sie so auf:

$b->getFile(...);

PS ich hatte die Reihenfolge der Parameter oben verdreht, aber sollte offensichtlich sein.

steffenk ·

warum habe ich die Objekte übergeben ?

conf: ich kann aus der eingebundenen Klasse auf die conf der Hauptklasse zugreifen (z.B. $this->conf['template'])

pibase: ich kann in der eingebundenen Klasse auf pibase zugreifen.
Beispiel Sprache

Hauptklasse: echo $this->pi_getLL('Sprachlabel');
Nebenklasse: echo $this->pibase->pi_getLL('Sprachlabel');

Knalltuete ·

ok, gesagt getan!
Trotzdem habe ich jetzt immernoch den folgenden fehler:

Fatal error: Call to a member function getFile() on a non-object

Muss ich mit der funktion init() noch irgendwas machen?

steffenk ·

hast Du auch instanziert? Hast Du auch die init aus der Hauptklasse aufgerufen ? Hast Du auch die Reihenfolge gleich ?

$b->init($this->conf,$this)
...
function init(&$conf,&$pibase) {
...

Knalltuete ·
$b->init($this->conf,$this)
...
function init(&$conf,&$pibase) {
...

so hab ich es gemacht.

Irgendwie bin ich doof.. aber ich moecht es endlich verstehen 🙁

steffenk ·

ok, hier das komplette Beispiel:

<?php
/***************************************************************
*  Copyright notice
*
*  (c) 2007  <>
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/

require_once(PATH_tslib.'class.tslib_pibase.php');
require_once(t3lib_extMgm::extPath('dummy').'pi1/class.tx_dummy_ext.php');   



/**
 * Plugin 'Dummy FE' for the 'dummy' extension.
 *
 * @author	 <>
 * @package	TYPO3
 * @subpackage	tx_dummy
 */
class tx_dummy_pi1 extends tslib_pibase {
	var $prefixId      = 'tx_dummy_pi1';		// Same as class name
	var $scriptRelPath = 'pi1/class.tx_dummy_pi1.php';	// Path to this script relative to the extension dir.
	var $extKey        = 'dummy';	// The extension key.
	var $pi_checkCHash = true;
	
	/**
	 * The main method of the PlugIn
	 *
	 * @param	string		$content: The PlugIn content
	 * @param	array		$conf: The PlugIn configuration
	 * @return	The content that is displayed on the website
	 */
	function main($content,$conf)	{
		$this->conf=$conf;
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();
		
	    $b = t3lib_div::makeInstance('tx_dummy_ext');
        $b->init($this->conf,$this);
		$content=$b->sayHello();
	
	
		return $this->pi_wrapInBaseClass($content);
	}
}



if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dummy/pi1/class.tx_dummy_pi1.php'])	{
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dummy/pi1/class.tx_dummy_pi1.php']);
}

?>

und die eingebundene:

<?php

class tx_dummy_ext  {

    function init(&$conf,&$pibase) {
        $this->conf = $conf;
        $this->pibase = $pibase;
    }
  
    function sayHello() {
        return 'Hello';
    }
}       
?>
Knalltuete ·

ok kapiert! funzt soweit auch, jedoch bleibt er jetzt bei der funktion

$this->cObj->fileResource($file)

in der klasse b haengen. Liegt das an dem cObj?

steffenk ·

in der Nebenklasse:

function sayHello() {
  return $this->pibase->cObj->calc('3+4');
}

Ich glaube hier hängts:

Hauptklasse erweitert pibase, also ist $this auch pibase.
cObj ist ein Objekt der pibase, also erreichbar über $this->cObj

in der Nebenklasse über die Hauptklasse:
$this->pibase->cObj

Knalltuete ·

VERDAMMT ES GEHT! :o
YEEEEHAAA 😃

woa ich danke dir von herzen 🙂
endlich kann ich loslegen zu programmieren!

aber komisch.. das hatte ich glaube schon probiert aber es lief net.. naja hauptsache es geht jetzt!

Nochmals vielen vielen herzlichen danke!
ich glaub ich checks jetzt auch 🙂

danke fuer die unglaubliche geduld!

mfg stefan 😃

Harakiri ·

Aber es ist doch Käse dass ich die Variablen übergeben muss! Warum kann ich nicht einfach die "Membervariablen" der Oberklasse aufgreifen? Normalerweise kenn ich das von OOP so.
Scheint aber in php4 nicht zu gehen oder?

steffenk ·

wenn das Käse für Dich ist, dann zeig uns doch einen Weg ohne - Du kennst ja OOP, also kein Problem 😉