Zum Inhalt springen

Schwaches Entity (weak entity) in Datensätzen

Erstellt am 4. November 2005 · 29 Antworten · letzte Antwort am 15. Januar 2007 · Seite 1 von 2

Tags: TCA, Frage

Stoneage ·

Hallo Benjamin,

Ich programmiere zur Zeit auch eine Veranstaltungsdatenbank, und fand Deine Frage sehr inspirierend. Herzlichen Dank! Ich habe mich sogar gleich drangesetzt und eine Lösung gefunden.

Meine Lösung:

1) in der tabelle veranstaltungen habe ich ein Feld Termine mit einer 1:n Beziehung (genau wie Du beschrieben hast, weak entity) zu der Tabelle tx_termine mit folgender config:

$TCA (Ausschnitt):

   <?php
 	"termine" => Array (		
			"exclude" => 1,		
			"label" => "LLL:EXT:veranstaltungen/locallang_db.php:tx_veranstaltung.termine",		
			"config" => Array (
				"type" => "select",		
				"size" => 10,	
				"minitems" => 0,
				"maxitems" => 20,
				"foreign_table" => "tx_termine",	
				"foreign_table_where" => "AND tx_termine.foreign_uid=###THIS_UID###"
				"wizards" => Array(
					"_PADDING" => 2,
					"_VERTICAL" => 1,
					"add" => Array(
					...
	?>

wichtig ist die zeile: "foreign_table_where" => "AND tx_termine.foreign_uid=###THIS_UID###"

damit hast du schon eine weak entity beziehung. das problem ist nun wie kriege ich die uid von der veranstaltung in die tabelle tx_termine, wenn man aus der veranstaltung einen neuen termin anlegt? das hat etwas gedauert bis bei mir der groschen fiel. zuerst habe ich gedacht das es über das wizard add skript (wizard_add.php) gehen würde, aber das war eine Sackgasse. Nach langem suchen hatte ich dann die idee das feld foreign_uid in der tabelle tx_termine als typ 'user' anzulegen. damit hat es dann geklappt (siehe step 2)

2) in der tabelle tx_termine habe ich das feld foreign_uid als typ 'user' angelegt (fid (Firmen-ID, Primary Key!) in Deiner Tabelle). in der user funktion habe ich dann ein hidden feld mit der aktuellen eltern uid zurückgegeben, so dass beim speichern des ganzen formulars das feld in die tabelle tx_termine abgespeichert wird! es sieht zwar etwas unschön aus, wenn ein hiddenfeld zurückgegeben wird, weil da automatisch ein normales be feld mit label und tabelle drumrum gewrapt wird, aber ich kann damit leben (der kunde hoffentlich auch). als letztes musste ich noch sicherstellen, dass die foreign_uid nicht belegt ist, weil man die Termine auch direkt bearbeiten kann! in diesem fall wird die (existierende) foreign_uid als hidden feld zurückgegeben.

Beispiel:

$TCA:

		<?php
   		'foreign_uid' => Array (
			'exclude' => 1,			
			'config' => Array (
				 'type' => 'user',
				 'userFunc' => 'tx_veranstaltungen_tcaTypeUser->hiddenUID',
			)
		),
		?>

die Klasse:

   <?php
   class tx_veranstaltungen_tcaTypeUser {
 
	function hiddenUID($PA, $fobj) {		
		
		if (empty($PA['row']['foreign_uid'])) {
			# create new date or doc			
			$getParams = explode('&',t3lib_div::_GET('returnUrl'));
			foreach ($getParams as $key) {
				$temp = explode("=",$key);
				$getParams[$temp[0]]=$temp[1];
			}			
			return '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.$getParams['P[uid]'].'" />';
		} else {
			# edit date or doc
			return '<input type="hidden" name="'.$PA['itemFormElName'].'" value="'.$PA['row']['foreign_uid'].'" />';
		}
		
	}
  }

Anmerkung: die eltern uid hole ich mir von der returnUrl, das ist nicht gerade schön, aber es funktionert!

3) fürs löschen habe ich den Hook processCmdmap_preProcess in der klasse tcemain benutzt. siehe auch tt_news.

Beispiel:

die Registrierung des Hooks in der ext_localconf.php

    <?php
   # Register t3lib_tcemain processCmdmapClass (processCmdmap_preProcess) hook
$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass']['0'] = 'EXT:veranstaltungen/pi1/class.tx_tcemain.php:tx_tcemain';
	?>

die Klasse:

   <?php

	class tx_tcemain {
	
		function processCmdmap_preProcess($command, $table, $id, $value, &$pObj) {		
			if ($command == 'delete' && $table == 'tx_termine') {
				# alle Termine dieser Veranstaltung löschen
				$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*','tx_termine','foreign_uid='.$id);			
				$result = array();		
				while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
					$pObj->deleteRecord('tx_termine',$row['uid'], 0);
				}
			}
		} 
    }
	?>

Und es funktioniert! Ich kann aus jeder Veranstaltung heraus mehrere Termine anlegen, die Veranstaltung kennt nur zugehörige Termine, wenn ich eine Veranstaltung lösche, werden alle zugehörigen Termine gelöscht. Perfekt! Getestet auf T3 3.8.0.

Ich hab oft in die T3 Core Api geguckt, und kann das nur empfehlen: https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Index.html

Viele Grüße,

T.

steffenk ·

WOW ! 8-)

Das finde ich sehr interessant und ich werde mir das genauer zu Gemüte führen, das ist ja kein Einzelfall für diese Anforderung.

Wird Deine Veranstaltungs-Extension auch public ? **interesse bekunde**

BenjaminW ·
Tetramatrix schrieb

Ich programmiere zur Zeit auch eine Veranstaltungsdatenbank, und fand Deine Frage sehr inspirierend. Herzlichen Dank! Ich habe mich sogar gleich drangesetzt und eine Lösung gefunden.

VIELEN DANK!!! Das freut mich aber sehr.
Ich werds mir gleich anschauen. 😃

Gruß,
Benjamin

BenjaminW ·

Es funktioniert tatsächlich. So ganz will mir aber das nicht gefallen. Erstens habe ich jetzt eine doppelte Referenzierung, das heisst, ich habe in der Tabelle Veranstaltungen einen BLOB mit komma-getrennten IDs (kommt gut bei SELECT Abfragen mit JOINs...) und zusätzlich in der Termine Tabelle noch die direkte Referenzierung zu den Veranstaltungen...
Aber wir kommen dem ganzen schon ein gutes Stück näher.

Kann man sich irgendwie die BLOB-Spalte sparen? Dann hätte ich halt noch das Problem, dass ich nicht in der List-Ansicht die Start und Endzeiten als Übersicht habe.

Der Hook-Code hatte einen kleinen Fehler:

<?php
# Register t3lib_tcemain processCmdmapClass (processCmdmap_preProcess) hook
$TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'][] = 'EXT:veranstaltungen/pi1/class.tx_tcemain.php:tx_tcemain';
?>

Aus dem ['processCmdmapClass']['0'] muss ein ['processCmdmapClass'][] gemacht werden, sonst überschreibt man Hooks von anderen Extensions (tt_news).

Noch als Ergänzung für die interessierte Allgemeinheit :-)
Hier noch die Hookfunktion fürs Kopieren von Veranstaltungen(Termine werden automatisch mitkopiert), die ich mal dazugescriptet habe. Die muss dazukopiert werden.

<?php
function processCmdmap_postProcess($command, $table, $id, $value, &$pObj)
{
  if ($command == 'copy' && $table == 'tx_weakentitytest_events' 
    and $pObj->copyMappingArray['tx_weakentitytest_events'])
  {
    // Ziel-ID herausfinden. Die steht im copyMappingArray
    $source = $id;
    $dest = $pObj->copyMappingArray['tx_weakentitytest_events'][$source];

    $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 
      'tx_weakentitytest_event_dates',
      'foreign_uid='.$source);

    while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))
    {
      // Datensätze kopieren. foreign_uid remappen
      // auf die neue Veranstaltungs-ID.
      $pObj->copyRecord('tx_weakentitytest_event_dates',$row['uid'],
        $row['pid'],0,array('foreign_uid' => $dest));
    }
  }
}
?>

Gruß,
Benjamin

Stoneage ·

Hallo Benjamin,

das BLOB-Feld kann man eventuell mit einer MM-Tabelle rausschmeissen. In die List-Ansicht kann man sich nur reinhacken (HOOK?), aber wie stellst Du Dir die Ansicht mit mehreren Terminen vor? Das wird ja voll die Fummelarbeit.

Gruß,

T.

BenjaminW ·

Hi Tetramatrix,

Tetramatrix schrieb

das BLOB-Feld kann man eventuell mit einer MM-Tabelle rausschmeissen.

Na dann hab ich ja immernoch die doppelte Referenzierung, und das auch noch in einer weiteren Table :-)

Tetramatrix schrieb

In die List-Ansicht kann man sich nur reinhacken (HOOK?), aber wie stellst Du Dir die Ansicht mit mehreren Terminen vor? Das wird ja voll die Fummelarbeit.

Ok, dann werd ich das wohl über ein eigenes Web->Modul lösen müssen.

Es ist halt z.Z. irgendwie nur ein riesiger Workaround. Typo3 kennt vom Core her keine identifizierende 1:n Beziehung (außer halt die "pid" Spalte bei z.B. tt_content).

Nachdenkliche Grüße,
Benjamin

Stoneage ·

Na dann hab ich ja immernoch die doppelte Referenzierung, und das auch noch in einer weiteren Table

Du könntest doch die foreign_uid in die mm_tabelle packen?

BenjaminW ·

Hi!

Tetramatrix schrieb

Du könntest doch die foreign_uid in die mm_tabelle packen?

Hm, geht das denn? Ich habe immer gedacht, dass die mm_table nicht bearbeitet werden kann, zumindest gibts ja dafür keine Konfiguration in der TCA, oder?

Gruß,
Benjamin

BenjaminW ·

Hi Tetram.,

Tetramatrix schrieb

das aber ne gute idee, oder?

Es geht halt nicht um den BLOB, sondern um diese zusätzliche Referenzierung der Veranstaltung zu Termine.
Letztlich gesehen ist das alles irgendwie murks :-) von vernünftigem DB-Design ist das weit entfernt.
Das DB Design sollte schon irgendwo entsprechenden Standards genügen (ist Vorgabe des Kunden). Jeder DB Fachmann kriegt Warzen wenn er das sieht *gg*

Ich bin halt noch ein wenig unschlüssig, ob das wirklich das Problem am Schopfe packt. Was wir bisher gemacht haben, ist, dass wir das foreign_table Feature ein wenig eingeschränkt haben. Was aber bleibt ist die Art und Weise, wie Typo3 die Referenzierungen macht. Eigentlich sollte die Zuweisung schon dadurch passiert sein, dass ein entsprechender Termin-Datensatz existiert und nicht noch durch eine weitere Zuweisung (ob per BLOB oder mm_table ist letztlich egal). Es ist ja keine M:N Beziehung, Typo3 macht aber eine.
Mein Formular sieht halt jetzt so aus, dass ich zwei Listen habe (links die zugewiesenen und rechts die vorhandenen). Das aber brauche ich eigentlich nicht, sondern nur eine Liste aller Termine, die ich im Veranstaltungs-Formular hinzufügen, bearbeiten und auch löschen (daran zerbreche ich mir grad den Kopf -> wizard) kann.

Grüße,
Benjamin

Stoneage ·

Hallo Benjamin,

stimmt, das zuweisen mit linker und rechter Spalte ist eigentlich unnötig. das könnte man auch rauschmeissen. meinst du findest eine lösung? Ich habe ja schon den Start gemacht...

Gruß,

T.

BenjaminW ·
Tetramatrix schrieb

das könnte man auch rauschmeissen. meinst du findest eine lösung? Ich habe ja schon den Start gemacht...

😉

Ich habe heute nochmal den ganzen Tag getüftelt. Mit Erfolg!
Zuerst habe ich aus dem "termine" Feld in Veranstaltungen ein User-defined Field gemacht. Die Liste baue ich nun selber auf. Außerdem habe ich die Wizards für Hinzufügen, Editieren und Löschen über TCEforms::renderWizards (ein Krampf war das!) um meinen Output gestülpt. Das klappt soweit und sieht auch gut aus. Leider funktioniert es noch nicht so wie ich es will. Delete musste ich über einen eigenen Wizard implementieren und Edit läuft auch noch nicht, weil wizard_edit.php anscheinend die ausgelesene ID nicht kriegt (er geht ja von zwei Listen aus, liest folglich die falsche aus), aber das schaffe ich glaube ich morgen schon (denke ich *gg*). Zur Not bastle ich auch noch den Edit-Wizard selbst...

Ich habe in der core api doku das Flag "noTableWrapping" gesehen (https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ColumnsConfig/Type/User/Index.html).
Wenn ich das richtig verstehe, kann ich hiermit verhindern, dass diese Spalte in die Datenbank geschrieben wird , oder? *hoff*
Zur Not lass ich sonst einfach den BLOB leer, fürs Auslesen vom Frontend-Plugin aus brauch ich ihn ja nicht.

Sobald ich was zeigbares habe, werd ich das hier mal posten; es scheint ja immerhin eine Premiere zu sein ;-)

Nochmals vielen Dank für die Denkanstöße!

Gruß,
Benjamin

BenjaminW ·

Hallo Tetramatrix,

Tetramatrix schrieb

das feld wird einfach nicht in der tceform gerendert.

Richtig. Habe ich inzwischen auch mit Bedauern festgestellt. Ich habe einfach die Spalte als VARCHAR definiert. Das ist wenigstens performanter.

Tetramatrix schrieb

bist du weiter gekommen?

Ja! Es läuft soweit. Hat noch ein paar Kinderkrankheiten, für die ich noch die richtige Medizin suche. Beispielsweise möchte ich Start und Endzeiten bei der Eingabe überprüfen (per Javascript am besten), ob Startzeit kleiner als Endzeit ist.

Sobald ich die Extension für mein derzeitiges Projekt fertig habe, werde ich mich mal an nem WE ransetzen und die wesentlichen Dinge rausisolieren und hier posten bzw. vielleicht mal als Beispiel-Extension auf Typo3.net.

Gruß,
Benjamin

Stoneage ·

Hallo Benjamin,

Zuerst habe ich aus dem "termine" Feld in Veranstaltungen ein User-defined Field gemacht. Die Liste baue ich nun selber auf. Außerdem habe ich die Wizards für Hinzufügen, Editieren und Löschen über TCEforms::renderWizards (ein Krampf war das!) um meinen Output gestülpt. Das klappt soweit und sieht auch gut aus. Leider funktioniert es noch nicht so wie ich es will. Delete musste ich über einen eigenen Wizard implementieren und Edit läuft auch noch nicht, weil wizard_edit.php anscheinend die ausgelesene ID nicht kriegt (er geht ja von zwei Listen aus, liest folglich die falsche aus), aber das schaffe ich glaube ich morgen schon (denke ich *gg*). Zur Not bastle ich auch noch den Edit-Wizard selbst...

Ich habe jetzt sowas ähnliches gemacht. Vielen Dank für Deine Hilfe!

T.

Stoneage ·

Hier mal meine Lösung:

In der ext_tables.php die neue Klasse tx_chvacationindex_tcaSingleBox inludieren:

// class for rendering a singlebox by a user function or class method.
include_once(t3lib_extMgm::extPath($_EXTKEY).'TCA/class.tx_chvacationindex_tcaSingleBox.php');

In der tca.php die user function tx_chvacationindex_tcaSingleBox->singleBox aufrufen:

'config' => Array (
 				'type' => 'select',
                                'form_type' => 'user',
				'userFunc' => 'tx_chvacationindex_tcaSingleBox->singleBox',
				'size' => 10,
				'minitems' => 0,
				'maxitems' => 100,
				'foreign_table' => 'tx_chvacationindex_accommodation',	
				'foreign_table_where' => 'AND tx_chvacationindex_accommodation.parent_uid=###THIS_UID###',
				'MM' => 'tx_chvacationindex_accommodation_mm',
                    )

Die Klasse "tx_chvacationindex_tcaSingleBox" zum abspeichern:

<?php

/***************************************************************
*  Copyright notice
*
*  (c) 2006 Chi Hoang (chibox@gmail.com)
*  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_t3lib.'class.t3lib_tceforms.php');
 
class tx_chvacationindex_tcaSingleBox extends t3lib_TCEforms {

	function singleBox($PA, $fobj) {		
	    global $TCA;
        
			// Field configuration from TCA:
		$config = $PA['fieldConf']['config'];

			// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist. See http://typo3.org/documentation/document-library/doc_core_api/Wizards_Configuratio/.
		$specConf = $this->getSpecConfFromString($PA['extra'], $PA['fieldConf']['defaultExtras']);

			// Getting the selector box items from the system
		$selItems = $this->addSelectOptionsToItemArray($this->initItemArray($PA['fieldConf']),$PA['fieldConf'],$this->setTSconfig($PA['fieldConf']['config']['foreign_table'],$PA['row']),$field);
        $selItems = $this->addItems($selItems,$PA['fieldTSConfig']['addItems.']);

        if ($config['itemsProcFunc']) $selItems = $this->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);

			// Possibly remove some items:
		$removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
        
		foreach($selItems as $tk => $p)	{
				// Checking languages and authMode:
			$languageDeny = $TCA[$table]['ctrl']['languageField'] && !strcmp($TCA[$table]['ctrl']['languageField'], $field) && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
			$authModeDeny = $config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$p[1],$config['authMode']);
			if (in_array($p[1],$removeItems) || $languageDeny || $authModeDeny)	{
				unset($selItems[$tk]);
			} elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
				$selItems[$tk][0]=$this->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
			}

				// Removing doktypes with no access:
			if ($table.'.'.$field == 'pages.doktype')	{
				if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'],$p[1])))	{
					unset($selItems[$tk]);
				}
			}
		}

			// Creating the label for the "No Matching Value" entry.
		$nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ '.$this->getLL('l_noMatchingValue').' ]';

			// Prepare some values:
		$maxitems = intval($config['maxitems']);        

        return $this->getSingleBox($PA['table'],$PA['field'],$PA['row'],$PA,$config,$selItems,$nMV_Label);  
	}

	/**
	 * Creates a multiple-selector box (two boxes, side-by-side)
	 * (Render function for getSingleField_typeSelect())
	 *
	 * @param	string		See getSingleField_typeSelect()
	 * @param	string		See getSingleField_typeSelect()
	 * @param	array		See getSingleField_typeSelect()
	 * @param	array		See getSingleField_typeSelect()
	 * @param	array		(Redundant) content of $PA['fieldConf']['config'] (for convenience)
	 * @param	array		Items available for selection
	 * @param	string		Label for no-matching-value
	 * @return	string		The HTML code for the item
	 * @see getSingleField_typeSelect()
	 */
	function getSingleBox($table,$field,$row,&$PA,$config='',$selItems='',$nMV_label='')	{

			// Setting this hidden field (as a flag that JavaScript can read out)
		$item.= '<input type="hidden" name="'.$PA['itemFormElName'].'_mul" value="'.($config['multiple']?1:0).'" />';

			// Set max and min items:
		$maxitems = t3lib_div::intInRange($config['maxitems'],0);
		if (!$maxitems)	$maxitems=100000;
		$minitems = t3lib_div::intInRange($config['minitems'],0);

			// Register the required number of elements:
		$this->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);

			// Get "removeItems":
		$removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
             
			// Perform modification of the selected items array:
		$itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
        
        foreach ($itemArray as $k => $v) {
            $tvP = explode('|',$v,2);
            $iA[$tvP[0]]=rawurldecode($tvP[1]); 
        }
        
        foreach ($selItems as $k) {
            if (!$iA[$k[1]]) {
                $iA[$k[1]] = $k[0];
            }            
        }        
        
        $itemArray=array();
        
        foreach ($iA as $k => $v) {
            $itemArray[] = $k.'|'.rawurlencode($v);
        }
        
		foreach($itemArray as $tk => $tv) {
			$tvP = explode('|',$tv,2);            
			$evalValue = rawurldecode($tvP[0]);
			$isRemoved = in_array($evalValue,$removeItems)  || ($config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$evalValue,$config['authMode']));
			if ($isRemoved && !$PA['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement'])	{
				$tvP[1] = rawurlencode(@sprintf($nMV_label, $evalValue));
			} elseif (isset($PA['fieldTSConfig']['altLabels.'][$evalValue])) {
				$tvP[1] = rawurlencode($this->sL($PA['fieldTSConfig']['altLabels.'][$evalValue]));
			} else {
				$tvP[1] = rawurlencode($this->sL(rawurldecode($tvP[1])));
			}
			$itemArray[$tk] = implode('|',$tvP);
		}

		$size = intval($config['size']);
		$size = $config['autoSizeMax'] ? t3lib_div::intInRange(count($itemArray)+1,t3lib_div::intInRange($size,1),$config['autoSizeMax']) : $size;
        
			// Pass to "dbFileIcons" function:
		$params = array(
			'size' => $size,
			'autoSizeMax' => t3lib_div::intInRange($config['autoSizeMax'],0),
			'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
			'dontShowMoveIcons' => ($maxitems<=1),
			'maxitems' => $maxitems,
			'info' => '',
			'headers' => array(
				'selector' => $this->getLL('l_selected').':<br />',
				'items' => $this->getLL('l_items').':<br />'
			),
			'noBrowser' => 1,
			'thumbnails' => $itemsToSelect
		);        
        
		$item .= $this->dbFileIconsSingleBox($PA['itemFormElName'],'','',$itemArray,'',$params,$PA['onFocus']);
        $item = $this->renderWizards(array($item,$altItem),$config['wizards'],$table,$row,$field,$PA,$PA['itemFormElName'],$specConf,$RTEwouldHaveBeenLoaded);
        
		return $item;
	}
    
    	/**
	 * Prints the selector box form-field for the db/file/select elements (multiple)
	 *
	 * @param	string		Form element name
	 * @param	string		Mode "db", "file" (internal_type for the "group" type) OR blank (then for the "select" type)
	 * @param	string		Commalist of "allowed"
	 * @param	array		The array of items. For "select" and "group"/"file" this is just a set of value. For "db" its an array of arrays with table/uid pairs.
	 * @param	string		Alternative selector box.
	 * @param	array		An array of additional parameters, eg: "size", "info", "headers" (array with "selector" and "items"), "noBrowser", "thumbnails"
	 * @param	string		On focus attribute string
	 * @return	string		The form fields for the selection.
	 */
	function dbFileIconsSingleBox($fName,$mode,$allowed,$itemArray,$selector='',$params=array(),$onFocus='')	{

			// Sets a flag which means some JavaScript is included on the page to support this element.
		$this->printNeededJS['dbFileIcons']=1;

			// INIT
		$uidList=array();
		$opt=array();
		$itemArrayC=0;

			// Creating <option> elements:
		if (is_array($itemArray))	{
			$itemArrayC=count($itemArray);
			reset($itemArray);
			switch($mode)	{
				case 'db':
					while(list(,$pp)=each($itemArray))	{
						$pRec = t3lib_BEfunc::getRecord($pp['table'],$pp['id']);
						if (is_array($pRec))	{
							$pTitle = t3lib_div::fixed_lgd_cs($this->noTitle($pRec[$GLOBALS['TCA'][$pp['table']]['ctrl']['label']]),$this->titleLen);
							$pUid = $pp['table'].'_'.$pp['id'];
							$uidList[]=$pUid;
							$opt[]='<option value="'.htmlspecialchars($pUid).'">'.htmlspecialchars($pTitle).'</option>';
						}
					}
				break;
				case 'file':
					while(list(,$pp)=each($itemArray))	{
						$pParts = explode('|',$pp);
						$uidList[]=$pUid=$pTitle = $pParts[0];
						$opt[]='<option value="'.htmlspecialchars(rawurldecode($pParts[0])).'">'.htmlspecialchars(rawurldecode($pParts[0])).'</option>';
					}
				break;
				default:
					while(list(,$pp)=each($itemArray))	{
						$pParts = explode('|',$pp);
						$uidList[]=$pUid=$pParts[0];
						$pTitle = $pParts[1];
						$opt[]='<option value="'.htmlspecialchars(rawurldecode($pUid)).'">'.htmlspecialchars(rawurldecode($pTitle)).'</option>';
					}
				break;
			}
		}

			// Create selector box of the options
		$sSize = $params['autoSizeMax'] ? t3lib_div::intInRange($itemArrayC+1,t3lib_div::intInRange($params['size'],1),$params['autoSizeMax']) : $params['size'];
		if (!$selector)	{
			$selector = '<select size="'.$sSize.'" this-="">insertDefStyle('group').' multiple="multiple" name="'.$fName.'_list" '.$onFocus.$params['style'].'>'.implode('',$opt).'</select>';
		}

		$icons = array(
			'L' => array(),
		);
        
		if (!$params['dontShowMoveIcons'])	{
			if ($sSize>=5)	{
				$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Top\'); return false;">'.
						'<img'.t3lib_iconworks::skinimg($this->backPath,'gfx/group_totop.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_move_to_top')).' />'.
						'</a>';
			}
			$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Up\'); return false;">'.
					'<img'.t3lib_iconworks::skinimg($this->backPath,'gfx/up.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_move_up')).' />'.
					'</a>';
			$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Down\'); return false;">'.
					'<img'.t3lib_iconworks::skinimg($this->backPath,'gfx/down.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_move_down')).' />'.
					'</a>';
			if ($sSize>=5)	{
				$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Bottom\'); return false;">'.
						'<img'.t3lib_iconworks::skinimg($this->backPath,'gfx/group_tobottom.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_move_to_bottom')).' />'.
						'</a>';
			}
		}
        
		$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Remove\'); return false;">'.
				'<img'.t3lib_iconworks::skinimg($this->backPath,'gfx/group_clear.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_remove_selected')).' />'.
				'</a>';

		$str='<table border="0" cellpadding="0" cellspacing="0" width="1">
			'.($params['headers']?'
				<tr>
					<td>'.$this->wrapLabels($params['headers']['selector']).'</td>
					<td></td>
					<td></td>
					<td></td>
				</tr>':'').
			'
			<tr>
				<td valign="top">'.
					$selector.'<br />'.
					$this->wrapLabels($params['info']).
				'</td>
				<td valign="top">'.
					implode('<br />',$icons['L']).'</td>
				<td valign="top"></td>
				<td><img src="clear.gif" width="5" height="1" alt="" /></td>
			</tr>
		</table>';

			// Creating the hidden field which contains the actual value as a comma list.
		$str.='<input type="hidden" name="'.$fName.'" value="'.htmlspecialchars(implode(',',$uidList)).'" />';

		return $str;
	}
}
?>
L1NU5 ·

Vielen Dank für das Posten deiner Lösung!

Dein Script enthält einen kleinen Fehler in Zeile 223:

$selector = '<select size="'.$sSize.'" this-="">insertDefStyle('group').' multiple="multiple" name="'.$fName.'_list"

müsste eigentlich folgendermassen heissen:

$selector = '<select size="'.$sSize.'" this-="">insertDefStyle('group') . ' multiple="multiple" name="'.$fName.'_list"

Leider funktionieren auch die Wizards nicht 😢
Habe es auf einem ähnlichem Weg versucht, aber den part mit den Wizards leider auch nicht hinbekommen...

Vielleicht kennt ja Jemand 'ne Lösung, oder Benjamin präsentiert mal seine #paralyzed#

Gruß Linus

Stoneage ·

Die PHP Anzeige vom Forum funktioniert wohl nicht ganz richtig. #angry# Die hat kleinere Probleme mit dem Parsen. Mein Skript ist schon korrekt. Es muß natürlich so heissen:

... $this->insertDefStyle('group') ...

Die Wizards (Add, List, Edit) funktionieren bei mir aber ganz gut. Die haben mit meinem Skript rein gar nichts zu tun. Die tust Du nach wie vor in der $TCA inkludieren:

'config' => Array (
    'MM' => 'tx_chvacationindex_accommodation_mm',
    'wizards' => Array(
        '_PADDING' => 2,
        '_VERTICAL' => 1,
        'add' => Array(
            'type' => 'script',
            'title' => 'Create new record',
            'icon' => 'add.gif',
            'params' => Array(
                'table'=>'tx_chvacationindex_accommodation',
                'pid' => '###CURRENT_PID###',
                'setValue' => 'append'
            ),
            'script' => 'wizard_add.php',
        ),
        'list' => Array(
            'type' => 'script',
            'title' => 'List',
            'icon' => 'list.gif',
            'params' => Array(
                'table'=>'tx_chvacationindex_accommodation',
                'pid' => '###CURRENT_PID###',
            ),
            'script' => 'wizard_list.php',
        ),
        'edit' => Array(
            'type' => 'popup',
            'title' => 'Edit',
            'script' => 'wizard_edit.php',
            'icon' => 'edit2.gif',
            'popup_onlyOpenIfSelected' => 1,						
            'JSopenParams' => 'height=800,width=630,status=0,menubar=0,scrollbars=1',
        ),
    )
L1NU5 ·

Die PHP Anzeige vom Forum funktioniert wohl nicht ganz richtig. #angry# Die hat kleinere Probleme mit dem Parsen.

#giggle# War mir gestern garnicht aufgefallen!

Die Wizards (Add, List, Edit) tust Du nach wie vor in der $TCA inkludieren:

Ja, schon klar, aber irgendwie funktioniert bei mir das Selektieren eines Eintrags in der Selectbox nicht richtig,
so dass Edit immer nur ausspuckt, dass kein Eintrag markiert ist...

Ausserdem kann ich auch keinen Eintrag aus der Selectbox löschen...

Naja, keine Ahnung wo bei mir da das Problem ist, aber ich werde mich Morgen nochmal ransetzen.

Vielen Dank für deine Hilfe!

hnesk ·

Hmmm, bin hier gerade nur so reingeschlittert, aber kann es ein dass du versuchst, die Einträge in der rechten Box zu bearbeiten? Die Wizards beziehen sich auf die linke Seite, habe ich mir auch schon mal ein wenig den Kopf drüber zerbrochen.