Zum Inhalt springen

Daten in Model erweitern

Erstellt am 26. Juli 2011 · 8 Antworten · letzte Antwort am 28. Juli 2011

Tags: Frage

Freshmeat ·

Ich befasse mich neu mit der Erstellung einer Extension auf Extbase/Fluid Basis. Jetzt haben sich einige Fragen aufgetan, die ich bis jetzt nicht lösen konnte. Hoffentlich kann mir jemand hier helfen.

Model um eigene Daten erweitern
Ich habe verschiedene Datensätze die einen generischen Link zu einem Portal beinhalten. Diesen Link würde ich gern im Model verfügbar haben, aber er muss nicht in der Datenbank gespeichert werden. Wie kann ich diesen bei der Instanzierung des Objekts im Model "abspeichern"?
Aktuell habe ich das in einem Viewhelper ausgelagert. Was für mich auch okey ist... nur habe ich eine ähnliche Situtation die sich nicht mit einem Viewhelper lösen lässt.

Etwa das gleiche Problem habe ich mit einem anderen "Feld". Ich habe verschiedene Datensätze die auf einer Google-Map dargestellt werden. Ich möchte nun die umliegenden Datensätze finden und deren individuelle Distanz zum aktuellen Karten-Mittelpunkt ausgeben. Die Berechnung der Distanz findet auf einem eigenen SQL-Statement statt. Von dort wird die berechnete Distanz aber nicht an das Model weitergegeben. Kann ich diese im Repository irgendwie ins Model speichern pro einzelner Datensatz?

PS: Ich weiss, dass ich die Distanz per Javascript errechnen könnte, nur muss ich sortieren können und wenn die Berechnung schon in der SQL stattfindet, bietet es sich an diese gleich zu verwenden.

Hört sich kompliziert an, falls jemand Code-Stücke benötigt, dann kann ich diese nachliefern, aber ich glaube es sind eher grundsätzliche Fragen die sich auch in anderen Fällen bieten.

Eydamos ·

Ich habe folgende Idee nicht getestet, sollte aber eigentlich funktionieren:

Erweiter dein Model einfach um die entsprechenden Eigenschaften wie z.B. distanz. Mach dazu deine setter und getter Methoden.
Trage die Eigenschaften die nicht in die Datenbank sollen auch NICHT ins TCA ein. Das sollte verhindern, dass TYPO3 versucht die Daten in die Datenbank zu schreiben bzw Sie auszulesen.
Im Controller kannst du dann die Eigenschaften beliebig mit Daten füllen.

BlackPixel ·
Eydamos schrieb

Ich habe folgende Idee nicht getestet, sollte aber eigentlich funktionieren:

Erweiter dein Model einfach um die entsprechenden Eigenschaften wie z.B. distanz. Mach dazu deine setter und getter Methoden.
Trage die Eigenschaften die nicht in die Datenbank sollen auch NICHT ins TCA ein. Das sollte verhindern, dass TYPO3 versucht die Daten in die Datenbank zu schreiben bzw Sie auszulesen.
Im Controller kannst du dann die Eigenschaften beliebig mit Daten füllen.

Genauso gehts. Einfach Dein Model um die Properties erweitern die du benötigst. Die Felder die nicht in der DB vorhanden sind werden auch nicht geschrieben.

Gruß Manfred

Freshmeat ·

Das habe ich bereits mit dem generischen Link probiert. Jedoch wird dieser im Objekt nicht mitgegeben, wenn ich z.B. über das Repository das Objekt anfrage.

Habe dann versucht die Funktion im Konstruktor (oder auch im initStorageObjects) aufzurufen, aber dadurch wurde der Link nicht gesetzt. Und ich möchte nicht jedesmal einen Schleife machen für alle Objekte um den Link zu setzen.

Was mache ich falsch?

Eydamos ·

Du musst den Wert wenn er nicht aus der Datenbank kommt irgendwo setzen.

Entweder du schreibst ihn statisch ins Model rein, wenn es eh immer der selbe Wert ist kannst du ihn ja so als default nutzen, oder du setzt ihn im Controller. Wenn es mehrere Objekte sind musst du die halt in ner Schleife durchlaufen lassen.
Der Konstruktor ist natürlich auch eine Möglichkeit, nur wird es dann glaub ich schwer einen Wert zu übergeben.

Freshmeat ·

Konkret geht es um folgenden Link:

http://maps.google.ch/maps?f=d&hl=de&geocode=&saddr=&daddr= ADDRESSE &sll= LATITUDE , LONGITUDE &sspn=&ie=isoz=15

Die grossgeschriebenen Variablen des Links sind im Model (Datenbank) hinterlegt. Dieser Link möchte ich nun z.B. als Property "googleMapsUri" im Model verfügbar haben. Beim "build" des Models soll dieser erzeugt werden.

Eydamos ·

Du kannst ihn ja auch beim abfragen generieren.

Fluid:

{object.googleMapsUri}

Model:

public function getGoogleMapsUri() {
  return "http://maps.google.ch/maps?f=d&hl=de&geocode=&saddr=&daddr=".$this->addresse."&sll=".$this->latitude.",".$this->longitude."&sspn=&ie=isoz=15";
}
Freshmeat ·

Okey ... jetzt konnte ich es lösen. Auf meine Art zufriedenstellend. Vielleicht sogar korrekt. Hatte etwas kompliziert gedacht.

Im Model habe ich die Distanz erweitert (ohne Datenbankfeld)
Im Repository eine Funktion geschrieben mit einem eigenen SQL-Statement das die umliegenden Standorte sucht. Liefert aber Objects zürck
Im Controller durchlaufe ich dann (trotzdem) nochmals alle Standorte und berechne mit der Suchanfrage die Distanz zum gewählten Standort. (PHP)

Model

/**
 * Description of property: distance
 *
 * @var string
 */
protected $distance;

/**
 * Returns the distance between the own point and the target location
 *
 * @param string $lat
 * @param string $lng
 * @return string $distance 
 */
public function calculateDistance($lat, $lng) {

	$lat = $lat * 3.141 / 180; // calculate radian
	$lng = $lng * 3.141 / 180; // calculate radian
	
	$placeLat = $this->getPlace()->getLatitude() * 3.141 / 180; // calculate radian
	$placeLng = $this->getPlace()->getLongitude() * 3.141 / 180; // calculate radian
	
	$distance = round( 6371 * acos(sin($placeLat) * sin($lat) + cos($placeLat) * cos($lat) * cos($placeLng - $lng) ), 2);
	
	return $distance;
}

Repository

public function findDemanded(Tx_KiAffiliates_Domain_Model_Demand $demand = NULL, $storagePid = NULL) {
	
	$affiliatesQuery = $this->createQuery();
	
	if ($demand !== NULL) {
		
		$affiliatesQuery->statement('
			SELECT places.*, affiliates.*, ( ROUND( 6371 * ACOS( SIN( '.$demand->getSearchLocationLat().' * PI() / 180 ) * SIN( latitude * PI() / 180 ) + COS( '.$demand->getSearchLocationLat().' * PI() / 180 ) * COS( latitude * PI() / 180 )  *  COS( ( longitude * PI() / 180) - ('.$demand->getSearchLocationLng().' * PI() / 180) ) ), 1 ) ) AS distance
			FROM tx_kiaffiliates_domain_model_places AS places
			INNER JOIN tx_kiaffiliates_domain_model_affiliates AS affiliates
			ON affiliates.place = places.uid
			WHERE affiliates.pid = '.$storagePid.'
			AND NOT affiliates.deleted
			AND NOT affiliates.hidden
			AND (
				( affiliates.starttime = 0 AND affiliates.endtime = 0)
				OR ( affiliates.starttime < UNIX_TIMESTAMP() AND affiliates.endtime > UNIX_TIMESTAMP() )
				OR ( affiliates.starttime = 0 AND affiliates.endtime > UNIX_TIMESTAMP() )
				OR ( affiliates.starttime < UNIX_TIMESTAMP() AND affiliates.endtime = 0 )
			)
			AND affiliates.sys_language_uid IN (0, -1)
			HAVING distance < '.$demand->getSearchLocationRad().'
			ORDER BY distance
		');
		
	}

	$affiliates = $affiliatesQuery->execute();
	
	return $affiliates;
	
}

Controller

$affiliates = $this->affiliatesRepository->findDemanded($demand, intval($configuration['persistence']['storagePid']));

foreach ($affiliates as $affiliate) {
	
	$distance = $affiliate->calculateDistance($demand->getSearchLocationLat(), $demand->getSearchLocationLng());
	$affiliate->setDistance($distance);
	
}

Kann/darf/sollte man das so machen?

Eydamos ·

Ja ich denke ich hätte es auf jeden Fall ähnlich wenn nicht genauso gemacht.

Noch eine kleine Anmerkung zum Controller:
Du berechnest die Distanz und speicherst sie anschließend mit einer extra Methode ab. Es ist doch das selbe Objekt, also speicher die Distanz direkt im Objekt anstatt es zurückzugeben und danach mit einer setter zu speichern.