99° Helpers für TYPO3 

Extension key

nnhelpers

Package name

nng/nnhelpers

Version

2.0.4

Language

de

Author

99°

License

Dieses Dokument ist veröffentlicht unter der Creative Commons BY 4.0 Lizenz.

Rendered

Tue, 09 Dec 2025 23:50:11 +0000


Eine umfassende Sammlung von Hilfsfunktionen für die TYPO3-Entwicklung.

Inhaltsverzeichnis

Wozu die Extension? 

Was macht nnhelpers? 

Diese Extension übernimmt den unschönen Teil Deines Entwickleralltags. Immer wenn Du denkst: "Verdammt, das muss doch irgendwie einfacher gehen" wirst Du Dich an nnhelpers erinnern. Die Extension sitzt in einem Backend-Modul, immer griffbereit – und (fast) immer mit einem einfachen Einzeiler, der Dein Problem löst.

Du willst Beispiele? Wunderbar. 

Schon mal probiert, in Typo3 ein simples Upload-Formular zu bauen, bei dem Dein User im Frontend ein Bild hochladen kann? Klingt eigentlich nach einem Kinderspiel, oder?

Nun ja. Wäre es auch – gäbe es da nicht den "File Abstract Layer" (FAL). Ein neues Domain-Model ist schnell gebaut und instanziiert. Aber wie bekommt man die Upload-Datei aus dem PHP tmp-Verzeichnis vernünftig in eine SysFileReference konvertiert, die sich an das Model hängen lässt?

Du stellt die Frage Google. Nach vielen Varianten Deiner Suchphrase landest Du auf der vielversprechenden Doku unter docs.typo3.org. Leider findest Du dort nur die ernüchternde Aussage: "Sorry, mein Lieber. Nicht unser Bier. Frag Helmut."

Du gibst also Helmut einen Besuch. Der macht einen prima Job. Viel Code. Super strukturiert und kommentiert. Eine knappe halbe Stunde versuchst Du, in seinem Repo genau das Stück destillierten Code zu identifiziern, das Du für Deinen Fall brauchst.

Für das Beispiel oben haben wir in der ersten Umsetzung knapp 4 Stunden gebraucht. Wir waren damals in der 6er Version von Typo3. Als dann Typo3 7 LTS veröffentlicht wurde, suchten wir erneut - im Core gab es neue, brilliante Ideen. Und in Version 8? Halleluja.

Immer wieder passten wir alle Extensions von uns an die neuen Konzepte der Typo3 Versionen an. Und jedes Mal schien uns das recht sinnfrei. Viel Zeit, die ich offen gesagt lieber mit anderen Dingen verbringe. Wenn es sein muss, auch mit meiner Schwiegermutter.

Wie lösen wir das heute?

Wir würde nnhelpers um Hilfe bitten.
Schauen wir mal ins Backend Module:

nnhelpers Backend Module

Das Backend Modul zeigt alle Methoden und ViewHelper übersichtlich gruppiert nach Themen

Wonach suchen wir?
Richtig. Es geht um FAL. Also: Runterscrollen wir zum Abschnitt FAL und schauen, was es im Angebot gibt|
nnhelpers Backend Module

Jede Methode hat eine ausführliche Erklärung und Beispiel.

setInModel() hört sich genau nach dem an, was wir suchen.
Wie sieht das Beispiel dazu aus?
\nn\t3::Fal()->setInModel( $model, 'fieldname', 'path/to/image.jpg' );
Copied!
Moment, willst Du mir wirklich sagen, um das Problem zu lösen, brauche ich nur einen verdammten Einzeiler?
Kein ObjectManager->get(), kein @inject?

Aber das Beste ist: Dieser Einzeiler wird sich nie ändern.
Nicht für Typo3 Version 7. Nicht für Typo3 11. Versprochen.

Ok, aber was ist, wenn der User mehrere Bilder hochgeladen hat?
Klar, ich könnte eine foreach-Schleife daraus machen. Aber Moment!
Das ist so einfach – hätte ich von selbst drauf kommen können.

\nn\t3::Fal()->setInModel( $model, 'fieldname', ['image-1.jpg', 'image-2.jpg'] );
Copied!
Ja, schön. Aber das ist gemogelt.
Meine Anwendung ist komplexer. Ich möchte, dass der User auch den Bildtitel und die Bildbeschreibung im Frontend eingeben kann. Oh – aber das scheint ja auch zu gehen:

\nn\t3::Fal()->setInModel( $member, 'fieldname', ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'] );
Copied!
HA! Jetzt hab ich Euch erwischt.
Ihr habt Euch selbst ein Ei gelegt. Jetzt kann der User ja nicht mehrere Bilder mit jeweils einem Titel und einer Beschreibung hochladen. Ähm... Moment - was ist das?
\nn\t3::Fal()->setInModel( $member, 'fieldname', [
   ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'],
   ['publicUrl'=>'02.jpg', 'title'=>'Titel', 'description'=>'...'],
]);
Copied!
Ja, aber mal ehrlich: Das ist häßlich. An der Uni habe ich gelernt, dass...
Richtig. Aber wenn es das Leben einfacher macht, ist uns das einfach egal.
Das hier ist eine Zeile Code, die Du Dir merken kannst. Die Benutzung ist intuitiv – sie folgt keinen Konventionen oder Paradigmen. Sie folgt Deiner Intuition.

Dir gefällt das alles nicht?
Fein. Dann kannst Du Dir den Quelltext klauen und daraus etwas eigenes bauen. Damit Du nicht in Dein Dateisystem abtauchen musst, haben wir auch hier mitgedacht: Ein Klick und Du blickst mitten ins Eingemachte.

nnhelpers Backend Module

Quelltext direkt im Backend anschauen.

Deine Entscheidung!

Stop thinking, start coding. 

Installation 

Die Installation läuft wie bei jeder Extension ab.

Du musst keine TypoScript-Templates hinzufügen. Da die Extension "nichts tut", außer einen Werkzeugkoffer an Methoden und Funktionen für Deine tägliche Arbeit bereitzustellen, wird es auch keine Konflikte mit anderen Extensions geben.

Du stehst auf den Extension Manager? 

Drücke den "Erweiterung hinzufügen"-Button und suche Sie nach dem Extension Key nnhelpers. Importiere die Extension aus dem Repository. Schau ins Backend-Modul. Fang an zu coden. Hab Spaß.

Handarbeit ist Dein Ding? 

Die aktuellste Version findest Du immer auf https://extensions.typo3.org/extension/nnhelpers/ zum direkten Download. Lade die t3x- oder zip-Version herunter - und anschließend im Extension-Manager hoch. Aktivieren, fertig.

composer ist Dein Freund? 

Wenn Typo3 bei Dir im Composer-Modus läuft, findest Du die neueste Version auf packagist unter dem Key nng/nnhelpers. Sorry, dass nng wie Angular klingt. Das ist ein ziemlich dämliches Akronym für Neunundneunziggrad (99°).

composer require nng/nnhelpers
Copied!

Nichts git übers GIT? 

Klar, gi(b)t es auch dort. Um genau zu sein, bei Bitbucket. Wenn es Dich glücklich macht, ziehe es Dir wie die "harten Jungs" über die Kommandozeile.

git clone https://bitbucket.org/99grad/nnhelpers/src/master/
Copied!

Dependencies festlegen 

Wenn Du nnhelpers in Deiner eigenen Extension verwenden möchtest, denke daran, die Abhängigkeiten in der ext_emconf.php und composer.json zu definieren:

Das hier kommt in die ext_emconf.php Deiner Extension:

$EM_CONF[$_EXTKEY] = [
   ...
   'constraints' => [
      'depends' => [
         'nnhelpers' => '1.7.0-0.0.0',
      ],
   ],
];
Copied!

Und das hier kommt in die composer.json Deiner Extension:

{
   ...
   "require": {
      "nng/nnhelpers": "^1.6"
   },
}
Copied!

Helpers Index 

Arrays 

\nn\t3::Arrays() 

Diverse Methoden, um mit Arrays zu arbeiten wie mergen, bereinigen oder leere Werte zu entfernen. Methoden, um ein Value eines assoziativen Arrays als Key zu verwenden.

Overview of Methods 

\nn\t3::Arrays()->first(); 

Gibt das erste Element des Arrays zurück, ohne array_shift()

\nn\t3::Arrays( $objArr )->first();
Copied!

| @return array

| ➜ Go to source code of Arrays::first()

\nn\t3::Arrays()->intExplode($delimiter = ','); 

Einen String – oder Array – am Trennzeichen splitten, nicht numerische und leere Elemente entfernen

\nn\t3::Arrays('1,a,b,2,3')->intExplode();     // [1,2,3]
\nn\t3::Arrays(['1','a','2','3'])->intExplode(); // [1,2,3]
Copied!

| @return array

| ➜ Go to source code of Arrays::intExplode()

\nn\t3::Arrays()->key($key = 'uid', $value = false); 

Als Key des Arrays ein Feld im Array verwenden, z.B. um eine Liste zu bekommen, deren Key immer die UID des assoziativen Arrays ist:

Beispiel:

$arr = [['uid'=>'1', 'title'=>'Titel A'], ['uid'=>'2', 'title'=>'Titel B']];
\nn\t3::Arrays($arr)->key('uid');          // ['1'=>['uid'=>'1', 'title'=>'Titel A'], '2'=>['uid'=>'2', 'title'=>'Titel B']]
\nn\t3::Arrays($arr)->key('uid', 'title');   // ['1'=>'Titel A', '2'=>'Titel B']
Copied!

| @return array

| ➜ Go to source code of Arrays::key()

\nn\t3::Arrays()->merge(); 

Ein assoziatives Array rekursiv mit einem anderen Array mergen.

$addKeys => wenn false werden nur Keys überschrieben, die auch in $arr1 existieren
$includeEmptyValues => wenn true werden auch leere Values in $arr1 übernommen
$enableUnsetFeature => wenn true, kann __UNSET als Wert in $arr2 verwendet werden, um eine Wert in $arr1 zu löschen
$mergedArray = \nn\t3::Arrays( $arr1 )->merge( $arr2, $addKeys, $includeEmptyValues, $enableUnsetFeature );
$mergedArray = \nn\t3::Arrays( $arr1 )->merge( $arr2 );
$mergedArray = \nn\t3::Arrays()->merge( $arr1, $arr2 );
Copied!

| @return array

| ➜ Go to source code of Arrays::merge()

\nn\t3::Arrays()->pluck($keys = NULL, $isSingleObject = false); 

Assoziatives Array auf bestimmte Elemente reduzieren / destillieren:

\nn\t3::Arrays( $objArr )->key('uid')->pluck('title');                    // ['1'=>'Titel A', '2'=>'Titel B']
\nn\t3::Arrays( $objArr )->key('uid')->pluck(['title', 'bodytext']);    // ['1'=>['title'=>'Titel A', 'bodytext'=>'Inhalt'], '2'=>...]
\nn\t3::Arrays( ['uid'=>1, 'pid'=>2] )->pluck(['uid'], true);            // ['uid'=>1]
Copied!

| @return array

| ➜ Go to source code of Arrays::pluck()

\nn\t3::Arrays()->removeEmpty(); 

Leere Werte aus einem Array entfernen.

$clean = \nn\t3::Arrays( $arr1 )->removeEmpty();
Copied!

| @return array

| ➜ Go to source code of Arrays::removeEmpty()

\nn\t3::Arrays()->toArray(); 

Gibt dieses Array-Object als "normales" Array zurück.

\nn\t3::Arrays( $objArr )->key('uid')->toArray();
Copied!

| @return array

| ➜ Go to source code of Arrays::toArray()

\nn\t3::Arrays()->trimExplode($delimiter = ',', $removeEmpty = true); 

Einen String – oder Array – am Trennzeichen splitten, leere Elemente entfernen Funktioniert mit Strings und Arrays.

\nn\t3::Arrays('1,,2,3')->trimExplode();           // [1,2,3]
\nn\t3::Arrays('1,,2,3')->trimExplode( false );        // [1,'',2,3]
\nn\t3::Arrays('1|2|3')->trimExplode('|');           // [1,2,3]
\nn\t3::Arrays('1|2||3')->trimExplode('|', false);   // [1,2,'',3]
\nn\t3::Arrays('1|2,3')->trimExplode(['|', ',']);  // [1,2,3]
\nn\t3::Arrays(['1','','2','3'])->trimExplode(); // [1,2,3]
Copied!

| @return array

| ➜ Go to source code of Arrays::trimExplode()

Methods 

Arrays::first() 

\nn\t3::Arrays()->first(); 

Gibt das erste Element des Arrays zurück, ohne array_shift()

\nn\t3::Arrays( $objArr )->first();
Copied!

| @return array

Source Code 

public function first ()
{
	$arr = (array) $this;
	if (!$arr) return false;
	foreach ($arr as $k=>$v) return $v;
}
Copied!

Arrays::intExplode() 

\nn\t3::Arrays()->intExplode($delimiter = ','); 

Einen String – oder Array – am Trennzeichen splitten, nicht numerische und leere Elemente entfernen

\nn\t3::Arrays('1,a,b,2,3')->intExplode();     // [1,2,3]
\nn\t3::Arrays(['1','a','2','3'])->intExplode(); // [1,2,3]
Copied!

| @return array

Source Code 

public function intExplode( $delimiter = ',' ) {
	$finals = [];
	if ($arr = $this->trimExplode($delimiter)) {
		foreach ($arr as $k=>$v) {
			if (is_numeric($v)) $finals[] = $v;
		}
	}
	return $finals;
}
Copied!

Arrays::key() 

\nn\t3::Arrays()->key($key = 'uid', $value = false); 

Als Key des Arrays ein Feld im Array verwenden, z.B. um eine Liste zu bekommen, deren Key immer die UID des assoziativen Arrays ist:

Beispiel:

$arr = [['uid'=>'1', 'title'=>'Titel A'], ['uid'=>'2', 'title'=>'Titel B']];
\nn\t3::Arrays($arr)->key('uid');          // ['1'=>['uid'=>'1', 'title'=>'Titel A'], '2'=>['uid'=>'2', 'title'=>'Titel B']]
\nn\t3::Arrays($arr)->key('uid', 'title');   // ['1'=>'Titel A', '2'=>'Titel B']
Copied!

| @return array

Source Code 

public function key( $key = 'uid', $value = false ) {
	$arr = (array) $this;
	$values = $value === false ? array_values($arr) : array_column( $arr, $value );
	$combinedArray = array_combine( array_column($arr, $key), $values );
	$this->exchangeArray($combinedArray);
	return $this;
}
Copied!

Arrays::merge() 

\nn\t3::Arrays()->merge(); 

Ein assoziatives Array rekursiv mit einem anderen Array mergen.

$addKeys => wenn false werden nur Keys überschrieben, die auch in $arr1 existieren
$includeEmptyValues => wenn true werden auch leere Values in $arr1 übernommen
$enableUnsetFeature => wenn true, kann __UNSET als Wert in $arr2 verwendet werden, um eine Wert in $arr1 zu löschen
$mergedArray = \nn\t3::Arrays( $arr1 )->merge( $arr2, $addKeys, $includeEmptyValues, $enableUnsetFeature );
$mergedArray = \nn\t3::Arrays( $arr1 )->merge( $arr2 );
$mergedArray = \nn\t3::Arrays()->merge( $arr1, $arr2 );
Copied!

| @return array

Source Code 

public function merge() {
	$defaultArgs = [
		'arr1' 		=> [],
		'arr2' 		=> [],
		'addKeys' 	=> true,
		'includeEmptyValues' => false,
		'enableUnsetFeature' => true,
	];
	$args = func_get_args();
	if ($this->initialArgument !== null && !is_array($args[1] ?? '')) {
		array_unshift($args, $this->initialArgument );
	}
	foreach ($defaultArgs as $k=>$v) {
		$val = array_shift( $args );
		if ($val == null) $val = $v;
		${$k} = $val;
	}
	ArrayUtility::mergeRecursiveWithOverrule($arr1, $arr2, $addKeys, $includeEmptyValues, $enableUnsetFeature );
	return $arr1;
}
Copied!

Arrays::pluck() 

\nn\t3::Arrays()->pluck($keys = NULL, $isSingleObject = false); 

Assoziatives Array auf bestimmte Elemente reduzieren / destillieren:

\nn\t3::Arrays( $objArr )->key('uid')->pluck('title');                    // ['1'=>'Titel A', '2'=>'Titel B']
\nn\t3::Arrays( $objArr )->key('uid')->pluck(['title', 'bodytext']);    // ['1'=>['title'=>'Titel A', 'bodytext'=>'Inhalt'], '2'=>...]
\nn\t3::Arrays( ['uid'=>1, 'pid'=>2] )->pluck(['uid'], true);            // ['uid'=>1]
Copied!

| @return array

Source Code 

public function pluck( $keys = null, $isSingleObject = false ) {
	$arr = (array) $this;
	$pluckedArray = [];
	if ($getSingleKey = is_string($keys)) {
		$keys = [$keys];
	}
	if ($isSingleObject) {
		$arr = [$arr];
	}
	foreach ($keys as $key) {
		foreach ($arr as $n=>$v) {
			if ($getSingleKey) {
				$pluckedArray[$n] = $v[$key] ?? '';
			} else {
				if (!isset($pluckedArray[$n])) $pluckedArray[$n] = [];
				$pluckedArray[$n][$key] = $v[$key] ?? '';
			}
		}
	}
	if ($isSingleObject) {
		$pluckedArray = array_pop($pluckedArray);
	}
	$this->exchangeArray($pluckedArray);
	return $this;
}
Copied!

Arrays::removeEmpty() 

\nn\t3::Arrays()->removeEmpty(); 

Leere Werte aus einem Array entfernen.

$clean = \nn\t3::Arrays( $arr1 )->removeEmpty();
Copied!

| @return array

Source Code 

public function removeEmpty() {
	return $this->merge( [], $this->toArray() );
}
Copied!

Arrays::toArray() 

\nn\t3::Arrays()->toArray(); 

Gibt dieses Array-Object als "normales" Array zurück.

\nn\t3::Arrays( $objArr )->key('uid')->toArray();
Copied!

| @return array

Source Code 

public function toArray ()
{
	return (array) $this;
}
Copied!

Arrays::trimExplode() 

\nn\t3::Arrays()->trimExplode($delimiter = ',', $removeEmpty = true); 

Einen String – oder Array – am Trennzeichen splitten, leere Elemente entfernen Funktioniert mit Strings und Arrays.

\nn\t3::Arrays('1,,2,3')->trimExplode();           // [1,2,3]
\nn\t3::Arrays('1,,2,3')->trimExplode( false );        // [1,'',2,3]
\nn\t3::Arrays('1|2|3')->trimExplode('|');           // [1,2,3]
\nn\t3::Arrays('1|2||3')->trimExplode('|', false);   // [1,2,'',3]
\nn\t3::Arrays('1|2,3')->trimExplode(['|', ',']);  // [1,2,3]
\nn\t3::Arrays(['1','','2','3'])->trimExplode(); // [1,2,3]
Copied!

| @return array

Source Code 

public function trimExplode( $delimiter = ',', $removeEmpty = true ) {
	$arr = $this->initialArgument !== null ? $this->initialArgument : (array) $this;
	if ($delimiter === false || $delimiter === true) {
		$delimiter = ',';
		$removeEmpty = $delimiter;
	}
	$firstDelimiter = is_array($delimiter) ? $delimiter[0] : $delimiter;
	if (is_array($arr)) $arr = join($firstDelimiter, $arr);
	if (is_array($delimiter)) {
		foreach ($delimiter as $d) {
			$arr = str_replace( $d, $firstDelimiter, $arr);
		}
		$delimiter = $firstDelimiter;
	}
	$arr = GeneralUtility::trimExplode( $delimiter, $arr, $removeEmpty );
	return $arr;
}
Copied!

BackendUser 

\nn\t3::BackendUser() 

Methoden, um im Frontend zu prüfen, ob ein User im Typo3-Backend eingeloggt ist und z.B. Admin-Rechte besitzt. Methoden, um einen Backend-User zu starten, falls er nicht existiert (z.B. während eines Scheduler-Jobs).

Overview of Methods 

\nn\t3::BackendUser()->get(); 

Holt den aktuellen Backend-User. Entspricht $GLOBALS['BE_USER'] in früheren Typo3-Versionen.

\nn\t3::BackendUser()->get();
Copied!

| @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication

| ➜ Go to source code of BackendUser::get()

\nn\t3::BackendUser()->getCookieName(); 

Cookie-Name des Backend-User-Cookies holen. Üblicherweise be_typo_user, außer es wurde in der LocalConfiguration geändert.

\nn\t3::BackendUser()->getCookieName();
Copied!

return string

| ➜ Go to source code of BackendUser::getCookieName()

\nn\t3::BackendUser()->getSettings($moduleName = 'nnhelpers', $path = NULL); 

Holt userspezifische Einstellungen für den aktuell eingeloggten Backend-User. Siehe \nn\t3::BackendUser()->updateSettings() zum Speichern der Daten.

\nn\t3::BackendUser()->getSettings('myext');                   // => ['wants'=>['drink'=>'coffee']]
\nn\t3::BackendUser()->getSettings('myext', 'wants');        // => ['drink'=>'coffee']
\nn\t3::BackendUser()->getSettings('myext', 'wants.drink');  // => 'coffee'
Copied!

| @return mixed

| ➜ Go to source code of BackendUser::getSettings()

\nn\t3::BackendUser()->isAdmin(); 

Prüft, ob der BE-User ein Admin ist. Früher: $GLOBALS['TSFE']->beUserLogin

\nn\t3::BackendUser()->isAdmin();
Copied!

| @return bool

| ➜ Go to source code of BackendUser::isAdmin()

\nn\t3::BackendUser()->isLoggedIn($request = NULL); 

Prüft, ob ein BE-User eingeloggt ist. Beispiel: Im Frontend bestimmte Inhalte nur zeigen, wenn der User im Backend eingeloggt ist. Früher: $GLOBALS['TSFE']->beUserLogin

// Prüfen nach vollständiger Initialisierung des Front/Backends
\nn\t3::BackendUser()->isLoggedIn();

// Prüfen anhand des JWT, z.B. in einem eID-script vor Authentifizierung
\nn\t3::BackendUser()->isLoggedIn( $request );
Copied!
@param ServerRequest $request
@return bool

| ➜ Go to source code of BackendUser::isLoggedIn()

\nn\t3::BackendUser()->start(); 

Starte (faken) Backend-User. Löst das Problem, das z.B. aus dem Scheduler bestimmte Funktionen wie log() nicht möglich sind, wenn kein aktiver BE-User existiert.

\nn\t3::BackendUser()->start();
Copied!

| @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication

| ➜ Go to source code of BackendUser::start()

\nn\t3::BackendUser()->updateSettings($moduleName = 'nnhelpers', $settings = []); 

Speichert userspezifische Einstellungen für den aktuell eingeloggten Backend-User. Diese Einstellungen sind auch nach Logout/Login wieder für den User verfügbar. Siehe \nn\t3::BackendUser()->getSettings('myext') zum Auslesen der Daten.

\nn\t3::BackendUser()->updateSettings('myext', ['wants'=>['drink'=>'coffee']]);
Copied!

| @return array

| ➜ Go to source code of BackendUser::updateSettings()

Methods 

BackendUser::get() 

\nn\t3::BackendUser()->get(); 

Holt den aktuellen Backend-User. Entspricht $GLOBALS['BE_USER'] in früheren Typo3-Versionen.

\nn\t3::BackendUser()->get();
Copied!

| @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication

Source Code 

public function get()
{
	return $GLOBALS['BE_USER'] ?? $this->start();
}
Copied!

BackendUser::getCookieName() 

\nn\t3::BackendUser()->getCookieName(); 

Cookie-Name des Backend-User-Cookies holen. Üblicherweise be_typo_user, außer es wurde in der LocalConfiguration geändert.

\nn\t3::BackendUser()->getCookieName();
Copied!

return string

Source Code 

public function getCookieName()
{
	if ($cookieName = $GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName'] ?? 'be_typo_user') {
		return $cookieName;
	}
	return \nn\t3::Environment()->getLocalConf('BE.cookieName');
}
Copied!

BackendUser::getSettings() 

\nn\t3::BackendUser()->getSettings($moduleName = 'nnhelpers', $path = NULL); 

Holt userspezifische Einstellungen für den aktuell eingeloggten Backend-User. Siehe \nn\t3::BackendUser()->updateSettings() zum Speichern der Daten.

\nn\t3::BackendUser()->getSettings('myext');                   // => ['wants'=>['drink'=>'coffee']]
\nn\t3::BackendUser()->getSettings('myext', 'wants');        // => ['drink'=>'coffee']
\nn\t3::BackendUser()->getSettings('myext', 'wants.drink');  // => 'coffee'
Copied!

| @return mixed

Source Code 

public function getSettings( $moduleName = 'nnhelpers', $path = null )
{
	$data = $this->get()->uc[$moduleName] ?? [];
	if (!$path) return $data;
	return \nn\t3::Settings()->getFromPath( $path, $data );
}
Copied!

BackendUser::isAdmin() 

\nn\t3::BackendUser()->isAdmin(); 

Prüft, ob der BE-User ein Admin ist. Früher: $GLOBALS['TSFE']->beUserLogin

\nn\t3::BackendUser()->isAdmin();
Copied!

| @return bool

Source Code 

public function isAdmin()
{
	$context = GeneralUtility::makeInstance(Context::class);
	return $context->getPropertyFromAspect('backend.user', 'isAdmin');
}
Copied!

BackendUser::isLoggedIn() 

\nn\t3::BackendUser()->isLoggedIn($request = NULL); 

Prüft, ob ein BE-User eingeloggt ist. Beispiel: Im Frontend bestimmte Inhalte nur zeigen, wenn der User im Backend eingeloggt ist. Früher: $GLOBALS['TSFE']->beUserLogin

// Prüfen nach vollständiger Initialisierung des Front/Backends
\nn\t3::BackendUser()->isLoggedIn();

// Prüfen anhand des JWT, z.B. in einem eID-script vor Authentifizierung
\nn\t3::BackendUser()->isLoggedIn( $request );
Copied!
@param ServerRequest $request
@return bool

Source Code 

public function isLoggedIn( $request = null )
{
	if ($request) {
		$cookieName = $this->getCookieName();
		$jwt = $request->getCookieParams()[$cookieName] ?? false;
		$identifier = false;
		if ($jwt) {
			try {
				$params = $request->getAttribute('normalizedParams') ?? NormalizedParams::createFromRequest($request);
				$cookieScope = $this->getCookieScope( $params );
				$identifier = \TYPO3\CMS\Core\Session\UserSession::resolveIdentifierFromJwt($jwt, $cookieScope);
			} catch( \Exception $e ) {}
		}
		if ($identifier) return true;
	}
	$context = GeneralUtility::makeInstance(Context::class);
	return $context->getPropertyFromAspect('backend.user', 'isLoggedIn');
}
Copied!

BackendUser::start() 

\nn\t3::BackendUser()->start(); 

Starte (faken) Backend-User. Löst das Problem, das z.B. aus dem Scheduler bestimmte Funktionen wie log() nicht möglich sind, wenn kein aktiver BE-User existiert.

\nn\t3::BackendUser()->start();
Copied!

| @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication

Source Code 

public function start()
{
	if (!($GLOBALS['BE_USER'] ?? null)) {
		$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
		if ($request) {
			// TYPO3 v13: Use BackendUserAuthentication directly
			$backendUser = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
			$backendUser->start($request);
			$GLOBALS['BE_USER'] = $backendUser;
		}
	}
	return $GLOBALS['BE_USER'] ?? null;
}
Copied!

BackendUser::updateSettings() 

\nn\t3::BackendUser()->updateSettings($moduleName = 'nnhelpers', $settings = []); 

Speichert userspezifische Einstellungen für den aktuell eingeloggten Backend-User. Diese Einstellungen sind auch nach Logout/Login wieder für den User verfügbar. Siehe \nn\t3::BackendUser()->getSettings('myext') zum Auslesen der Daten.

\nn\t3::BackendUser()->updateSettings('myext', ['wants'=>['drink'=>'coffee']]);
Copied!

| @return array

Source Code 

public function updateSettings( $moduleName = 'nnhelpers', $settings = [] )
{
	if ($beUser = $this->get()) {
		if (!isset($beUser->uc[$moduleName])) {
			$beUser->uc[$moduleName] = [];
		}
		foreach ($settings as $k=>$v) {
			$beUser->uc[$moduleName][$k] = $v;
		}
		$beUser->writeUC();
		return $beUser->uc[$moduleName];
	}
	return [];
}
Copied!

Cache 

\nn\t3::Cache() 

Methoden, zum Lesen und Schreiben in den Typo3 Cache. Nutzt das Caching-Framework von Typo3, siehe EXT:nnhelpers/ext_localconf.php für Details

Overview of Methods 

\nn\t3::Cache()->clear($identifier = NULL); 

Löscht Caches. Wird ein identifier angegeben, dann werden nur die Caches des spezifischen identifiers gelöscht – sonst ALLE Caches aller Extensions und Seiten.

RAM-Caches CachingFramework-Caches, die per \nn\t3::Cache()->set() gesetzt wurde Datei-Caches, die per \nn\t3::Cache()->write() gesetzt wurde

// ALLE Caches löschen – auch die Caches anderer Extensions, der Seiten etc.
\nn\t3::Cache()->clear();

// Nur die Caches mit einem bestimmten Identifier löschen
\nn\t3::Cache()->clear('nnhelpers');
Copied!
@param string $identifier
@return void

| ➜ Go to source code of Cache::clear()

\nn\t3::Cache()->clearPageCache($pid = NULL); 

Löscht den Seiten-Cache. Alias zu \nn\t3::Page()->clearCache()

\nn\t3::Cache()->clearPageCache( 17 );       // Seiten-Cache für pid=17 löschen
\nn\t3::Cache()->clearPageCache();           // Cache ALLER Seiten löschen
Copied!
@param mixed $pid pid der Seite, deren Cache gelöscht werden soll oder leer lassen für alle Seite
@return void

| ➜ Go to source code of Cache::clearPageCache()

\nn\t3::Cache()->get($identifier = '', $useRamCache = false); 

Lädt Inhalt des Typo3-Caches anhand eines Identifiers. Der Identifier ist ein beliebiger String oder ein Array, der den Cache eindeutif Identifiziert.

\nn\t3::Cache()->get('myid');
\nn\t3::Cache()->get(['pid'=>1, 'uid'=>'7']);
\nn\t3::Cache()->get(['func'=>__METHOD__, 'uid'=>'17']);
\nn\t3::Cache()->get([__METHOD__=>$this->request->getArguments()]);
Copied!
@param mixed $identifier String oder Array zum Identifizieren des Cache
@param mixed $useRamCache temporärer Cache in $GLOBALS statt Caching-Framework

| @return mixed

| ➜ Go to source code of Cache::get()

\nn\t3::Cache()->getIdentifier($identifier = NULL); 

Wandelt übergebenen Cache-Identifier in brauchbaren String um. Kann auch ein Array als Identifier verarbeiten.

@param mixed $indentifier
@return string

| ➜ Go to source code of Cache::getIdentifier()

\nn\t3::Cache()->read($identifier); 

Statischen Datei-Cache lesen.

Liest die PHP-Datei, die per \nn\t3::Cache()->write() geschrieben wurde.

$cache = \nn\t3::Cache()->read( $identifier );
Copied!

Die PHP-Datei ist ein ausführbares PHP-Script mit dem return-Befehl. Sie speichert den Cache-Inhalt in einem Array.

<?php
    return ['_'=>...];
Copied!

| @return string|array

| ➜ Go to source code of Cache::read()

\nn\t3::Cache()->set($identifier = '', $data = NULL, $useRamCache = false); 

Schreibt einen Eintrag in den Typo3-Cache. Der Identifier ist ein beliebiger String oder ein Array, der den Cache eindeutif Identifiziert.

// Klassische Anwendung im Controller: Cache holen und setzen
if ($cache = \nn\t3::Cache()->get('myid')) return $cache;
...
$cache = $this->view->render();
return \nn\t3::Cache()->set('myid', $cache);
Copied!
// RAM-Cache verwenden? TRUE als dritter Parameter setzen
\nn\t3::Cache()->set('myid', $dataToCache, true);

// Dauer des Cache auf 60 Minuten festlegen
\nn\t3::Cache()->set('myid', $dataToCache, 3600);

// Als key kann auch ein Array angegeben werden
\nn\t3::Cache()->set(['pid'=>1, 'uid'=>'7'], $html);
Copied!
@param mixed $indentifier String oder Array zum Identifizieren des Cache
@param mixed $data Daten, die in den Cache geschrieben werden sollen. (String oder Array)
@param mixed $useRamCache true: temporärer Cache in $GLOBALS statt Caching-Framework.
integer: Wie viele Sekunden cachen?

| @return mixed

| ➜ Go to source code of Cache::set()

\nn\t3::Cache()->write($identifier, $cache); 

Statischen Datei-Cache schreiben.

Schreibt eine PHP-Datei, die per $cache = require('...') geladen werden kann.

Angelehnt an viele Core-Funktionen und Extensions (z.B. mask), die statische PHP-Dateien ins Filesystem legen, um performancelastige Prozesse wie Klassenpfade, Annotation-Parsing etc. besser zu cachen. Nutzt bewußt nicht die Core-Funktionen, um jeglichen Overhead zu vermeiden und größtmögliche Kompatibilität bei Core-Updates zu gewährleisten.

$cache = ['a'=>1, 'b'=>2];
$identifier = 'myid';

\nn\t3::Cache()->write( $identifier, $cache );
$read = \nn\t3::Cache()->read( $identifier );
Copied!

Das Beispiel oben generiert eine PHP-Datei mit diesem Inhalt:

<?php
return ['_' => ['a'=>1, 'b'=>2]];
Copied!

| @return string|array

| ➜ Go to source code of Cache::write()

Methods 

Cache::clear() 

\nn\t3::Cache()->clear($identifier = NULL); 

Löscht Caches. Wird ein identifier angegeben, dann werden nur die Caches des spezifischen identifiers gelöscht – sonst ALLE Caches aller Extensions und Seiten.

RAM-Caches CachingFramework-Caches, die per \nn\t3::Cache()->set() gesetzt wurde Datei-Caches, die per \nn\t3::Cache()->write() gesetzt wurde

// ALLE Caches löschen – auch die Caches anderer Extensions, der Seiten etc.
\nn\t3::Cache()->clear();

// Nur die Caches mit einem bestimmten Identifier löschen
\nn\t3::Cache()->clear('nnhelpers');
Copied!
@param string $identifier
@return void

Source Code 

public function clear( $identifier = null )
{
	if (!$identifier) {
		// ALLE TYPO3 Caches löschen, der über das CachingFramework registriert wurde
		$this->cacheManager->flushCaches();
	} else {
		// Spezifischen Cache löschen
		if ($cacheUtility = $this->cacheManager->getCache( $identifier )) {
			$cacheUtility->flush();
		}
	}
	if (!$identifier || $identifier == 'nnhelpers') {
		// RAM Cache löschen
		$GLOBALS['nnhelpers_cache'] = [];
		// File-Cache löschen
		$cacheDir = \nn\t3::Environment()->getVarPath() . "/cache/code/nnhelpers";
		if (is_dir($cacheDir)) {
			$iterator = new \DirectoryIterator($cacheDir);
			foreach ($iterator as $file) {
				if ($file->isFile() && $file->getExtension() === 'php') {
					unlink($file->getPathname());
				}
			}
		}
	}
}
Copied!

Cache::clearPageCache() 

\nn\t3::Cache()->clearPageCache($pid = NULL); 

Löscht den Seiten-Cache. Alias zu \nn\t3::Page()->clearCache()

\nn\t3::Cache()->clearPageCache( 17 );       // Seiten-Cache für pid=17 löschen
\nn\t3::Cache()->clearPageCache();           // Cache ALLER Seiten löschen
Copied!
@param mixed $pid pid der Seite, deren Cache gelöscht werden soll oder leer lassen für alle Seite
@return void

Source Code 

public function clearPageCache( $pid = null )
{
	return \nn\t3::Page()->clearCache( $pid );
}
Copied!

Cache::get() 

\nn\t3::Cache()->get($identifier = '', $useRamCache = false); 

Lädt Inhalt des Typo3-Caches anhand eines Identifiers. Der Identifier ist ein beliebiger String oder ein Array, der den Cache eindeutif Identifiziert.

\nn\t3::Cache()->get('myid');
\nn\t3::Cache()->get(['pid'=>1, 'uid'=>'7']);
\nn\t3::Cache()->get(['func'=>__METHOD__, 'uid'=>'17']);
\nn\t3::Cache()->get([__METHOD__=>$this->request->getArguments()]);
Copied!
@param mixed $identifier String oder Array zum Identifizieren des Cache
@param mixed $useRamCache temporärer Cache in $GLOBALS statt Caching-Framework

| @return mixed

Source Code 

public function get( $identifier = '', $useRamCache = false )
{
	$identifier = self::getIdentifier( $identifier );
	// Ram-Cache verwenden? Einfache globale.
	if ($useRamCache && ($cache = $GLOBALS['nnhelpers_cache'][$identifier] ?? false)) {
		return $cache;
	}
	$cacheUtility = $this->getCacheInstance();
	if (!$cacheUtility) {
		return false;
	}
	if ($data = $cacheUtility->get($identifier)) {
		$data = json_decode( $cacheUtility->get($identifier), true );
		if ($data['content'] && $data['expires'] < time()) return false;
		return $data['content'] ?: false;
	}
	return false;
}
Copied!

Cache::getIdentifier() 

\nn\t3::Cache()->getIdentifier($identifier = NULL); 

Wandelt übergebenen Cache-Identifier in brauchbaren String um. Kann auch ein Array als Identifier verarbeiten.

@param mixed $indentifier
@return string

Source Code 

public static function getIdentifier( $identifier = null )
{
	if (is_array($identifier)) {
		$identifier = json_encode($identifier);
	}
	return md5($identifier);
}
Copied!

Cache::read() 

\nn\t3::Cache()->read($identifier); 

Statischen Datei-Cache lesen.

Liest die PHP-Datei, die per \nn\t3::Cache()->write() geschrieben wurde.

$cache = \nn\t3::Cache()->read( $identifier );
Copied!

Die PHP-Datei ist ein ausführbares PHP-Script mit dem return-Befehl. Sie speichert den Cache-Inhalt in einem Array.

<?php
    return ['_'=>...];
Copied!

| @return string|array

Source Code 

public function read( $identifier )
{
	if ($cache = $this->get( $identifier, true )) return $cache;
	$identifier = self::getIdentifier( $identifier );
	$path = \nn\t3::Environment()->getVarPath() . "/cache/code/nnhelpers/{$identifier}.php";
	if (!file_exists($path)) {
		return null;
	}
	$cache = require( $path );
	return $cache['_'];
}
Copied!

Cache::set() 

\nn\t3::Cache()->set($identifier = '', $data = NULL, $useRamCache = false); 

Schreibt einen Eintrag in den Typo3-Cache. Der Identifier ist ein beliebiger String oder ein Array, der den Cache eindeutif Identifiziert.

// Klassische Anwendung im Controller: Cache holen und setzen
if ($cache = \nn\t3::Cache()->get('myid')) return $cache;
...
$cache = $this->view->render();
return \nn\t3::Cache()->set('myid', $cache);
Copied!
// RAM-Cache verwenden? TRUE als dritter Parameter setzen
\nn\t3::Cache()->set('myid', $dataToCache, true);

// Dauer des Cache auf 60 Minuten festlegen
\nn\t3::Cache()->set('myid', $dataToCache, 3600);

// Als key kann auch ein Array angegeben werden
\nn\t3::Cache()->set(['pid'=>1, 'uid'=>'7'], $html);
Copied!
@param mixed $indentifier String oder Array zum Identifizieren des Cache
@param mixed $data Daten, die in den Cache geschrieben werden sollen. (String oder Array)
@param mixed $useRamCache true: temporärer Cache in $GLOBALS statt Caching-Framework.
integer: Wie viele Sekunden cachen?

| @return mixed

Source Code 

public function set( $identifier = '', $data = null, $useRamCache = false )
{
	$identifier = self::getIdentifier( $identifier );
	$lifetime = 86400;
	if ($useRamCache === true) {
		if (!isset($GLOBALS['nnhelpers_cache'])) {
			$GLOBALS['nnhelpers_cache'] = [];
		}
		return $GLOBALS['nnhelpers_cache'][$identifier] = $data;
	} else if ( $useRamCache !== false ) {
		$lifetime = intval($useRamCache);
	}
	$expires = time() + $lifetime;
	$cacheUtility = $this->getCacheInstance();
	if (!$cacheUtility) {
		return $data;
	}
	$serializedData = json_encode(['content'=>$data, 'expires'=>$expires]);
	$cacheUtility->set($identifier, $serializedData, [], $lifetime);
	return $data;
}
Copied!

Cache::write() 

\nn\t3::Cache()->write($identifier, $cache); 

Statischen Datei-Cache schreiben.

Schreibt eine PHP-Datei, die per $cache = require('...') geladen werden kann.

Angelehnt an viele Core-Funktionen und Extensions (z.B. mask), die statische PHP-Dateien ins Filesystem legen, um performancelastige Prozesse wie Klassenpfade, Annotation-Parsing etc. besser zu cachen. Nutzt bewußt nicht die Core-Funktionen, um jeglichen Overhead zu vermeiden und größtmögliche Kompatibilität bei Core-Updates zu gewährleisten.

$cache = ['a'=>1, 'b'=>2];
$identifier = 'myid';

\nn\t3::Cache()->write( $identifier, $cache );
$read = \nn\t3::Cache()->read( $identifier );
Copied!

Das Beispiel oben generiert eine PHP-Datei mit diesem Inhalt:

<?php
return ['_' => ['a'=>1, 'b'=>2]];
Copied!

| @return string|array

Source Code 

public function write( $identifier, $cache )
{
	$this->set( $identifier, $cache, true );
	$identifier = self::getIdentifier( $identifier );
	$phpCode = '<?php return ' . var_export(['_' => $cache], true) . ';';
	$path = \nn\t3::Environment()->getVarPath() . "cache/code/nnhelpers/{$identifier}.php";
	\TYPO3\CMS\Core\Utility\GeneralUtility::writeFileToTypo3tempDir( $path, $phpCode );
	return $cache;
}
Copied!

Content 

\nn\t3::Content() 

Inhaltselemente und Inhalte einer Backend-Spalten (colPos) lesen und rendern

Overview of Methods 

\nn\t3::Content()->addRelations($data = []); 

Lädt Relationen (media, assets, ...) zu einem tt_content-Data-Array. Falls EXT:mask installiert ist, wird die entsprechende Methode aus mask genutzt.

\nn\t3::Content()->addRelations( $data );
Copied!

| @return array

| ➜ Go to source code of Content::addRelations()

\nn\t3::Content()->column($colPos, $pageUid = NULL, $slide = NULL); 

Lädt den Content für eine bestimmte Spalte (colPos) und Seite. Wird keine pageUid angegeben, verwendet er die aktuelle Seite. Mit slide werden die Inhaltselement der übergeordnete Seite geholt, falls auf der angegeben Seiten kein Inhaltselement in der Spalte existiert.

Inhalt der colPos = 110 von der aktuellen Seite holen:

\nn\t3::Content()->column( 110 );
Copied!

Inhalt der colPos = 110 von der aktuellen Seite holen. Falls auf der aktuellen Seite kein Inhalt in der Spalte ist, den Inhalt aus der übergeordneten Seite verwenden:

\nn\t3::Content()->column( 110, true );
Copied!

Inhalt der colPos = 110 von der Seite mit id 99 holen:

\nn\t3::Content()->column( 110, 99 );
Copied!

Inhalt der colPos = 110 von der Seite mit der id 99 holen. Falls auf Seite 99 kein Inhalt in der Spalte ist, den Inhalt aus der übergeordneten Seite der Seite 99 verwenden:

\nn\t3::Content()->column( 110, 99, true );
Copied!

Auch als ViewHelper vorhanden:

{nnt3:content.column(colPos:110)}
{nnt3:content.column(colPos:110, slide:1)}
{nnt3:content.column(colPos:110, pid:99)}
{nnt3:content.column(colPos:110, pid:99, slide:1)}
Copied!

| @return string

| ➜ Go to source code of Content::column()

\nn\t3::Content()->columnData($colPos, $addRelations = false, $pageUid = NULL); 

Lädt die "rohen" tt_content Daten einer bestimmten Spalte (colPos).

\nn\t3::Content()->columnData( 110 );
\nn\t3::Content()->columnData( 110, true );
\nn\t3::Content()->columnData( 110, true, 99 );
Copied!

Auch als ViewHelper vorhanden. | relations steht im ViewHelper als default auf TRUE

{nnt3:content.columnData(colPos:110)}
{nnt3:content.columnData(colPos:110, pid:99, relations:0)}
Copied!

| @return array

| ➜ Go to source code of Content::columnData()

\nn\t3::Content()->get($ttContentUid = NULL, $getRelations = false, $localize = true, $field = 'uid'); 

Lädt die Daten eines tt_content-Element als einfaches Array:

\nn\t3::Content()->get( 1201 );
Copied!

Laden von Relationen (media, assets, ...)

\nn\t3::Content()->get( 1201, true );
Copied!

Übersetzungen / Localization:

Element NICHT automatisch übersetzen, falls eine andere Sprache eingestellt wurde

\nn\t3::Content()->get( 1201, false, false );
Copied!

Element in einer ANDEREN Sprache holen, als im Frontend eingestellt wurde. Berücksichtigt die Fallback-Chain der Sprache, die in der Site-Config eingestellt wurde

\nn\t3::Content()->get( 1201, false, 2 );
Copied!

Element mit eigener Fallback-Chain holen. Ignoriert dabei vollständig die Chain, die in der Site-Config definiert wurde.

\nn\t3::Content()->get( 1201, false, [2,3,0] );
Copied!

Eigenes Feld zur Erkennung verwenden

\nn\t3::Content()->get( 'footer', true, true, 'content_uuid' );
Copied!
@param int|string $ttContentUid Content-Uid in der Tabelle tt_content (oder string mit einem key)
@param bool $getRelations Auch Relationen / FAL holen?
@param bool $localize Übersetzen des Eintrages?
@param string $localize Übersetzen des Eintrages?
@param string $field Falls anderes Feld als uid verwendet werden soll
@return array

| ➜ Go to source code of Content::get()

\nn\t3::Content()->getAll($constraints = [], $getRelations = false, $localize = true); 

Mehrere Content-Elemente (aus tt_content) holen.

Die Datensätze werden automatisch lokalisiert – außer $localize wird auf false gesetzt. Siehe \nn\t3::Content()->get() für weitere $localize Optionen.

Anhand einer Liste von UIDs:

\nn\t3::Content()->getAll( 1 );
\nn\t3::Content()->getAll( [1, 2, 7] );
Copied!

Anhand von Filter-Kriterien:

\nn\t3::Content()->getAll( ['pid'=>1] );
\nn\t3::Content()->getAll( ['pid'=>1, 'colPos'=>1] );
\nn\t3::Content()->getAll( ['pid'=>1, 'CType'=>'mask_section_cards', 'colPos'=>1] );
Copied!
@param mixed $ttContentUid Content-Uids oder Constraints für Abfrage der Daten
@param bool $getRelations Auch Relationen / FAL holen?
@param bool $localize Übersetzen des Eintrages?
@return array

| ➜ Go to source code of Content::getAll()

\nn\t3::Content()->localize($table = 'tt_content', $data = [], $localize = true); 

Daten lokalisieren / übersetzen.

Beispiele:

Daten übersetzen, dabei die aktuelle Sprache des Frontends verwenden.

\nn\t3::Content()->localize( 'tt_content', $data );
Copied!

Daten in einer ANDEREN Sprache holen, als im Frontend eingestellt wurde. Berücksichtigt die Fallback-Chain der Sprache, die in der Site-Config eingestellt wurde

\nn\t3::Content()->localize( 'tt_content', $data, 2 );
Copied!

Daten mit eigener Fallback-Chain holen. Ignoriert dabei vollständig die Chain, die in der Site-Config definiert wurde.

\nn\t3::Content()->localize( 'tt_content', $data, [3, 2, 0] );
Copied!
@param string $table Datenbank-Tabelle
@param array $data Array mit den Daten der Standard-Sprache (languageUid = 0)
@param mixed $localize Angabe, wie übersetzt werden soll. Boolean, uid oder Array mit uids
@return array

| ➜ Go to source code of Content::localize()

\nn\t3::Content()->render($ttContentUid = NULL, $data = [], $field = NULL); 

Rendert ein tt_content-Element als HTML

\nn\t3::Content()->render( 1201 );
\nn\t3::Content()->render( 1201, ['key'=>'value'] );
\nn\t3::Content()->render( 'footer', ['key'=>'value'], 'content_uuid' );
Copied!

Auch als ViewHelper vorhanden:

{nnt3:contentElement(uid:123, data:feUser.data)}
{nnt3:contentElement(uid:'footer', field:'content_uuid')}
Copied!

| @return string

| ➜ Go to source code of Content::render()

Methods 

Content::addRelations() 

\nn\t3::Content()->addRelations($data = []); 

Lädt Relationen (media, assets, ...) zu einem tt_content-Data-Array. Falls EXT:mask installiert ist, wird die entsprechende Methode aus mask genutzt.

\nn\t3::Content()->addRelations( $data );
Copied!

| @return array

Source Code 

public function addRelations($data = [])
{
	if (!$data) return [];
	if (\nn\t3::Environment()->extLoaded('mask')) {
		$maskProcessor = GeneralUtility::makeInstance(\MASK\Mask\DataProcessing\MaskProcessor::class);
		$cObjRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
		$request = $GLOBALS['TYPO3_REQUEST'] ?? new \TYPO3\CMS\Core\Http\ServerRequest();
		$cObjRenderer->setRequest($request);
		$dataWithRelations = $maskProcessor->process($cObjRenderer, [], [], ['data' => $data, 'current' => null]);
		$data = $dataWithRelations['data'] ?: [];
	} else {
		$falFields = \nn\t3::Tca()->getFalFields('tt_content');
		$fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class);
		foreach ($falFields as $field) {
			$data[$field] = $fileRepository->findByRelation('tt_content', $field, $data['uid']);
		}
	}
	return $data;
}
Copied!

Content::column() 

\nn\t3::Content()->column($colPos, $pageUid = NULL, $slide = NULL); 

Lädt den Content für eine bestimmte Spalte (colPos) und Seite. Wird keine pageUid angegeben, verwendet er die aktuelle Seite. Mit slide werden die Inhaltselement der übergeordnete Seite geholt, falls auf der angegeben Seiten kein Inhaltselement in der Spalte existiert.

Inhalt der colPos = 110 von der aktuellen Seite holen:

\nn\t3::Content()->column( 110 );
Copied!

Inhalt der colPos = 110 von der aktuellen Seite holen. Falls auf der aktuellen Seite kein Inhalt in der Spalte ist, den Inhalt aus der übergeordneten Seite verwenden:

\nn\t3::Content()->column( 110, true );
Copied!

Inhalt der colPos = 110 von der Seite mit id 99 holen:

\nn\t3::Content()->column( 110, 99 );
Copied!

Inhalt der colPos = 110 von der Seite mit der id 99 holen. Falls auf Seite 99 kein Inhalt in der Spalte ist, den Inhalt aus der übergeordneten Seite der Seite 99 verwenden:

\nn\t3::Content()->column( 110, 99, true );
Copied!

Auch als ViewHelper vorhanden:

{nnt3:content.column(colPos:110)}
{nnt3:content.column(colPos:110, slide:1)}
{nnt3:content.column(colPos:110, pid:99)}
{nnt3:content.column(colPos:110, pid:99, slide:1)}
Copied!

| @return string

Source Code 

public function column($colPos, $pageUid = null, $slide = null)
{
	if ($slide === null && $pageUid === true) {
		$pageUid = null;
		$slide = true;
	}
	if (!$pageUid && !$slide) $pageUid = \nn\t3::Page()->getPid();
	$conf = [
		'table' => 'tt_content',
		'select.' => [
			'orderBy' => 'sorting',
			'where' => 'colPos=' . intval($colPos),
		],
	];
	if ($pageUid) {
		$conf['select.']['pidInList'] = intval($pageUid);
	}
	if ($slide) {
		$conf['slide'] = -1;
	}
	$html = \nn\t3::Tsfe()->cObjGetSingle('CONTENT', $conf);
	return $html;
}
Copied!

Content::columnData() 

\nn\t3::Content()->columnData($colPos, $addRelations = false, $pageUid = NULL); 

Lädt die "rohen" tt_content Daten einer bestimmten Spalte (colPos).

\nn\t3::Content()->columnData( 110 );
\nn\t3::Content()->columnData( 110, true );
\nn\t3::Content()->columnData( 110, true, 99 );
Copied!

Auch als ViewHelper vorhanden. | relations steht im ViewHelper als default auf TRUE

{nnt3:content.columnData(colPos:110)}
{nnt3:content.columnData(colPos:110, pid:99, relations:0)}
Copied!

| @return array

Source Code 

public function columnData($colPos, $addRelations = false, $pageUid = null)
{
	if (!$pageUid) $pageUid = \nn\t3::Page()->getPid();
	$queryBuilder = \nn\t3::Db()->getQueryBuilder('tt_content');
	$data = $queryBuilder
		->select('*')
		->from('tt_content')
		->andWhere($queryBuilder->expr()->eq('colPos', $queryBuilder->createNamedParameter($colPos)))
		->andWhere($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageUid)))
		->orderBy('sorting')
		->executeQuery()
		->fetchAllAssociative();
	if (!$data) return [];
	if ($addRelations) {
		foreach ($data as $n => $row) {
			$data[$n] = $this->addRelations($row);
		}
	}
	return $data;
}
Copied!

Content::get() 

\nn\t3::Content()->get($ttContentUid = NULL, $getRelations = false, $localize = true, $field = 'uid'); 

Lädt die Daten eines tt_content-Element als einfaches Array:

\nn\t3::Content()->get( 1201 );
Copied!

Laden von Relationen (media, assets, ...)

\nn\t3::Content()->get( 1201, true );
Copied!

Übersetzungen / Localization:

Element NICHT automatisch übersetzen, falls eine andere Sprache eingestellt wurde

\nn\t3::Content()->get( 1201, false, false );
Copied!

Element in einer ANDEREN Sprache holen, als im Frontend eingestellt wurde. Berücksichtigt die Fallback-Chain der Sprache, die in der Site-Config eingestellt wurde

\nn\t3::Content()->get( 1201, false, 2 );
Copied!

Element mit eigener Fallback-Chain holen. Ignoriert dabei vollständig die Chain, die in der Site-Config definiert wurde.

\nn\t3::Content()->get( 1201, false, [2,3,0] );
Copied!

Eigenes Feld zur Erkennung verwenden

\nn\t3::Content()->get( 'footer', true, true, 'content_uuid' );
Copied!
@param int|string $ttContentUid Content-Uid in der Tabelle tt_content (oder string mit einem key)
@param bool $getRelations Auch Relationen / FAL holen?
@param bool $localize Übersetzen des Eintrages?
@param string $localize Übersetzen des Eintrages?
@param string $field Falls anderes Feld als uid verwendet werden soll
@return array

Source Code 

public function get($ttContentUid = null, $getRelations = false, $localize = true, $field = 'uid')
{
	if (!$ttContentUid) return [];
	// Datensatz in der Standard-Sprache holen
	$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
	$data = $queryBuilder
		->select('*')
		->from('tt_content')
		->andWhere($queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($ttContentUid)))
		->executeQuery()
		->fetchAssociative();
	if (!$data) return [];
	$data = $this->localize('tt_content', $data, $localize);
	if ($getRelations) {
		$data = $this->addRelations($data);
	}
	return $data;
}
Copied!

Content::getAll() 

\nn\t3::Content()->getAll($constraints = [], $getRelations = false, $localize = true); 

Mehrere Content-Elemente (aus tt_content) holen.

Die Datensätze werden automatisch lokalisiert – außer $localize wird auf false gesetzt. Siehe \nn\t3::Content()->get() für weitere $localize Optionen.

Anhand einer Liste von UIDs:

\nn\t3::Content()->getAll( 1 );
\nn\t3::Content()->getAll( [1, 2, 7] );
Copied!

Anhand von Filter-Kriterien:

\nn\t3::Content()->getAll( ['pid'=>1] );
\nn\t3::Content()->getAll( ['pid'=>1, 'colPos'=>1] );
\nn\t3::Content()->getAll( ['pid'=>1, 'CType'=>'mask_section_cards', 'colPos'=>1] );
Copied!
@param mixed $ttContentUid Content-Uids oder Constraints für Abfrage der Daten
@param bool $getRelations Auch Relationen / FAL holen?
@param bool $localize Übersetzen des Eintrages?
@return array

Source Code 

public function getAll($constraints = [], $getRelations = false, $localize = true)
{
	if (!$constraints) return [];
	// ist es eine uid-Liste, z.B. [1, 2, 3]?
	$isUidList = count(array_filter(array_flip($constraints), function ($v) {
			return !is_numeric($v);
		})) == 0;
	$results = [];
	// ... dann einfach \nn\t3::Content()->get() verwenden
	if ($isUidList) {
		foreach ($constraints as $uid) {
			if ($element = $this->get($uid, $getRelations, $localize)) {
				$results[] = $element;
			}
		}
		return $results;
	}
	// und sonst: eine Query bauen
	// Datensatz in der Standard-Sprache holen
	$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
	$query = $queryBuilder
		->select('*')
		->from('tt_content')
		->addOrderBy('sorting', \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING)
		->andWhere($queryBuilder->expr()->eq('sys_language_uid', 0));
	if (isset($constraints['pid'])) {
		$pid = $constraints['pid'];
		$query->andWhere($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid)));
	}
	if (isset($constraints['colPos'])) {
		$colPos = $constraints['colPos'];
		$query->andWhere($queryBuilder->expr()->eq('colPos', $queryBuilder->createNamedParameter($colPos)));
	}
	if ($cType = $constraints['CType'] ?? false) {
		$query->andWhere($queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter($cType)));
	}
	$data = $query->executeQuery()->fetchAllAssociative();
	if (!$data) return [];
	foreach ($data as $row) {
		if ($row = $this->localize('tt_content', $row, $localize)) {
			if ($getRelations) {
				$data = $this->addRelations($data);
			}
			$results[] = $row;
		}
	}
	return $results;
}
Copied!

Content::localize() 

\nn\t3::Content()->localize($table = 'tt_content', $data = [], $localize = true); 

Daten lokalisieren / übersetzen.

Beispiele:

Daten übersetzen, dabei die aktuelle Sprache des Frontends verwenden.

\nn\t3::Content()->localize( 'tt_content', $data );
Copied!

Daten in einer ANDEREN Sprache holen, als im Frontend eingestellt wurde. Berücksichtigt die Fallback-Chain der Sprache, die in der Site-Config eingestellt wurde

\nn\t3::Content()->localize( 'tt_content', $data, 2 );
Copied!

Daten mit eigener Fallback-Chain holen. Ignoriert dabei vollständig die Chain, die in der Site-Config definiert wurde.

\nn\t3::Content()->localize( 'tt_content', $data, [3, 2, 0] );
Copied!
@param string $table Datenbank-Tabelle
@param array $data Array mit den Daten der Standard-Sprache (languageUid = 0)
@param mixed $localize Angabe, wie übersetzt werden soll. Boolean, uid oder Array mit uids
@return array

Source Code 

public function localize($table = 'tt_content', $data = [], $localize = true)
{
	// Irgendwas ging schief?
	$pageRepository = \nn\t3::injectClass(PageRepository::class);
	if (!$pageRepository) return $data;
	// Aktuelle Sprache aus dem Frontend-Request
	$currentLanguageUid = \nn\t3::Environment()->getLanguage();
	// `false` angegeben - oder Zielsprache ist Standardsprache? Dann nichts tun.
	if ($localize === false || $localize === $currentLanguageUid) {
		return $data;
	}
	// `true` angegeben: Dann ist die Zielsprache == die aktuelle Sprache im FE
	if ($localize === true) {
		$localize = $currentLanguageUid;
		$fallbackChain = \nn\t3::Environment()->getLanguageFallbackChain($localize);
		$languageId = $localize;
	}
	// `uid` der Zielsprache angegeben (z.B. `1`)? Dann Fallback-Chain aus TYPO3-Site-Konfiguration laden
	if (is_numeric($localize)) {
		$languageId = (int)$localize;
		$fallbackChain = \nn\t3::Environment()->getLanguageFallbackChain($localize);
	}
	// `[2,1,0]` als Zielsprachen angegeben? Dann als Fallback-Chain verwenden
	if (is_array($localize)) {
		$languageId = $localize[0] ?? 0;
		$fallbackChain = $localize;
	}
	$overlayType = LanguageAspect::OVERLAYS_ON;
	foreach ($fallbackChain as $langUid) {
		$langAspect = GeneralUtility::makeInstance(LanguageAspect::class, $langUid, $langUid, $overlayType, $fallbackChain);
		if ($overlay = $pageRepository->getLanguageOverlay($table, $data, $langAspect)) {
			return $overlay;
		}
	}
	return $data;
}
Copied!

Content::render() 

\nn\t3::Content()->render($ttContentUid = NULL, $data = [], $field = NULL); 

Rendert ein tt_content-Element als HTML

\nn\t3::Content()->render( 1201 );
\nn\t3::Content()->render( 1201, ['key'=>'value'] );
\nn\t3::Content()->render( 'footer', ['key'=>'value'], 'content_uuid' );
Copied!

Auch als ViewHelper vorhanden:

{nnt3:contentElement(uid:123, data:feUser.data)}
{nnt3:contentElement(uid:'footer', field:'content_uuid')}
Copied!

| @return string

Source Code 

public function render($ttContentUid = null, $data = [], $field = null)
{
	if (!$ttContentUid) return '';
	if ($field && $field !== 'uid') {
		$row = \nn\t3::Db()->findOneByValues('tt_content', [$field => $ttContentUid]);
		if (!$row) return '';
		$ttContentUid = $row['uid'];
	}
	$conf = [
		'tables' => 'tt_content',
		'source' => $ttContentUid,
		'dontCheckPid' => 1
	];
	\nn\t3::Tsfe()->forceAbsoluteUrls(true);
	$html = \nn\t3::Tsfe()->cObjGetSingle('RECORDS', $conf);
	// Wenn data-Array übergeben wurde, Ergebnis erneut über Fluid Standalone-View parsen.
	if ($data) {
		$html = \nn\t3::Template()->renderHtml($html, $data);
	}
	return $html;
}
Copied!

Convert 

\nn\t3::Convert() 

Konvertieren von Arrays zu Models, Models zu JSONs, Arrays zu ObjectStorages, Hex-Farben zu RGB und vieles mehr, was irgendwie mit Konvertieren von Dingen zu tun hat.

Overview of Methods 

\nn\t3::Convert()->toArray($obj = NULL, $depth = 3); 

Konvertiert ein Model in ein Array Alias zu nnt3::Obj()->toArray();

Bei Memory-Problemen wegen Rekursionen: Max-Tiefe angebenen!

\nn\t3::Convert($model)->toArray(2);
\nn\t3::Convert($model)->toArray();      => ['uid'=>1, 'title'=>'Beispiel', ...]
Copied!

| @return array

| ➜ Go to source code of Convert::toArray()

\nn\t3::Convert()->toBytes(); 

Konvertiert eine für Menschen lesbare Angabe von Bytes/Megabytes in einen Byte-Integer. Extrem tolerant, was Leerzeichen, Groß/Klein-Schreibung und Kommas statt Punkten angeht.

\nn\t3::Convert('1M')->toBytes();  // -> 1048576
\nn\t3::Convert('1 MB')->toBytes();    // -> 1048576
\nn\t3::Convert('1kb')->toBytes(); // -> 1024
\nn\t3::Convert('1,5kb')->toBytes();   // -> 1024
\nn\t3::Convert('1.5Gb')->toBytes();   // -> 1610612736
Copied!

Für den umgekehrten Weg (Bytes zu menschenlesbarer Schreibweise wie 1024 -> 1kb) gibt es einen praktischen Fluid ViewHelper im Core:

{fileSize->f:format.bytes()}
Copied!

| @return integer

| ➜ Go to source code of Convert::toBytes()

\nn\t3::Convert()->toFileReference(); 

Konvertiert ein \TYPO3\CMS\Core\Resource\FileReference (oder seine uid) in eine \TYPO3\CMS\Extbase\Domain\Model\FileReference

\nn\t3::Convert( $input )->toFileReference() => \TYPO3\CMS\Extbase\Domain\Model\FileReference
Copied!
@param $input Kann \TYPO3\CMS\Core\Resource\FileReference oder uid davon sein
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Convert::toFileReference()

\nn\t3::Convert()->toIso(); 

Konvertiert (normalisiert) einen String zu ISO-8859-1

\nn\t3::Convert('äöü')->toIso();
Copied!

| @return string

| ➜ Go to source code of Convert::toIso()

\nn\t3::Convert()->toJson($obj = NULL, $depth = 3); 

Konvertiert ein Model in ein JSON

\nn\t3::Convert($model)->toJson()        => ['uid'=>1, 'title'=>'Beispiel', ...]
Copied!

| @return array

| ➜ Go to source code of Convert::toJson()

\nn\t3::Convert()->toLanguage($sysLanguageUid = NULL); 

Konvertiert eine Sprach-ID (z.B. '0', '1') in das zweistellige Sprachkürzel (z.B. 'de', 'en')

// Sprach-ID 0 -> 'de'
\nn\t3::Convert(0)->toLanguage();
Copied!
@param int $sysLanguageUid
@return string

| ➜ Go to source code of Convert::toLanguage()

\nn\t3::Convert()->toLanguageId($languageCode = NULL); 

Konvertiert ein zweistelliges Sprachkürzel (z.B. 'de', 'en') in die Sprach-ID (z.B. '0', '1')

// Sprach-ID 0 -> 'de'
\nn\t3::Convert('de')->toLanguageId();
Copied!
@param int $sysLanguageUid
@return string

| ➜ Go to source code of Convert::toLanguageId()

\nn\t3::Convert()->toModel($className = NULL, $parentModel = NULL); 

Konvertiert ein Array in ein Model.

\nn\t3::Convert($array)->toModel( \Nng\Model\Name::class )       => \Nng\Model\Name
Copied!

Kann auch automatisch FileReferences erzeugen. In diesem Bespiel wird ein neues Model des Typs \Nng\Model\Name erzeugt und danach in der Datenbank persistiert. Das Feld falMedia ist eine ObjectStorage mit FileReferences. Die FileReferences werden automatisch erzeugt!

$data = [
    'pid' => 6,
    'title' => 'Neuer Datensatz',
    'description' => 'Der Text',
    'falMedia' => [
        ['title'=>'Bild 1', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
        ['title'=>'Bild 2', 'publicUrl'=>'fileadmin/_tests/5e505fbf5d3dd.jpg'],
        ['title'=>'Bild 3', 'publicUrl'=>'fileadmin/_tests/5e505f435061e.jpg'],
    ]
];
$newModel = \nn\t3::Convert( $data )->toModel( \Nng\Model\Name::class );
$modelRepository->add( $newModel );
\nn\t3::Db()->persistAll();
Copied!

Beispiel: Aus einem Array einen News-Model erzeugen:

$entry = [
    'pid'             => 12,
    'title'           => 'News-Titel',
    'description' => '<p>Meine News</p>',
    'falMedia'        => [['publicUrl' => 'fileadmin/bild.jpg', 'title'=>'Bild'], ...],
    'categories'  => [1, 2]
];
$model = \nn\t3::Convert( $entry )->toModel( \GeorgRinger\News\Domain\Model\News::class );
$newsRepository->add( $model );
\nn\t3::Db()->persistAll();
Copied!

Hinweis Um ein bereits existierendes Model mit Daten aus einem Array zu aktualisieren gibt es die Methode $updatedModel = \nn\t3::Obj( $prevModel )->merge( $data );

| @return mixed

| ➜ Go to source code of Convert::toModel()

\nn\t3::Convert()->toObjectStorage($obj = NULL, $childType = NULL); 

Konvertiert etwas in eine ObjectStorage

\nn\t3::Convert($something)->toObjectStorage()
\nn\t3::Convert($something)->toObjectStorage( \My\Child\Type::class )

\nn\t3::Convert()->toObjectStorage([['uid'=>1], ['uid'=>2], ...], \My\Child\Type::class )
\nn\t3::Convert()->toObjectStorage([1, 2, ...], \My\Child\Type::class )
Copied!

| @return ObjectStorage

| ➜ Go to source code of Convert::toObjectStorage()

\nn\t3::Convert()->toRGB(); 

Konvertiert einen Farbwert in ein anderes Zahlenformat

\nn\t3::Convert('#ff6600')->toRGB();   // -> 255,128,0
Copied!

| @return string

| ➜ Go to source code of Convert::toRGB()

\nn\t3::Convert()->toSysCategories(); 

Konvertiert eine Liste in eine ObjectStorage mit SysCategory

Noch nicht implementiert!
Copied!

| @return ObjectStorage

| ➜ Go to source code of Convert::toSysCategories()

\nn\t3::Convert()->toUTF8(); 

Konvertiert (normalisiert) einen String zu UTF-8

\nn\t3::Convert('äöü')->toUTF8();
Copied!

| @return string

| ➜ Go to source code of Convert::toUTF8()

Methods 

Convert::toArray() 

\nn\t3::Convert()->toArray($obj = NULL, $depth = 3); 

Konvertiert ein Model in ein Array Alias zu nnt3::Obj()->toArray();

Bei Memory-Problemen wegen Rekursionen: Max-Tiefe angebenen!

\nn\t3::Convert($model)->toArray(2);
\nn\t3::Convert($model)->toArray();      => ['uid'=>1, 'title'=>'Beispiel', ...]
Copied!

| @return array

Source Code 

public function toArray( $obj = null, $depth = 3 ) {
	if (is_int($obj)) $depth = $obj;
	$obj = $this->initialArgument !== null ? $this->initialArgument : $obj;
	return \nn\t3::Obj()->toArray($obj, $depth);
}
Copied!

Convert::toBytes() 

\nn\t3::Convert()->toBytes(); 

Konvertiert eine für Menschen lesbare Angabe von Bytes/Megabytes in einen Byte-Integer. Extrem tolerant, was Leerzeichen, Groß/Klein-Schreibung und Kommas statt Punkten angeht.

\nn\t3::Convert('1M')->toBytes();  // -> 1048576
\nn\t3::Convert('1 MB')->toBytes();    // -> 1048576
\nn\t3::Convert('1kb')->toBytes(); // -> 1024
\nn\t3::Convert('1,5kb')->toBytes();   // -> 1024
\nn\t3::Convert('1.5Gb')->toBytes();   // -> 1610612736
Copied!

Für den umgekehrten Weg (Bytes zu menschenlesbarer Schreibweise wie 1024 -> 1kb) gibt es einen praktischen Fluid ViewHelper im Core:

{fileSize->f:format.bytes()}
Copied!

| @return integer

Source Code 

public function toBytes() {
	$input = strtoupper($this->initialArgument);
	$units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
	$input = str_replace(',', '.', $input);
	if (substr($input, -1) == 'M') $input .= 'B';
	$number = substr($input, 0, -2);
	$suffix = substr($input,-2);
	if(is_numeric(substr($suffix, 0, 1))) {
		return preg_replace('/[^\d]/', '', $input);
	}
	$exponent = array_flip($units)[$suffix] ?? null;
	if($exponent === null) {
		return null;
	}
	return $number * (1024 ** $exponent);
}
Copied!

Convert::toFileReference() 

\nn\t3::Convert()->toFileReference(); 

Konvertiert ein \TYPO3\CMS\Core\Resource\FileReference (oder seine uid) in eine \TYPO3\CMS\Extbase\Domain\Model\FileReference

\nn\t3::Convert( $input )->toFileReference() => \TYPO3\CMS\Extbase\Domain\Model\FileReference
Copied!
@param $input Kann \TYPO3\CMS\Core\Resource\FileReference oder uid davon sein
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

Source Code 

public function toFileReference() {
	$input = $this->initialArgument;
	if (is_a( $input, \TYPO3\CMS\Core\Resource\FileReference::class )) {
		$falFileReference = $input;
	} else if (is_numeric($input)) {
		$resourceFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class);
		$falFileReference = $resourceFactory->getFileReferenceObject($input);
	}
	$sysFileReference = GeneralUtility::makeInstance( \TYPO3\CMS\Extbase\Domain\Model\FileReference::class );
	$sysFileReference->setOriginalResource($falFileReference);
	return $sysFileReference;
}
Copied!

Convert::toIso() 

\nn\t3::Convert()->toIso(); 

Konvertiert (normalisiert) einen String zu ISO-8859-1

\nn\t3::Convert('äöü')->toIso();
Copied!

| @return string

Source Code 

public function toIso() {
	$input = $this->initialArgument;
	$input = html_entity_decode($input);
	if (function_exists('iconv')) {
		$input = iconv('UTF-8', 'ISO-8859-1', $input);
	}
	return $input;
}
Copied!

Convert::toJson() 

\nn\t3::Convert()->toJson($obj = NULL, $depth = 3); 

Konvertiert ein Model in ein JSON

\nn\t3::Convert($model)->toJson()        => ['uid'=>1, 'title'=>'Beispiel', ...]
Copied!

| @return array

Source Code 

public function toJson( $obj = null, $depth = 3 ) {
	return json_encode( $this->toArray($obj, $depth) );
}
Copied!

Convert::toLanguage() 

\nn\t3::Convert()->toLanguage($sysLanguageUid = NULL); 

Konvertiert eine Sprach-ID (z.B. '0', '1') in das zweistellige Sprachkürzel (z.B. 'de', 'en')

// Sprach-ID 0 -> 'de'
\nn\t3::Convert(0)->toLanguage();
Copied!
@param int $sysLanguageUid
@return string

Source Code 

public function toLanguage($sysLanguageUid = null)
{
	if (is_string($sysLanguageUid) && strlen($sysLanguageUid) == 2) {
		return $sysLanguageUid;
	}
	$key = $sysLanguageUid !== null ? $sysLanguageUid : $this->initialArgument;
	$languages = \nn\t3::Environment()->getLanguages('languageId', 'iso-639-1');
	return $languages[$key] ?? '';
}
Copied!

Convert::toLanguageId() 

\nn\t3::Convert()->toLanguageId($languageCode = NULL); 

Konvertiert ein zweistelliges Sprachkürzel (z.B. 'de', 'en') in die Sprach-ID (z.B. '0', '1')

// Sprach-ID 0 -> 'de'
\nn\t3::Convert('de')->toLanguageId();
Copied!
@param int $sysLanguageUid
@return string

Source Code 

public function toLanguageId($languageCode = null)
{
	if (is_numeric($languageCode)) {
		return $languageCode;
	}
	$key = $languageCode !== null ? $languageCode : $this->initialArgument;
	$languages = \nn\t3::Environment()->getLanguages('iso-639-1', 'languageId');
	return $languages[$key] ?? '';
}
Copied!

Convert::toModel() 

\nn\t3::Convert()->toModel($className = NULL, $parentModel = NULL); 

Konvertiert ein Array in ein Model.

\nn\t3::Convert($array)->toModel( \Nng\Model\Name::class )       => \Nng\Model\Name
Copied!

Kann auch automatisch FileReferences erzeugen. In diesem Bespiel wird ein neues Model des Typs \Nng\Model\Name erzeugt und danach in der Datenbank persistiert. Das Feld falMedia ist eine ObjectStorage mit FileReferences. Die FileReferences werden automatisch erzeugt!

$data = [
    'pid' => 6,
    'title' => 'Neuer Datensatz',
    'description' => 'Der Text',
    'falMedia' => [
        ['title'=>'Bild 1', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
        ['title'=>'Bild 2', 'publicUrl'=>'fileadmin/_tests/5e505fbf5d3dd.jpg'],
        ['title'=>'Bild 3', 'publicUrl'=>'fileadmin/_tests/5e505f435061e.jpg'],
    ]
];
$newModel = \nn\t3::Convert( $data )->toModel( \Nng\Model\Name::class );
$modelRepository->add( $newModel );
\nn\t3::Db()->persistAll();
Copied!

Beispiel: Aus einem Array einen News-Model erzeugen:

$entry = [
    'pid'             => 12,
    'title'           => 'News-Titel',
    'description' => '<p>Meine News</p>',
    'falMedia'        => [['publicUrl' => 'fileadmin/bild.jpg', 'title'=>'Bild'], ...],
    'categories'  => [1, 2]
];
$model = \nn\t3::Convert( $entry )->toModel( \GeorgRinger\News\Domain\Model\News::class );
$newsRepository->add( $model );
\nn\t3::Db()->persistAll();
Copied!

Hinweis Um ein bereits existierendes Model mit Daten aus einem Array zu aktualisieren gibt es die Methode $updatedModel = \nn\t3::Obj( $prevModel )->merge( $data );

| @return mixed

Source Code 

public function toModel( $className = null, $parentModel = null ) {
	$arr = $this->initialArgument;
	$model = GeneralUtility::makeInstance( $className );
	return \nn\t3::Obj($model)->merge( $arr );
	# ToDo: Prüfen, warum der DataMapper hier nicht funktioniert. Model wird nicht persistiert!
	# $dataMapper = GeneralUtility::makeInstance(DataMapper::class);
	# return $dataMapper->map($model, [$arr]);
}
Copied!

Convert::toObjectStorage() 

\nn\t3::Convert()->toObjectStorage($obj = NULL, $childType = NULL); 

Konvertiert etwas in eine ObjectStorage

\nn\t3::Convert($something)->toObjectStorage()
\nn\t3::Convert($something)->toObjectStorage( \My\Child\Type::class )

\nn\t3::Convert()->toObjectStorage([['uid'=>1], ['uid'=>2], ...], \My\Child\Type::class )
\nn\t3::Convert()->toObjectStorage([1, 2, ...], \My\Child\Type::class )
Copied!

| @return ObjectStorage

Source Code 

public function toObjectStorage( $obj = null, $childType = null ) {
	$childType = $this->initialArgument !== null ? $obj : $childType;
	$persistenceManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class);
	$obj = $this->initialArgument !== null ? $this->initialArgument : $obj;
	$objectStorage = GeneralUtility::makeInstance( ObjectStorage::class );
	if ($childRepository = ($childType ? \nn\t3::Db()->getRepositoryForModel($childType) : false)) {
		\nn\t3::Db()->ignoreEnableFields($childRepository);
	}
	if (is_a($obj, QueryResultInterface::class) || is_array($obj)) {
		foreach($obj as $item) {
			if (!$childType || is_a($item, $childType)) {
				$objectStorage->attach( $item );
			} else {
				$uid = is_numeric($item) ? $item : \nn\t3::Obj()->get($item, 'uid');
				if ($uid) {
					if ($childType == \Nng\Nnhelpers\Domain\Model\FileReference::class) {
						$childType = \TYPO3\CMS\Extbase\Domain\Model\FileReference::class;
					}
					// @returns \TYPO3\CMS\Extbase\Domain\Model\FileReference
					$child = $persistenceManager->getObjectByIdentifier($uid, $childType, false);
					$objectStorage->attach( $child );
				} else {
					$child = GeneralUtility::makeInstance( $childType );
					$objectStorage->attach( $child );
				}
			}
		}
	}
	return $objectStorage;
}
Copied!

Convert::toRGB() 

\nn\t3::Convert()->toRGB(); 

Konvertiert einen Farbwert in ein anderes Zahlenformat

\nn\t3::Convert('#ff6600')->toRGB();   // -> 255,128,0
Copied!

| @return string

Source Code 

public function toRGB() {
	$input = $this->initialArgument;
	$isHex = substr($input, 0, 1) == '#' || strlen($input) == 6;
	if ($isHex) {
		$input = str_replace('#', '', $input);
		$rgb = sscanf($input, "%02x%02x%02x");
		return join(',', $rgb);
	}
	return '';
}
Copied!

Convert::toSysCategories() 

\nn\t3::Convert()->toSysCategories(); 

Konvertiert eine Liste in eine ObjectStorage mit SysCategory

Noch nicht implementiert!
Copied!

| @return ObjectStorage

Source Code 

public function toSysCategories() {
	$input = $this->initialArgument;
}
Copied!

Convert::toUTF8() 

\nn\t3::Convert()->toUTF8(); 

Konvertiert (normalisiert) einen String zu UTF-8

\nn\t3::Convert('äöü')->toUTF8();
Copied!

| @return string

Source Code 

public function toUTF8() {
	$input = $this->initialArgument;
	$input = html_entity_decode($input);
	if (function_exists('iconv')) {
		$input = iconv('ISO-8859-1', 'UTF-8', $input);
	}
	return $input;
}
Copied!

Cookies 

\nn\t3::Cookies() 

Methoden zum Setzen eines Cookies.

Seit TYPO3 12 können Cookies nicht einfach über $_COOKIE[] gesetzt werden. Sie müssen stattdessen im Psr\Http\Message\ResponseInterface gesetzt werden.

Overview of Methods 

\nn\t3::Cookies()->add($name = '', $value = '', $expire = 0); 

Einen Cookie erzeugen - aber noch nicht an den Client senden. Der Cookie wird erst in der Middleware gesetzt, siehe: | \Nng\Nnhelpers\Middleware\ModifyResponse

$cookie = \nn\t3::Cookies()->add( $name, $value, $expire );
$cookie = \nn\t3::Cookies()->add( 'my_cookie', 'my_nice_value', time() + 60 );
Copied!
@param string $name
@param string $value
@param int $expire
@return Cookie

| ➜ Go to source code of Cookies::add()

\nn\t3::Cookies()->addCookiesToResponse($request, $response); 

Fügt alle gespeicherten Cookies an den PSR-7 Response. Wird von \Nng\Nnhelpers\Middleware\ModifyResponse aufgerufen.

// Beispiel in einer MiddleWare:
$response = $handler->handle($request);
\nn\t3::Cookies()->addCookiesToResponse( $request, $response );
Copied!
@param ServerRequestInterface $request
@param ResponseInterface $request

| ➜ Go to source code of Cookies::addCookiesToResponse()

\nn\t3::Cookies()->create($request = NULL, $name = '', $value = '', $expire = 0); 

Eine Instanz des Symfony-Cookies erzeugen

$cookie = \nn\t3::Cookies()->create( $request, $name, $value, $expire );
$cookie = \nn\t3::Cookies()->create( $request, 'my_cookie', 'my_nice_value', time() + 60 );
Copied!
@param ServerRequestInterface $request
@param string $name
@param string $value
@param int $expire
@return Cookie

| ➜ Go to source code of Cookies::create()

\nn\t3::Cookies()->getAll(); 

Gibt alle Cookies zurück, die darauf warten, in der Middleware beim Response gesetzt zu werden.

$cookies = \nn\t3::Cookies()->getAll();
Copied!

| @return array

| ➜ Go to source code of Cookies::getAll()

Methods 

Cookies::add() 

\nn\t3::Cookies()->add($name = '', $value = '', $expire = 0); 

Einen Cookie erzeugen - aber noch nicht an den Client senden. Der Cookie wird erst in der Middleware gesetzt, siehe: | \Nng\Nnhelpers\Middleware\ModifyResponse

$cookie = \nn\t3::Cookies()->add( $name, $value, $expire );
$cookie = \nn\t3::Cookies()->add( 'my_cookie', 'my_nice_value', time() + 60 );
Copied!
@param string $name
@param string $value
@param int $expire
@return Cookie

Source Code 

public function add ( $name = '', $value = '', $expire = 0 )
{
	$this->cookiesToSet[$name] = [
		'value' => $value,
		'expire' => $expire
	];
}
Copied!

Cookies::addCookiesToResponse() 

\nn\t3::Cookies()->addCookiesToResponse($request, $response); 

Fügt alle gespeicherten Cookies an den PSR-7 Response. Wird von \Nng\Nnhelpers\Middleware\ModifyResponse aufgerufen.

// Beispiel in einer MiddleWare:
$response = $handler->handle($request);
\nn\t3::Cookies()->addCookiesToResponse( $request, $response );
Copied!
@param ServerRequestInterface $request
@param ResponseInterface $request

Source Code 

public function addCookiesToResponse ( $request, &$response )
{
	foreach ($this->cookiesToSet as $name=>$cookie) {
		$cookie = $this->create( $request, $name, $cookie['value'], $cookie['expire'] );
		$response = $response->withAddedHeader('Set-Cookie', (string) $cookie);
	}
	return $response;
}
Copied!

Cookies::create() 

\nn\t3::Cookies()->create($request = NULL, $name = '', $value = '', $expire = 0); 

Eine Instanz des Symfony-Cookies erzeugen

$cookie = \nn\t3::Cookies()->create( $request, $name, $value, $expire );
$cookie = \nn\t3::Cookies()->create( $request, 'my_cookie', 'my_nice_value', time() + 60 );
Copied!
@param ServerRequestInterface $request
@param string $name
@param string $value
@param int $expire
@return Cookie

Source Code 

public function create ( $request = null, $name = '', $value = '', $expire = 0 )
{
	$normalizedParams = $request->getAttribute('normalizedParams');
	$secure = $normalizedParams instanceof NormalizedParams && $normalizedParams->isHttps();
	$path = $normalizedParams->getSitePath();
	return new Cookie(
		$name,
		$value,
		$expire,
		$path,
		null,
		$secure,
		true,
		false,
		Cookie::SAMESITE_STRICT
	);
}
Copied!

Cookies::getAll() 

\nn\t3::Cookies()->getAll(); 

Gibt alle Cookies zurück, die darauf warten, in der Middleware beim Response gesetzt zu werden.

$cookies = \nn\t3::Cookies()->getAll();
Copied!

| @return array

Source Code 

public function getAll ()
{
	return $this->cookiesToSet;
}
Copied!

Db 

\nn\t3::Db() 

Zugriff auf die meist genutzten Datenbank-Operationen für Schreiben, Lesen, Löschen vereinfachen.

Overview of Methods 

\nn\t3::Db()->debug($query = NULL, $return = false); 

Debug des QueryBuilder-Statements.

Gibt den kompletten, kompilierten Query als lesbaren String aus, so wie er später in der Datenbank ausgeführt wird z.B. SELECT FROM fe_users WHERE ...

// Statement direkt im Browser ausgeben
\nn\t3::Db()->debug( $query );

// Statement als String zurückgeben, nicht automatisch ausgeben
echo \nn\t3::Db()->debug( $query, true );
Copied!
@param mixed $query
@param boolean $return
@return string

| ➜ Go to source code of Db::debug()

\nn\t3::Db()->delete($table = '', $constraint = [], $reallyDelete = false); 

Datenbank-Eintrag löschen. Klein und Fein. Es kann entweder ein Tabellenname und die UID übergeben werden - oder ein Model.

Löschen eines Datensatzes per Tabellenname und uid oder einem beliebigen Constraint:

// Löschen anhand der uid
\nn\t3::Db()->delete('table', $uid);

// Löschen anhand eines eigenen Feldes
\nn\t3::Db()->delete('table', ['uid_local'=>$uid]);

// Eintrag komplett und unwiderruflich löschen (nicht nur per Flag deleted = 1 entfernen)
\nn\t3::Db()->delete('table', $uid, true);
Copied!

Löschen eines Datensatzes per Model:

\nn\t3::Db()->delete( $model );
Copied!
@param mixed $table
@param array $constraint
@param boolean $reallyDelete
@return mixed

| ➜ Go to source code of Db::delete()

\nn\t3::Db()->deleteWithAllFiles($model); 

Die DSGVO-Variante des Löschens.

Radikales entfernen aller Spuren eines Datensatzen inkl. der physischen SysFiles, die mit dem Model verknüpft sind. Mit Vorsicht zu verwenden, da keine Relationen auf das zu löschende Model geprüft werden.

\nn\t3::deleteWithAllFiles( $model );
Copied!
@param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $model
@return void

| ➜ Go to source code of Db::deleteWithAllFiles()

\nn\t3::Db()->filterDataForTable($data = [], $table = ''); 

In key/val-Array nur Elemente behalten, deren keys auch in TCA für bestimmte Tabelle existieren

@param array $data
@param string $table
@return array

| ➜ Go to source code of Db::filterDataForTable()

\nn\t3::Db()->findAll($table = '', $ignoreEnableFields = false); 

Holt ALLE Eintrag aus einer Datenbank-Tabelle.

Die Daten werden als Array zurückgegeben – das ist (leider) noch immer die absolute performanteste Art, viele Datensätze aus einer Tabelle zu holen, da kein DataMapper die einzelnen Zeilen parsen muss.

// Alle Datensätze holen. "hidden" wird berücksichtigt.
\nn\t3::Db()->findAll('fe_users');

// Auch Datensätze holen, die "hidden" sind
\nn\t3::Db()->findAll('fe_users', true);
Copied!
@param string $table
@param boolean $ignoreEnableFields
@return array

| ➜ Go to source code of Db::findAll()

\nn\t3::Db()->findByUid($table = '', $uid = NULL, $ignoreEnableFields = false); 

Findet einen Eintrag anhand der UID. Funktioniert auch, wenn Frontend noch nicht initialisiert wurden, z.B. während AuthentificationService läuft oder im Scheduler.

\nn\t3::Db()->findByUid('fe_user', 12);
\nn\t3::Db()->findByUid('fe_user', 12, true);
Copied!
@param string $table
@param int $uid
@param boolean $ignoreEnableFields
@return array

| ➜ Go to source code of Db::findByUid()

\nn\t3::Db()->findByUids($table = '', $uids = NULL, $ignoreEnableFields = false); 

Findet Einträge anhand mehrerer UIDs.

\nn\t3::Db()->findByUids('fe_user', [12,13]);
\nn\t3::Db()->findByUids('fe_user', [12,13], true);
Copied!
@param string $table
@param int|array $uids
@param boolean $ignoreEnableFields
@return array

| ➜ Go to source code of Db::findByUids()

\nn\t3::Db()->findByValues($table = NULL, $where = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = [], $additionalQueryParams = []); 

Findet ALLE Einträge anhand eines gewünschten Feld-Wertes. Funktioniert auch, wenn Frontend noch nicht initialisiert wurde.

// SELECT  FROM fe_users WHERE email = 'david@99grad.de'
\nn\t3::Db()->findByValues('fe_users', ['email'=>'david@99grad.de']);

// SELECT  FROM fe_users WHERE uid IN (1,2,3)
\nn\t3::Db()->findByValues('fe_users', ['uid'=>[1,2,3]]);

// SELECT uid, username FROM fe_users WHERE name = 'test'
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, ['uid', 'username']);

// SELECT  FROM fe_users WHERE name = 'test' LIMIT 1
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, false, ['limit'=>1]);

// SELECT  FROM fe_users WHERE name = 'test' LIMIT 2 OFFSET 3
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, false, ['limit'=>2, 'offset'=>3]);
Copied!
@param string $table
@param array $whereArr
@param boolean $useLogicalOr
@param boolean $ignoreEnableFields
@param array|boolean $fieldsToGet
@param array $additionalQueryParams
@return array

| ➜ Go to source code of Db::findByValues()

\nn\t3::Db()->findIn($table = '', $column = '', $values = [], $ignoreEnableFields = false); 

Findet ALLE Einträge, die in der Spalte $column einen Wert aus dem Array $values enthält. Funktioniert auch, wenn das Frontend noch nicht initialisiert wurden. Alias zu \nn\t3::Db()->findByValues()

// SELECT  FROM fe_users WHERE uid IN (1,2,3)
\nn\t3::Db()->findIn('fe_users', 'uid', [1,2,3]);

// SELECT  FROM fe_users WHERE username IN ('david', 'martin')
\nn\t3::Db()->findIn('fe_users', 'username', ['david', 'martin']);
Copied!
@param string $table
@param string $column
@param array $values
@param boolean $ignoreEnableFields
@return array

| ➜ Go to source code of Db::findIn()

\nn\t3::Db()->findNotIn($table = '', $colName = '', $values = [], $ignoreEnableFields = false); 

Umkehrung zu \nn\t3::Db()->findIn():

Findet ALLE Einträge, die in der Spalte $column NICHT einen Wert aus dem Array $values enthält. Funktioniert auch, wenn das Frontend noch nicht initialisiert wurden.

// SELECT  FROM fe_users WHERE uid NOT IN (1,2,3)
\nn\t3::Db()->findNotIn('fe_users', 'uid', [1,2,3]);

// SELECT  FROM fe_users WHERE username NOT IN ('david', 'martin')
\nn\t3::Db()->findNotIn('fe_users', 'username', ['david', 'martin']);
Copied!
@param string $table
@param string $colName
@param array $values
@param boolean $ignoreEnableFields
@return array

| ➜ Go to source code of Db::findNotIn()

\nn\t3::Db()->findOneByValues($table = NULL, $whereArr = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = []); 

Findet EINEN Eintrag anhand von gewünschten Feld-Werten.

// SELECT  FROM fe_users WHERE email = 'david@99grad.de'
\nn\t3::Db()->findOneByValues('fe_users', ['email'=>'david@99grad.de']);

// SELECT  FROM fe_users WHERE firstname = 'david' AND username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john']);

// SELECT  FROM fe_users WHERE firstname = 'david' OR username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john'], true);

// SELECT uid, name FROM fe_users WHERE firstname = 'david' OR username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john'], true, false, ['uid', 'name']);
Copied!
@param string $table
@param array $whereArr
@param boolean $useLogicalOr
@param boolean $ignoreEnableFields
@param array $fieldsToGet
@return array

| ➜ Go to source code of Db::findOneByValues()

\nn\t3::Db()->fixFileReferencesForModel($model); 

"Repariert" die SysFileReferences für Modelle, die eine Property haben, die statt einer ObjectStorage<FileReference> nur eine FileReference referenzieren. Zum aktuellen Zeitpunkt ist es unklar, weshalb TYPO3 diese zwar in der Tabelle sys_file_reference persistiert, aber das Feld tablenames leert – bzw. uid_foreign nicht setzt. Bei einer ObjectStorage<FileReference> tritt das Problem nicht auf.

// muss direkt nach dem persistieren des Models passieren
\nn\t3::Db()->fixFileReferencesForModel( $model );
Copied!

| ➜ Go to source code of Db::fixFileReferencesForModel()

\nn\t3::Db()->get($uid, $modelType = '', $ignoreEnableFields = false); 

Ein oder mehrere Domain-Model/Entity anhand einer uid holen. Es kann eine einzelne $uid oder eine Liste von $uids übergeben werden.

Liefert das "echte" Model/Object inklusive aller Relationen, analog zu einer Query über das Repository.

// Ein einzelnes Model anhand seiner uid holen
$model = \nn\t3::Db()->get( 1, \Nng\MyExt\Domain\Model\Name::class );

// Ein Array an Models anhand ihrer uids holen
$modelArray = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Name::class );

// Gibt auch hidden Models zurück
$modelArrayWithHidden = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Name::class, true );
Copied!
@param int $uid
@param string $modelType
@param boolean $ignoreEnableFields
@return Object

| ➜ Go to source code of Db::get()

\nn\t3::Db()->getColumn($table = '', $colName = '', $useSchemaManager = false); 

Eine Tabellen-Spalte (TCA) für bestimmte Tabelle holen

\nn\t3::Db()->getColumn( 'tablename', 'fieldname' );
Copied!
@param string $table
@param string $colName
@param boolean $useSchemaManager
@return array

| ➜ Go to source code of Db::getColumn()

\nn\t3::Db()->getColumnLabel($column = '', $table = ''); 

Lokalisiertes Label eines bestimmten TCA Feldes holen

@param string $column
@param string $table
@return string

| ➜ Go to source code of Db::getColumnLabel()

\nn\t3::Db()->getColumns($table = '', $useSchemaManager = false); 

Alle Tabellen-Spalten (TCA) für bestimmte Tabelle holen

// Felder anhand des TCA-Arrays holen
\nn\t3::Db()->getColumns( 'tablename' );

// Felder über den SchemaManager ermitteln
\nn\t3::Db()->getColumns( 'tablename', true );
Copied!
@param string $table
@param boolean $useSchemaManager
@return array

| ➜ Go to source code of Db::getColumns()

\nn\t3::Db()->getColumnsByType($table = '', $colType = '', $useSchemaManager = false); 

Felder einer Tabelle nach einem bestimmten Typ holen

\nn\t3::Db()->getColumnsByType( 'tx_news_domain_model_news', 'slug' );
Copied!
@param string $table
@param string $colType
@param boolean $useSchemaManager
@return array

| ➜ Go to source code of Db::getColumnsByType()

\nn\t3::Db()->getConnection(); 

Eine "rohe" Verbindung zur Datenbank holen. Nur in wirklichen Ausnahmefällen sinnvoll.

$connection = \nn\t3::Db()->getConnection();
$connection->fetchAll( 'SELECT  FROM tt_news WHERE 1;' );
Copied!

| @return \TYPO3\CMS\Core\Database\Connection

| ➜ Go to source code of Db::getConnection()

\nn\t3::Db()->getDeleteColumn($table = ''); 

Delete-Column für bestimmte Tabelle holen.

Diese Spalte wird als Flag für gelöschte Datensätze verwendet. Normalerweise: deleted = 1

@param string $table
@return string

| ➜ Go to source code of Db::getDeleteColumn()

\nn\t3::Db()->getQueryBuilder($table = ''); 

QueryBuilder für eine Tabelle holen

$queryBuilder = \nn\t3::Db()->getQueryBuilder( 'fe_users' );
Copied!

Beispiel:

$queryBuilder = \nn\t3::Db()->getQueryBuilder( 'fe_users' );
$queryBuilder->select('name')->from( 'fe_users' );
$queryBuilder->andWhere( $queryBuilder->expr()->eq( 'uid', $queryBuilder->createNamedParameter(12) ));
$rows = $queryBuilder->executeStatement()->fetchAllAssociative();
Copied!
@param string $table
@return QueryBuilder

| ➜ Go to source code of Db::getQueryBuilder()

\nn\t3::Db()->getRepositoryForModel($className = NULL); 

Instanz des Repositories für ein Model (oder einen Model-Klassennamen) holen.

\nn\t3::Db()->getRepositoryForModel( \My\Domain\Model\Name::class );
\nn\t3::Db()->getRepositoryForModel( $myModel );
Copied!
@param mixed $className
@return \TYPO3\CMS\Extbase\Persistence\Repository

| ➜ Go to source code of Db::getRepositoryForModel()

\nn\t3::Db()->getTableNameForModel($className = NULL); 

Tabellen-Name für ein Model (oder einen Model-Klassennamen) holen. Alias zu \nn\t3::Obj()->getTableName()

// tx_myext_domain_model_entry
\nn\t3::Db()->getTableNameForModel( $myModel );

// tx_myext_domain_model_entry
\nn\t3::Db()->getTableNameForModel( \My\Domain\Model\Name::class );
Copied!
@param mixed $className
@return string

| ➜ Go to source code of Db::getTableNameForModel()

\nn\t3::Db()->ignoreEnableFields($queryOrRepository, $ignoreStoragePid = true, $ignoreHidden = false, $ignoreDeleted = false, $ignoreStartEnd = false); 

Entfernt Default-Constraints zur StoragePID, hidden und/oder deleted zu einer Query oder Repository.

\nn\t3::Db()->ignoreEnableFields( $entryRepository );
\nn\t3::Db()->ignoreEnableFields( $query );
Copied!

Beispiel für eine Custom Query:

$table = 'tx_myext_domain_model_entry';
$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
$queryBuilder->select('uid','title','hidden')->from( $table );
\nn\t3::Db()->ignoreEnableFields( $queryBuilder, true, true );
$rows = $queryBuilder->executeQuery()->fetchAllAssociative();
Copied!

Sollte das nicht reichen oder zu kompliziert werden, siehe:

\nn\t3::Db()->statement();
Copied!
@param mixed $queryOrRepository
@param boolean $ignoreStoragePid
@param boolean $ignoreHidden
@param boolean $ignoreDeleted
@param boolean $ignoreStartEnd
@return mixed

| ➜ Go to source code of Db::ignoreEnableFields()

\nn\t3::Db()->insert($tableNameOrModel = '', $data = []); 

Datenbank-Eintrag einfügen. Simpel und idiotensicher. Entweder kann der Tabellenname und ein Array übergeben werden - oder ein Domain-Model.

Einfügen eines neuen Datensatzes per Tabellenname und Daten-Array:

$insertArr = \nn\t3::Db()->insert('table', ['bodytext'=>'...']);
Copied!

Einfügen eines neuen Models. Das Repository wird automatisch ermittelt. Das Model wird direkt persistiert.

$model = new \My\Nice\Model();
$persistedModel = \nn\t3::Db()->insert( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@return mixed

| ➜ Go to source code of Db::insert()

\nn\t3::Db()->insertMultiple($tableName = '', $rows = [], $colOrder = []); 

Mehrere Zeilen in Datenbank einfügen.

use TYPO3\CMS\Core\Database\Connection;

$data = [
    ['title' => 'Eins', 'tstamp'=>123],
    ['title' => 'Zwei', 'tstamp'=>123],
];
$colOrder = [
    'tstamp' => Connection::PARAM_INT,
    'title' => Connection::PARAM_STR,
];

\nn\t3::Db()->insertMultiple('table', $data, $colOrder);
Copied!
@param string $tableName
@param array $rows
@param array $colOrder
@return boolean

| ➜ Go to source code of Db::insertMultiple()

\nn\t3::Db()->insertOrUpdate($tableName, $whereArr = [], $model = []); 

Store an item in the database, but keep it unique by $whereArr = []

$data = [ profileUid: "", entityType: "", entityUid: "",  ... ];
\nn\un::Interaction()->insertOrUpdate( $data );
Copied!
@param int $feUserId
@param array $data
@return array $model

| ➜ Go to source code of Db::insertOrUpdate()

\nn\t3::Db()->orderBy($queryOrRepository, $ordering = []); 

Sortierung für ein Repository oder einen Query setzen.

$ordering = ['title' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );

// asc und desc können als synonym verwendet werden
$ordering = ['title' => 'asc'];
$ordering = ['title' => 'desc'];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!

Kann auch zum Sortieren nach einer Liste von Werten (z.B. uids) verwendet werden. Dazu wird ein Array für den Wert des einzelnen orderings übergeben:

$ordering = ['uid' => [3,7,2,1]];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!
@param mixed $queryOrRepository
@param array $ordering
@return mixed

| ➜ Go to source code of Db::orderBy()

\nn\t3::Db()->persistAll(); 

Alles persistieren.

\nn\t3::Db()->persistAll();
Copied!

| @return void

| ➜ Go to source code of Db::persistAll()

\nn\t3::Db()->quote($value = ''); 

Ein Ersatz für die mysqli_real_escape_string() Methode.

Sollte nur im Notfall bei Low-Level Queries verwendet werden. Besser ist es, preparedStatements zu verwenden.

Funktioniert nur bei SQL, nicht bei DQL.

$sword = \nn\t3::Db()->quote('test');          // => 'test'
$sword = \nn\t3::Db()->quote("test';SET");        // => 'test\';SET'
$sword = \nn\t3::Db()->quote([1, 'test', '2']);  // => [1, "'test'", '2']
$sword = \nn\t3::Db()->quote('"; DROP TABLE fe_user;#');
Copied!
@param string|array $value
@return string|array

| ➜ Go to source code of Db::quote()

\nn\t3::Db()->save($tableNameOrModel = '', $data = []); 

Datenbank-Eintrag erstellen ODER einen vorhandenen Datensatz updaten.

Entscheidet selbstständig, ob der Eintrag per UPDATE oder INSERT in die Datenbank eingefügt bzw. ein vorhandener Datensatz aktualisiert werden muss. Die Daten werden direkt persistiert!

Beispiel für Übergabe eines Tabellennamens und eines Arrays:

// keine uid übergeben? Dann INSERT eines neuen Datensatzes
\nn\t3::Db()->save('table', ['bodytext'=>'...']);

// uid übergeben? Dann UPDATE vorhandener Daten
\nn\t3::Db()->save('table', ['uid'=>123, 'bodytext'=>'...']);
Copied!

Beispiel für Übergabe eines Domain-Models:

// neues Model? Wird per $repo->add() eingefügt
$model = new \My\Nice\Model();
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );

// vorhandenes Model? Wird per $repo->update() aktualisiert
$model = $myRepo->findByUid(123);
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@return mixed

| ➜ Go to source code of Db::save()

\nn\t3::Db()->setFalConstraint($queryBuilder = NULL, $tableName = '', $falFieldName = '', $numFal = true, $operator = false); 

Constraint für sys_file_reference zu einem QueryBuilder hinzufügen. Beschränkt die Ergebnisse darauf, ob es eine FAL-Relation gibt.

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );

// Nur Datensätze holen, die für falfield mindestes eine SysFileReference haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield' );

// ... die KEINE SysFileReference für falfield haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', false );

// ... die GENAU 2 SysFileReferences haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2 );

// ... die 2 oder weniger (less than or equal) SysFileReferences haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2, 'lte' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder
@param string $tableName
@param string $falFieldName
@param boolean $numFal
@param boolean $operator
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

| ➜ Go to source code of Db::setFalConstraint()

\nn\t3::Db()->setNotInSysCategoryConstraint($queryBuilder = NULL, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories'); 

Contraint auf Datensätze beschränken, die NICHT in eine der angegebenen Kategorien sind. Gegenteil und Alias zu \nn\t3::Db()->setSysCategoryConstraint()

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
\nn\t3::Db()->setNotInSysCategoryConstraint( $queryBuilder, [1,3,4], 'tx_myext_tablename', 'categories' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder
@param array $sysCategoryUids
@param string $tableName
@param string $categoryFieldName
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

| ➜ Go to source code of Db::setNotInSysCategoryConstraint()

\nn\t3::Db()->setSysCategoryConstraint($queryBuilder = NULL, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories', $useNotIn = false); 

Constraint für sys_category / sys_category_record_mm zu einem QueryBuilder hinzufügen. Beschränkt die Ergebnisse auf die angegebenen Sys-Categories-UIDs.

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
\nn\t3::Db()->setSysCategoryConstraint( $queryBuilder, [1,3,4], 'tx_myext_tablename', 'categories' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $querybuilder
@param array $sysCategoryUids
@param string $tableName
@param string $categoryFieldName
@param boolean $useNotIn
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

| ➜ Go to source code of Db::setSysCategoryConstraint()

\nn\t3::Db()->sortBy($objectArray, $fieldName = 'uid', $uidList = []); 

Sortiert Ergebnisse eines Queries nach einem Array und bestimmten Feld. Löst das Problem, dass eine ->in()-Query die Ergebnisse nicht in der Reihenfolge der übergebenen IDs liefert. Beispiel: | $query->matching($query->in('uid', [3,1,2])); kommt nicht zwingend in der Reihenfolge [3,1,2] zurück.

$insertArr = \nn\t3::Db()->sortBy( $storageOrArray, 'uid', [2,1,5]);
Copied!
@param mixed $objectArray
@param string $fieldName
@param array $uidList
@return array

| ➜ Go to source code of Db::sortBy()

\nn\t3::Db()->statement($statement = '', $params = [], $types = []); 

Eine "rohe" Query an die Datenbank absetzen. Näher an der Datenbank geht nicht. Du bist für alles selbst verantwortlich. Injections steht nur Deine (hoffentlich ausreichende :) Intelligenz entgegen.

Hilft z.B. bei Abfragen von Tabellen, die nicht Teil der Typo3 Installation sind und daher über den normal QueryBuilder nicht erreicht werden könnten.

// Variablen IMMER über escapen!
$keyword = \nn\t3::Db()->quote('suchbegriff');
$rows = \nn\t3::Db()->statement( "SELECT  FROM tt_news WHERE bodytext LIKE '%{$keyword}%'");

// oder besser gleich prepared statements verwenden:
$rows = \nn\t3::Db()->statement( 'SELECT  FROM tt_news WHERE bodytext LIKE :str', ['str'=>"%{$keyword}%"] );

// Typen können übergeben werden (bei Array wird das automatisch ermittelt)
$rows = \nn\t3::Db()->statement( 'SELECT  FROM tt_news WHERE uid IN (:uids)', ['uids'=>[1,2,3]], ['uids'=>Connection::PARAM_INT_ARRAY] );
Copied!

Bei einem SELECT Statement werden die Zeilen aus der Datenbank als Array zurückgegeben. Bei allen anderen Statements (z.B. UPDATE oder DELETE) wird die Anzahl der betroffenen Zeilen zurückgegeben.

@param string $statement
@param array $params
@param array $types
@return mixed

| ➜ Go to source code of Db::statement()

\nn\t3::Db()->tableExists($table = ''); 

Existiert eine bestimmte DB-Tabelle?

$exists = \nn\t3::Db()->tableExists('table');
Copied!

| @return boolean

| ➜ Go to source code of Db::tableExists()

\nn\t3::Db()->truncate($table = ''); 

Datenbank-Tabelle leeren. Löscht alle Einträge in der angegebenen Tabelle und setzt den Auto-Increment-Wert auf 0 zurück.

\nn\t3::Db()->truncate('table');
Copied!
@param string $table
@return boolean

| ➜ Go to source code of Db::truncate()

\nn\t3::Db()->undelete($table = '', $constraint = []); 

Gelöschten Datenbank-Eintrag wiederherstellen. Dazu wird der Flag für "gelöscht" (deleted) wieder auf 0 gesetzt wird.

\nn\t3::Db()->undelete('table', $uid);
\nn\t3::Db()->undelete('table', ['uid_local'=>$uid]);
Copied!
@param string $table
@param array $constraint
@return boolean

| ➜ Go to source code of Db::undelete()

\nn\t3::Db()->update($tableNameOrModel = '', $data = [], $uid = NULL); 

Datenbank-Eintrag aktualisieren. Schnell und einfach. Das Update kann entweder per Tabellenname und Daten-Array passieren. Oder man übergibt ein Model.

Beispiele:

// UPDATES table SET title='new' WHERE uid=1
\nn\t3::Db()->update('table', ['title'=>'new'], 1);

// UPDATES table SET title='new' WHERE uid IN (1,2,3)
\nn\t3::Db()->update('table', ['title'=>'new'], ['uid'=>[1,2,3]);

// UPDATE table SET title='new' WHERE email='david@99grad.de' AND pid=12
\nn\t3::Db()->update('table', ['title'=>'new'], ['email'=>'david@99grad.de', 'pid'=>12, ...]);
Copied!

Mit true statt einer $uid werden ALLE Datensätze der Tabelle geupdated.

// UPDATE table SET test='1' WHERE 1
\nn\t3::Db()->update('table', ['test'=>1], true);
Copied!

Statt einem Tabellenname kann auch ein einfach Model übergeben werden. Das Repository wird automatisch ermittelt und das Model direkt persistiert.

$model = $myRepo->findByUid(1);
\nn\t3::Db()->update( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@param int $uid
@return mixed

| ➜ Go to source code of Db::update()

Methods 

Db::debug() 

\nn\t3::Db()->debug($query = NULL, $return = false); 

Debug des QueryBuilder-Statements.

Gibt den kompletten, kompilierten Query als lesbaren String aus, so wie er später in der Datenbank ausgeführt wird z.B. SELECT FROM fe_users WHERE ...

// Statement direkt im Browser ausgeben
\nn\t3::Db()->debug( $query );

// Statement als String zurückgeben, nicht automatisch ausgeben
echo \nn\t3::Db()->debug( $query, true );
Copied!
@param mixed $query
@param boolean $return
@return string

Source Code 

public function debug ( $query = null, $return = false )
{
	if( !($query instanceof QueryBuilder) ) {
		$queryParser = \nn\t3::injectClass(Typo3DbQueryParser::class);
		$query = $queryParser->convertQueryToDoctrineQueryBuilder($query);
	}
	$dcValues = $query->getParameters();
	$dcValuesFull = [];
	foreach ($dcValues as $k=>$v) {
		if (is_array($v)) {
			foreach ($v as &$n) {
				if (!is_numeric($n)) {
					$n = "'" . addslashes($n) . "'";
				}
			}
			$v = join(',', $v);
		} else if (!is_numeric($v)) {
			$v = "'" . addslashes($v) . "'";
		}
		$dcValuesFull[":{$k}"] = $v;
	}
	// Sicherstellen, dass zuerst `:value55` vor `:value5` ersetzt wird
	uksort($dcValuesFull, function($a, $b) {
		return strlen($a) > strlen($b) ? -1 : 1;
	});
	$str = $query->getSQL();
	$str = str_replace( array_keys($dcValuesFull), array_values($dcValuesFull), $str );
	if (!$return) echo $str;
	return $str;
}
Copied!

Db::delete() 

\nn\t3::Db()->delete($table = '', $constraint = [], $reallyDelete = false); 

Datenbank-Eintrag löschen. Klein und Fein. Es kann entweder ein Tabellenname und die UID übergeben werden - oder ein Model.

Löschen eines Datensatzes per Tabellenname und uid oder einem beliebigen Constraint:

// Löschen anhand der uid
\nn\t3::Db()->delete('table', $uid);

// Löschen anhand eines eigenen Feldes
\nn\t3::Db()->delete('table', ['uid_local'=>$uid]);

// Eintrag komplett und unwiderruflich löschen (nicht nur per Flag deleted = 1 entfernen)
\nn\t3::Db()->delete('table', $uid, true);
Copied!

Löschen eines Datensatzes per Model:

\nn\t3::Db()->delete( $model );
Copied!
@param mixed $table
@param array $constraint
@param boolean $reallyDelete
@return mixed

Source Code 

public function delete ( $table = '', $constraint = [], $reallyDelete = false )
{
	if (\nn\t3::Obj()->isModel($table)) {
		$model = $table;
		$repository = $this->getRepositoryForModel( $model );
		$repository->remove( $model );
		$this->persistAll();
		return $model;
	}
	if (!$constraint) return false;
	if (is_numeric($constraint)) {
		$constraint = ['uid' => $constraint];
	}
	$deleteColumn = $reallyDelete ? false : $this->getDeleteColumn( $table );
	if ($deleteColumn) {
		return $this->update( $table, [$deleteColumn => 1], $constraint );
	}
	$queryBuilder = $this->getQueryBuilder( $table );
	$queryBuilder->delete($table);
	foreach ($constraint as $k=>$v) {
		if (is_array($v)) {
			$queryBuilder->andWhere(
				$queryBuilder->expr()->in( $k, $queryBuilder->createNamedParameter($v, Connection::PARAM_STR_ARRAY) )
			);
		} else {
			$queryBuilder->andWhere(
				$queryBuilder->expr()->eq( $k, $queryBuilder->createNamedParameter($v))
			);
		}
	}
	return $queryBuilder->executeStatement();
}
Copied!

Db::deleteWithAllFiles() 

\nn\t3::Db()->deleteWithAllFiles($model); 

Die DSGVO-Variante des Löschens.

Radikales entfernen aller Spuren eines Datensatzen inkl. der physischen SysFiles, die mit dem Model verknüpft sind. Mit Vorsicht zu verwenden, da keine Relationen auf das zu löschende Model geprüft werden.

\nn\t3::deleteWithAllFiles( $model );
Copied!
@param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $model
@return void

Source Code 

public function deleteWithAllFiles( $model )
{
	$tableName = $this->getTableNameForModel( $model );
	$uid = $model->getUid();
	if (!$tableName || !$uid) return;
	\nn\t3::Fal()->deleteForModel( $model );
	\nn\t3::Db()->delete($tableName, $uid, true);
}
Copied!

Db::filterDataForTable() 

\nn\t3::Db()->filterDataForTable($data = [], $table = ''); 

In key/val-Array nur Elemente behalten, deren keys auch in TCA für bestimmte Tabelle existieren

@param array $data
@param string $table
@return array

Source Code 

public function filterDataForTable ( $data = [], $table = '' )
{
	$tcaColumns = $this->getColumns( $table );
	$existingCols = array_intersect( array_keys($data), array_keys($tcaColumns));
	foreach ($data as $k=>$v) {
		if (!in_array($k, $existingCols)) {
			unset($data[$k]);
		}
	}
	return $data;
}
Copied!

Db::findAll() 

\nn\t3::Db()->findAll($table = '', $ignoreEnableFields = false); 

Holt ALLE Eintrag aus einer Datenbank-Tabelle.

Die Daten werden als Array zurückgegeben – das ist (leider) noch immer die absolute performanteste Art, viele Datensätze aus einer Tabelle zu holen, da kein DataMapper die einzelnen Zeilen parsen muss.

// Alle Datensätze holen. "hidden" wird berücksichtigt.
\nn\t3::Db()->findAll('fe_users');

// Auch Datensätze holen, die "hidden" sind
\nn\t3::Db()->findAll('fe_users', true);
Copied!
@param string $table
@param boolean $ignoreEnableFields
@return array

Source Code 

public function findAll( $table = '', $ignoreEnableFields = false )
{
	$rows = $this->findByValues( $table, [], false, $ignoreEnableFields );
	return $rows ?: [];
}
Copied!

Db::findByUid() 

\nn\t3::Db()->findByUid($table = '', $uid = NULL, $ignoreEnableFields = false); 

Findet einen Eintrag anhand der UID. Funktioniert auch, wenn Frontend noch nicht initialisiert wurden, z.B. während AuthentificationService läuft oder im Scheduler.

\nn\t3::Db()->findByUid('fe_user', 12);
\nn\t3::Db()->findByUid('fe_user', 12, true);
Copied!
@param string $table
@param int $uid
@param boolean $ignoreEnableFields
@return array

Source Code 

public function findByUid( $table = '', $uid = null, $ignoreEnableFields = false )
{
	$rows = $this->findByValues( $table, ['uid' => $uid], false, $ignoreEnableFields );
	return $rows ? array_shift($rows) : [];
}
Copied!

Db::findByUids() 

\nn\t3::Db()->findByUids($table = '', $uids = NULL, $ignoreEnableFields = false); 

Findet Einträge anhand mehrerer UIDs.

\nn\t3::Db()->findByUids('fe_user', [12,13]);
\nn\t3::Db()->findByUids('fe_user', [12,13], true);
Copied!
@param string $table
@param int|array $uids
@param boolean $ignoreEnableFields
@return array

Source Code 

public function findByUids( $table = '', $uids = null, $ignoreEnableFields = false )
{
	if (!$uids) return [];
	$rows = $this->findByValues( $table, ['uid' => $uids], false, $ignoreEnableFields );
	return $rows;
}
Copied!

Db::findByValues() 

\nn\t3::Db()->findByValues($table = NULL, $where = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = [], $additionalQueryParams = []); 

Findet ALLE Einträge anhand eines gewünschten Feld-Wertes. Funktioniert auch, wenn Frontend noch nicht initialisiert wurde.

// SELECT  FROM fe_users WHERE email = 'david@99grad.de'
\nn\t3::Db()->findByValues('fe_users', ['email'=>'david@99grad.de']);

// SELECT  FROM fe_users WHERE uid IN (1,2,3)
\nn\t3::Db()->findByValues('fe_users', ['uid'=>[1,2,3]]);

// SELECT uid, username FROM fe_users WHERE name = 'test'
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, ['uid', 'username']);

// SELECT  FROM fe_users WHERE name = 'test' LIMIT 1
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, false, ['limit'=>1]);

// SELECT  FROM fe_users WHERE name = 'test' LIMIT 2 OFFSET 3
\nn\t3::Db()->findByValues('fe_users', ['name'=>'test'], false, false, false, ['limit'=>2, 'offset'=>3]);
Copied!
@param string $table
@param array $whereArr
@param boolean $useLogicalOr
@param boolean $ignoreEnableFields
@param array|boolean $fieldsToGet
@param array $additionalQueryParams
@return array

Source Code 

public function findByValues( $table = null, $where = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = [], $additionalQueryParams = [] )
{
	// Nur Felder behalten, die auch in Tabelle (TCA) existieren
	$whereArr = $this->filterDataForTable( $where, $table );
	// nichts mehr übrig? Dann macht die Abfrage keinen Sinn
	if ($where && !$whereArr) {
		return [];
	}
	if (!$fieldsToGet) {
		$fieldsToGet = ['*'];
	}
	$queryBuilder = $this->getQueryBuilder( $table );
	$queryBuilder->select(...$fieldsToGet)->from( $table );
	// Alle Einschränkungen z.B. hidden oder starttime / endtime entfernen?
	if ($ignoreEnableFields) {
		$queryBuilder->getRestrictions()->removeAll();
	}
	// set LIMIT?
	if ($limit = $additionalQueryParams['limit'] ?? false) {
		$queryBuilder->setMaxResults( $limit );
	}
	// set LIMIT OFFSET?
	if ($offset = $additionalQueryParams['offset'] ?? false) {
		$queryBuilder->setFirstResult( $offset );
	}
	if ($whereArr) {
		foreach ($whereArr as $colName=>$v) {
			if (is_array($v)) {
				$v = $this->quote( $v );
				$expr = $queryBuilder->expr()->in($colName, $v );
				if ($uids = \nn\t3::Arrays($v)->intExplode()) {
					$this->orderBy( $queryBuilder, ["{$table}.{$colName}"=>$uids] );
				}
			} else {
				$expr = $queryBuilder->expr()->eq( $colName, $queryBuilder->createNamedParameter( $v ) );
			}
			if (!$useLogicalOr) {
				$queryBuilder->andWhere( $expr );
			} else {
				$queryBuilder->orWhere( $expr );
			}
		}
	}
	// "deleted" IMMER berücksichtigen!
	if ($deleteCol = $this->getDeleteColumn( $table )) {
		$queryBuilder->andWhere( $queryBuilder->expr()->eq($deleteCol, 0) );
	}
	$rows = $queryBuilder->executeQuery()->fetchAllAssociative();
	return $rows;
}
Copied!

Db::findIn() 

\nn\t3::Db()->findIn($table = '', $column = '', $values = [], $ignoreEnableFields = false); 

Findet ALLE Einträge, die in der Spalte $column einen Wert aus dem Array $values enthält. Funktioniert auch, wenn das Frontend noch nicht initialisiert wurden. Alias zu \nn\t3::Db()->findByValues()

// SELECT  FROM fe_users WHERE uid IN (1,2,3)
\nn\t3::Db()->findIn('fe_users', 'uid', [1,2,3]);

// SELECT  FROM fe_users WHERE username IN ('david', 'martin')
\nn\t3::Db()->findIn('fe_users', 'username', ['david', 'martin']);
Copied!
@param string $table
@param string $column
@param array $values
@param boolean $ignoreEnableFields
@return array

Source Code 

public function findIn( $table = '', $column = '', $values = [], $ignoreEnableFields = false )
{
	if (!$values) return [];
	return $this->findByValues( $table, [$column=>$values], false, $ignoreEnableFields );
}
Copied!

Db::findNotIn() 

\nn\t3::Db()->findNotIn($table = '', $colName = '', $values = [], $ignoreEnableFields = false); 

Umkehrung zu \nn\t3::Db()->findIn():

Findet ALLE Einträge, die in der Spalte $column NICHT einen Wert aus dem Array $values enthält. Funktioniert auch, wenn das Frontend noch nicht initialisiert wurden.

// SELECT  FROM fe_users WHERE uid NOT IN (1,2,3)
\nn\t3::Db()->findNotIn('fe_users', 'uid', [1,2,3]);

// SELECT  FROM fe_users WHERE username NOT IN ('david', 'martin')
\nn\t3::Db()->findNotIn('fe_users', 'username', ['david', 'martin']);
Copied!
@param string $table
@param string $colName
@param array $values
@param boolean $ignoreEnableFields
@return array

Source Code 

public function findNotIn( $table = '', $colName = '', $values = [], $ignoreEnableFields = false )
{
	$queryBuilder = $this->getQueryBuilder( $table );
	$queryBuilder->select('*')->from( $table );
	// Alle Einschränkungen z.B. hidden oder starttime / endtime entfernen?
	if ($ignoreEnableFields) {
		$queryBuilder->getRestrictions()->removeAll();
	}
	// "deleted" IMMER berücksichtigen!
	if ($deleteCol = $this->getDeleteColumn( $table )) {
		$queryBuilder->andWhere( $queryBuilder->expr()->eq($deleteCol, 0) );
	}
	$values = $this->quote( $values );
	$expr = $queryBuilder->expr()->notIn( $colName, $values );
	$queryBuilder->andWhere( $expr );
	$rows = $queryBuilder->executeQuery()->fetchAllAssociative();
	return $rows;
}
Copied!

Db::findOneByValues() 

\nn\t3::Db()->findOneByValues($table = NULL, $whereArr = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = []); 

Findet EINEN Eintrag anhand von gewünschten Feld-Werten.

// SELECT  FROM fe_users WHERE email = 'david@99grad.de'
\nn\t3::Db()->findOneByValues('fe_users', ['email'=>'david@99grad.de']);

// SELECT  FROM fe_users WHERE firstname = 'david' AND username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john']);

// SELECT  FROM fe_users WHERE firstname = 'david' OR username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john'], true);

// SELECT uid, name FROM fe_users WHERE firstname = 'david' OR username = 'john'
\nn\t3::Db()->findOneByValues('fe_users', ['firstname'=>'david', 'username'=>'john'], true, false, ['uid', 'name']);
Copied!
@param string $table
@param array $whereArr
@param boolean $useLogicalOr
@param boolean $ignoreEnableFields
@param array $fieldsToGet
@return array

Source Code 

public function findOneByValues( $table = null, $whereArr = [], $useLogicalOr = false, $ignoreEnableFields = false, $fieldsToGet = [] )
{
	$additionalQueryParams = [
		'limit' => 1
	];
	$result = $this->findByValues( $table, $whereArr, $useLogicalOr, $ignoreEnableFields, $fieldsToGet, $additionalQueryParams );
	return $result ? array_shift($result) : [];
}
Copied!

Db::fixFileReferencesForModel() 

\nn\t3::Db()->fixFileReferencesForModel($model); 

"Repariert" die SysFileReferences für Modelle, die eine Property haben, die statt einer ObjectStorage<FileReference> nur eine FileReference referenzieren. Zum aktuellen Zeitpunkt ist es unklar, weshalb TYPO3 diese zwar in der Tabelle sys_file_reference persistiert, aber das Feld tablenames leert – bzw. uid_foreign nicht setzt. Bei einer ObjectStorage<FileReference> tritt das Problem nicht auf.

// muss direkt nach dem persistieren des Models passieren
\nn\t3::Db()->fixFileReferencesForModel( $model );
Copied!

Source Code 

public function fixFileReferencesForModel( $model )
{
	$props = \nn\t3::Obj()->getProps( $model );
	$modelTableName = \nn\t3::Obj()->getTableName( $model );
	foreach ($props as $field=>$prop) {
		if (is_a($prop, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class, true)) {
			$sysFile = \nn\t3::Obj()->get($model, $field);
			if (!$sysFile) continue;
			$resource = $sysFile->getOriginalResource();
			$uid = $resource->getUid();
			if (!$uid) {
				$result = $this->insert($sysFile);
				$uid = $result->getUid();
			}
			if (!$resource) continue;
			$uidForeign =  $resource->getProperty('uid_foreign');
			$tableName = $resource->getProperty('tablenames');
			if (!$uidForeign || !$tableName) {
				$this->update('sys_file_reference', [
					'uid_foreign'	=> $model->getUid(),
					'tablenames'	=> $modelTableName,
				], $uid);
			}
		}
	}
}
Copied!

Db::get() 

\nn\t3::Db()->get($uid, $modelType = '', $ignoreEnableFields = false); 

Ein oder mehrere Domain-Model/Entity anhand einer uid holen. Es kann eine einzelne $uid oder eine Liste von $uids übergeben werden.

Liefert das "echte" Model/Object inklusive aller Relationen, analog zu einer Query über das Repository.

// Ein einzelnes Model anhand seiner uid holen
$model = \nn\t3::Db()->get( 1, \Nng\MyExt\Domain\Model\Name::class );

// Ein Array an Models anhand ihrer uids holen
$modelArray = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Name::class );

// Gibt auch hidden Models zurück
$modelArrayWithHidden = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Name::class, true );
Copied!
@param int $uid
@param string $modelType
@param boolean $ignoreEnableFields
@return Object

Source Code 

public function get( $uid, $modelType = '', $ignoreEnableFields = false)
{
	if (!is_array($uid)) {
		$persistenceManager = \nn\t3::injectClass( PersistenceManager::class );
		$entity = $persistenceManager->getObjectByIdentifier($uid, $modelType, false);
		return $entity;
	}
	$dataMapper = \nn\t3::injectClass(DataMapper::class);
	$tableName = $this->getTableNameForModel( $modelType);
	$rows = $this->findByUids( $tableName, $uid, $ignoreEnableFields );
	return $dataMapper->map( $modelType, $rows);
}
Copied!

Db::getColumn() 

\nn\t3::Db()->getColumn($table = '', $colName = '', $useSchemaManager = false); 

Eine Tabellen-Spalte (TCA) für bestimmte Tabelle holen

\nn\t3::Db()->getColumn( 'tablename', 'fieldname' );
Copied!
@param string $table
@param string $colName
@param boolean $useSchemaManager
@return array

Source Code 

public function getColumn ( $table = '', $colName = '', $useSchemaManager = false )
{
	$cols = $this->getColumns( $table, $useSchemaManager );
	return $cols[$colName] ?? [];
}
Copied!

Db::getColumnLabel() 

\nn\t3::Db()->getColumnLabel($column = '', $table = ''); 

Lokalisiertes Label eines bestimmten TCA Feldes holen

@param string $column
@param string $table
@return string

Source Code 

public function getColumnLabel ( $column = '', $table = '' )
{
	$tca = $this->getColumns( $table );
	$label = $tca[$column]['label'] ?? '';
	if ($label && ($LL = LocalizationUtility::translate($label))) return $LL;
	return $label;
}
Copied!

Db::getColumns() 

\nn\t3::Db()->getColumns($table = '', $useSchemaManager = false); 

Alle Tabellen-Spalten (TCA) für bestimmte Tabelle holen

// Felder anhand des TCA-Arrays holen
\nn\t3::Db()->getColumns( 'tablename' );

// Felder über den SchemaManager ermitteln
\nn\t3::Db()->getColumns( 'tablename', true );
Copied!
@param string $table
@param boolean $useSchemaManager
@return array

Source Code 

public function getColumns ( $table = '', $useSchemaManager = false )
{
	$cols = isset($GLOBALS['TCA'][$table]) ? $GLOBALS['TCA'][$table]['columns'] : [];
	// Diese Felder sind nicht ausdrücklich im TCA, aber für Abfrage legitim
	if ($cols) {
		$cols = \nn\t3::Arrays( $cols )->merge(['uid'=>'uid', 'pid'=>'pid', 'tstamp'=>'tstamp', 'crdate'=>'crdate', 'endtime'=>'endtime', 'starttime'=>'starttime', 'deleted'=>'deleted', 'disable'=>'disable']);
	}
	// Keine cols ermittelt, weil nicht  im TCA registriert – oder Abfrage erzwungen
	if (!$cols || $useSchemaManager) {
		$cols = GeneralUtility::makeInstance(ConnectionPool::class)
			->getConnectionForTable($table)
			->createSchemaManager()
			->listTableColumns($table);
	}
	foreach ($cols as $k=>$v) {
		$cols[GeneralUtility::underscoredToLowerCamelCase($k)] = $v;
	}
	return $cols;
}
Copied!

Db::getColumnsByType() 

\nn\t3::Db()->getColumnsByType($table = '', $colType = '', $useSchemaManager = false); 

Felder einer Tabelle nach einem bestimmten Typ holen

\nn\t3::Db()->getColumnsByType( 'tx_news_domain_model_news', 'slug' );
Copied!
@param string $table
@param string $colType
@param boolean $useSchemaManager
@return array

Source Code 

public function getColumnsByType( $table = '', $colType = '', $useSchemaManager = false )
{
	$cols = $this->getColumns( $table, $useSchemaManager );
	$results = [];
	foreach ($cols as $fieldName=>$col) {
		$type = $col['config']['type'] ?? false;
		$fieldName = GeneralUtility::camelCaseToLowerCaseUnderscored( $fieldName );
		if ($type == $colType) {
			$results[$fieldName] = array_merge(['fieldName'=>$fieldName], $col);
		}
	}
	return $results;
}
Copied!

Db::getConnection() 

\nn\t3::Db()->getConnection(); 

Eine "rohe" Verbindung zur Datenbank holen. Nur in wirklichen Ausnahmefällen sinnvoll.

$connection = \nn\t3::Db()->getConnection();
$connection->fetchAll( 'SELECT  FROM tt_news WHERE 1;' );
Copied!

| @return \TYPO3\CMS\Core\Database\Connection

Source Code 

public function getConnection()
{
	$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
	$connectionName = array_shift($connectionPool->getConnectionNames());
	return $connectionPool->getConnectionByName( $connectionName );
}
Copied!

Db::getDeleteColumn() 

\nn\t3::Db()->getDeleteColumn($table = ''); 

Delete-Column für bestimmte Tabelle holen.

Diese Spalte wird als Flag für gelöschte Datensätze verwendet. Normalerweise: deleted = 1

@param string $table
@return string

Source Code 

public function getDeleteColumn ( $table = '' )
{
	$ctrl = $GLOBALS['TCA'][$table]['ctrl'] ?? [];
	return $ctrl['delete'] ?? false;
}
Copied!

Db::getQueryBuilder() 

\nn\t3::Db()->getQueryBuilder($table = ''); 

QueryBuilder für eine Tabelle holen

$queryBuilder = \nn\t3::Db()->getQueryBuilder( 'fe_users' );
Copied!

Beispiel:

$queryBuilder = \nn\t3::Db()->getQueryBuilder( 'fe_users' );
$queryBuilder->select('name')->from( 'fe_users' );
$queryBuilder->andWhere( $queryBuilder->expr()->eq( 'uid', $queryBuilder->createNamedParameter(12) ));
$rows = $queryBuilder->executeStatement()->fetchAllAssociative();
Copied!
@param string $table
@return QueryBuilder

Source Code 

public function getQueryBuilder( $table = '' )
{
	$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable( $table );
	return $queryBuilder;
}
Copied!

Db::getRepositoryForModel() 

\nn\t3::Db()->getRepositoryForModel($className = NULL); 

Instanz des Repositories für ein Model (oder einen Model-Klassennamen) holen.

\nn\t3::Db()->getRepositoryForModel( \My\Domain\Model\Name::class );
\nn\t3::Db()->getRepositoryForModel( $myModel );
Copied!
@param mixed $className
@return \TYPO3\CMS\Extbase\Persistence\Repository

Source Code 

public function getRepositoryForModel( $className = null )
{
	if (!is_string($className)) $className = get_class($className);
	$repositoryName = \TYPO3\CMS\Core\Utility\ClassNamingUtility::translateModelNameToRepositoryName( $className );
	return \nn\t3::injectClass( $repositoryName );
}
Copied!

Db::getTableNameForModel() 

\nn\t3::Db()->getTableNameForModel($className = NULL); 

Tabellen-Name für ein Model (oder einen Model-Klassennamen) holen. Alias zu \nn\t3::Obj()->getTableName()

// tx_myext_domain_model_entry
\nn\t3::Db()->getTableNameForModel( $myModel );

// tx_myext_domain_model_entry
\nn\t3::Db()->getTableNameForModel( \My\Domain\Model\Name::class );
Copied!
@param mixed $className
@return string

Source Code 

public function getTableNameForModel( $className = null )
{
	return \nn\t3::Obj()->getTableName( $className );
}
Copied!

Db::ignoreEnableFields() 

\nn\t3::Db()->ignoreEnableFields($queryOrRepository, $ignoreStoragePid = true, $ignoreHidden = false, $ignoreDeleted = false, $ignoreStartEnd = false); 

Entfernt Default-Constraints zur StoragePID, hidden und/oder deleted zu einer Query oder Repository.

\nn\t3::Db()->ignoreEnableFields( $entryRepository );
\nn\t3::Db()->ignoreEnableFields( $query );
Copied!

Beispiel für eine Custom Query:

$table = 'tx_myext_domain_model_entry';
$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
$queryBuilder->select('uid','title','hidden')->from( $table );
\nn\t3::Db()->ignoreEnableFields( $queryBuilder, true, true );
$rows = $queryBuilder->executeQuery()->fetchAllAssociative();
Copied!

Sollte das nicht reichen oder zu kompliziert werden, siehe:

\nn\t3::Db()->statement();
Copied!
@param mixed $queryOrRepository
@param boolean $ignoreStoragePid
@param boolean $ignoreHidden
@param boolean $ignoreDeleted
@param boolean $ignoreStartEnd
@return mixed

Source Code 

public function ignoreEnableFields ( $queryOrRepository, $ignoreStoragePid = true, $ignoreHidden = false, $ignoreDeleted = false, $ignoreStartEnd = false )
{
	$isQueryObject = get_class( $queryOrRepository ) == Query::class;
	$isQueryBuilderObject = get_class( $queryOrRepository) == QueryBuilder::class;
	if ($isQueryObject) {
		$query = $queryOrRepository;
	} else if ($isQueryBuilderObject) {
		// s. https://bit.ly/3fFvM18
		$restrictions = $queryOrRepository->getRestrictions();
		if ($ignoreStartEnd) {
			$restrictions->removeByType( \TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction::class );
			$restrictions->removeByType( \TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction::class );
		}
		if ($ignoreHidden) {
			$hiddenRestrictionClass = \nn\t3::injectClass( \TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction::class );
			$restrictions->removeByType( get_class( $hiddenRestrictionClass ) );
		}
		if ($ignoreDeleted) {
			$deletedRestrictionClass = \nn\t3::injectClass( \TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction::class );
			$restrictions->removeByType( get_class($deletedRestrictionClass) );
		}
		return $queryOrRepository;
	} else {
		$query = $queryOrRepository->createQuery();
	}
	$querySettings = $query->getQuerySettings();
	$ignoreHidden = $ignoreHidden === true ? true : $querySettings->getIgnoreEnableFields();
	$ignoreDeleted = $ignoreDeleted === true ? true : $querySettings->getIncludeDeleted();
	$querySettings->setRespectStoragePage( !$ignoreStoragePid );
	$querySettings->setIgnoreEnableFields( $ignoreHidden );
	$querySettings->setIncludeDeleted( $ignoreDeleted );
	if (!$isQueryObject) {
		$queryOrRepository->setDefaultQuerySettings( $querySettings );
	}
	return $query;
}
Copied!

Db::insert() 

\nn\t3::Db()->insert($tableNameOrModel = '', $data = []); 

Datenbank-Eintrag einfügen. Simpel und idiotensicher. Entweder kann der Tabellenname und ein Array übergeben werden - oder ein Domain-Model.

Einfügen eines neuen Datensatzes per Tabellenname und Daten-Array:

$insertArr = \nn\t3::Db()->insert('table', ['bodytext'=>'...']);
Copied!

Einfügen eines neuen Models. Das Repository wird automatisch ermittelt. Das Model wird direkt persistiert.

$model = new \My\Nice\Model();
$persistedModel = \nn\t3::Db()->insert( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@return mixed

Source Code 

public function insert ( $tableNameOrModel = '', $data = [] )
{
	if (\nn\t3::Obj()->isModel( $tableNameOrModel )) {
		$persistenceManager = \nn\t3::injectClass( PersistenceManager::class );
		$persistenceManager->add( $tableNameOrModel );
		$persistenceManager->persistAll();
		$this->fixFileReferencesForModel( $tableNameOrModel );
		return $tableNameOrModel;
	}
	$data = $this->filterDataForTable( $data, $tableNameOrModel );
	$queryBuilder = $this->getQueryBuilder( $tableNameOrModel );
	$queryBuilder->insert( $tableNameOrModel )
		->values($data)->executeStatement();
	$data['uid'] = $queryBuilder->getConnection()->lastInsertId();
	return $data;
}
Copied!

Db::insertMultiple() 

\nn\t3::Db()->insertMultiple($tableName = '', $rows = [], $colOrder = []); 

Mehrere Zeilen in Datenbank einfügen.

use TYPO3\CMS\Core\Database\Connection;

$data = [
    ['title' => 'Eins', 'tstamp'=>123],
    ['title' => 'Zwei', 'tstamp'=>123],
];
$colOrder = [
    'tstamp' => Connection::PARAM_INT,
    'title' => Connection::PARAM_STR,
];

\nn\t3::Db()->insertMultiple('table', $data, $colOrder);
Copied!
@param string $tableName
@param array $rows
@param array $colOrder
@return boolean

Source Code 

public function insertMultiple ( $tableName = '', $rows = [], $colOrder = [] )
{
	$connection = $connection = $this->getConnection();
	if (!$rows) {
		return true;
	}
	$flattened = [];
	foreach ($rows as $row) {
		$insert = [];
		foreach ($colOrder as $col=>$type) {
			$insert[] = $row[$col] ?? '';
		}
		$flattened[] = $insert;
	}
	$result = $connection->bulkInsert(
		$tableName,
		$flattened,
		array_keys( $colOrder ),
		array_values( $colOrder ),
	);
	return $result;
}
Copied!

Db::insertOrUpdate() 

\nn\t3::Db()->insertOrUpdate($tableName, $whereArr = [], $model = []); 

Store an item in the database, but keep it unique by $whereArr = []

$data = [ profileUid: "", entityType: "", entityUid: "",  ... ];
\nn\un::Interaction()->insertOrUpdate( $data );
Copied!
@param int $feUserId
@param array $data
@return array $model

Source Code 

public function insertOrUpdate($tableName, $whereArr = [], $model = [])
{
	// check if entityUid exists
	$exists = $this->findOneByValues($tableName, $whereArr);
	if ($exists) {
		// remove existing entry
		$this->delete($tableName, $whereArr, true);
	}
	return $this->insert($model);
}
Copied!

Db::orderBy() 

\nn\t3::Db()->orderBy($queryOrRepository, $ordering = []); 

Sortierung für ein Repository oder einen Query setzen.

$ordering = ['title' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );

// asc und desc können als synonym verwendet werden
$ordering = ['title' => 'asc'];
$ordering = ['title' => 'desc'];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!

Kann auch zum Sortieren nach einer Liste von Werten (z.B. uids) verwendet werden. Dazu wird ein Array für den Wert des einzelnen orderings übergeben:

$ordering = ['uid' => [3,7,2,1]];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!
@param mixed $queryOrRepository
@param array $ordering
@return mixed

Source Code 

public function orderBy( $queryOrRepository, $ordering = [] )
{
	$isQueryObject = get_class( $queryOrRepository ) == Query::class;
	$isQueryBuilderObject = get_class( $queryOrRepository) == QueryBuilder::class;
	if ($isQueryObject) {
		// ToDo!
	} else if ($isQueryBuilderObject) {
		foreach ($ordering as $colName => $ascDesc) {
			if (is_array($ascDesc)) {
				foreach ($ascDesc as &$v) {
					$v = $queryOrRepository->createNamedParameter( $v );
				}
				$queryOrRepository->add('orderBy', "FIELD({$colName}," . implode(',', $ascDesc) . ')', true );
			} else {
				// 'asc' und 'desc' können als Synonym verwendet werden
				if (strtolower($ascDesc) == 'asc') {
					$ascDesc = \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING;
				}
				if (strtolower($ascDesc) == 'desc') {
					$ascDesc = \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING;
				}
				$queryOrRepository->addOrderBy( $colName, $ascDesc );
			}
		}
	} else {
		$queryOrRepository->setDefaultOrderings( $ordering );
	}
	return $queryOrRepository;
}
Copied!

Db::persistAll() 

\nn\t3::Db()->persistAll(); 

Alles persistieren.

\nn\t3::Db()->persistAll();
Copied!

| @return void

Source Code 

public function persistAll ()
{
	$persistenceManager = \nn\t3::injectClass( PersistenceManager::class );
	$persistenceManager->persistAll();
}
Copied!

Db::quote() 

\nn\t3::Db()->quote($value = ''); 

Ein Ersatz für die mysqli_real_escape_string() Methode.

Sollte nur im Notfall bei Low-Level Queries verwendet werden. Besser ist es, preparedStatements zu verwenden.

Funktioniert nur bei SQL, nicht bei DQL.

$sword = \nn\t3::Db()->quote('test');          // => 'test'
$sword = \nn\t3::Db()->quote("test';SET");        // => 'test\';SET'
$sword = \nn\t3::Db()->quote([1, 'test', '2']);  // => [1, "'test'", '2']
$sword = \nn\t3::Db()->quote('"; DROP TABLE fe_user;#');
Copied!
@param string|array $value
@return string|array

Source Code 

public function quote( $value = '' )
{
	if (is_array($value)) {
		foreach ($value as &$val) {
			if (!is_numeric($val)) {
				$val = $this->quote($val);
			}
		}
		return $value;
	}
	return $this->getConnection()->quote( $value );
}
Copied!

Db::save() 

\nn\t3::Db()->save($tableNameOrModel = '', $data = []); 

Datenbank-Eintrag erstellen ODER einen vorhandenen Datensatz updaten.

Entscheidet selbstständig, ob der Eintrag per UPDATE oder INSERT in die Datenbank eingefügt bzw. ein vorhandener Datensatz aktualisiert werden muss. Die Daten werden direkt persistiert!

Beispiel für Übergabe eines Tabellennamens und eines Arrays:

// keine uid übergeben? Dann INSERT eines neuen Datensatzes
\nn\t3::Db()->save('table', ['bodytext'=>'...']);

// uid übergeben? Dann UPDATE vorhandener Daten
\nn\t3::Db()->save('table', ['uid'=>123, 'bodytext'=>'...']);
Copied!

Beispiel für Übergabe eines Domain-Models:

// neues Model? Wird per $repo->add() eingefügt
$model = new \My\Nice\Model();
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );

// vorhandenes Model? Wird per $repo->update() aktualisiert
$model = $myRepo->findByUid(123);
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@return mixed

Source Code 

public function save( $tableNameOrModel = '', $data = [] )
{
	if (\nn\t3::Obj()->isModel( $tableNameOrModel )) {
		$uid = \nn\t3::Obj()->get( $tableNameOrModel, 'uid' ) ?: null;
		$method = $uid ? 'update' : 'insert';
	} else {
		$uid = $data['uid'] ?? null;
		$method = ($uid && $this->findByUid( $tableNameOrModel, $uid )) ? 'update' : 'insert';
	}
	return $this->$method( $tableNameOrModel, $data );
}
Copied!

Db::setFalConstraint() 

\nn\t3::Db()->setFalConstraint($queryBuilder = NULL, $tableName = '', $falFieldName = '', $numFal = true, $operator = false); 

Constraint für sys_file_reference zu einem QueryBuilder hinzufügen. Beschränkt die Ergebnisse darauf, ob es eine FAL-Relation gibt.

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );

// Nur Datensätze holen, die für falfield mindestes eine SysFileReference haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield' );

// ... die KEINE SysFileReference für falfield haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', false );

// ... die GENAU 2 SysFileReferences haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2 );

// ... die 2 oder weniger (less than or equal) SysFileReferences haben
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2, 'lte' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder
@param string $tableName
@param string $falFieldName
@param boolean $numFal
@param boolean $operator
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

Source Code 

public function setFalConstraint( &$queryBuilder = null, $tableName = '', $falFieldName = '', $numFal = true, $operator = false )
{
	if ($operator === false) {
		if ($numFal === 0 || $numFal === 1) {
			$operator = 'eq';
		}
		if ($numFal === true) 	{
			$numFal = 1;
			$operator = 'gte';
		}
		if ($numFal === false) 	{
			$numFal = 0;
		}
	}
	if ($operator === false) {
		$operator = 'eq';
	}
	$groupName = 'cnt_' . preg_replace('[^a-zA-Z0-1]', '', $falFieldName);
	$subQuery = $this->getQueryBuilder( 'sys_file_reference' )
		->selectLiteral('COUNT(s.uid)')
		->from('sys_file_reference', 's')
		->andWhere($queryBuilder->expr()->eq('s.fieldname', $queryBuilder->createNamedParameter($falFieldName)))
		->andWhere($queryBuilder->expr()->eq('s.uid_foreign', $queryBuilder->quoteIdentifier($tableName.'.uid')))
		->getSql();
	$queryBuilder
		->addSelectLiteral("({$subQuery}) AS {$groupName}")
		->having( $queryBuilder->expr()->{$operator}($groupName, $numFal) );
	return $queryBuilder;
}
Copied!

Db::setNotInSysCategoryConstraint() 

\nn\t3::Db()->setNotInSysCategoryConstraint($queryBuilder = NULL, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories'); 

Contraint auf Datensätze beschränken, die NICHT in eine der angegebenen Kategorien sind. Gegenteil und Alias zu \nn\t3::Db()->setSysCategoryConstraint()

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
\nn\t3::Db()->setNotInSysCategoryConstraint( $queryBuilder, [1,3,4], 'tx_myext_tablename', 'categories' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder
@param array $sysCategoryUids
@param string $tableName
@param string $categoryFieldName
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

Source Code 

public function setNotInSysCategoryConstraint( &$queryBuilder = null, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories' )
{
	return $this->setSysCategoryConstraint( $queryBuilder, $sysCategoryUids, $tableName, $categoryFieldName, true );
}
Copied!

Db::setSysCategoryConstraint() 

\nn\t3::Db()->setSysCategoryConstraint($queryBuilder = NULL, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories', $useNotIn = false); 

Constraint für sys_category / sys_category_record_mm zu einem QueryBuilder hinzufügen. Beschränkt die Ergebnisse auf die angegebenen Sys-Categories-UIDs.

$queryBuilder = \nn\t3::Db()->getQueryBuilder( $table );
\nn\t3::Db()->setSysCategoryConstraint( $queryBuilder, [1,3,4], 'tx_myext_tablename', 'categories' );
Copied!
@param \TYPO3\CMS\Core\Database\Query\QueryBuilder $querybuilder
@param array $sysCategoryUids
@param string $tableName
@param string $categoryFieldName
@param boolean $useNotIn
@return \TYPO3\CMS\Core\Database\Query\QueryBuilder

Source Code 

public function setSysCategoryConstraint ( &$queryBuilder = null, $sysCategoryUids = [], $tableName = '', $categoryFieldName = 'categories', $useNotIn = false )
{
	if (!$sysCategoryUids) return $queryBuilder;
	$and = [
		$queryBuilder->expr()->eq('categoryMM.tablenames', $queryBuilder->expr()->literal($tableName)),
		$queryBuilder->expr()->eq('categoryMM.fieldname', $queryBuilder->expr()->literal($categoryFieldName))
	];
	if (!$useNotIn) {
		$and[] = $queryBuilder->expr()->in( 'categoryMM.uid_local', $sysCategoryUids );
		$queryBuilder->andWhere(...$and);
	} else {
		$and[] = $queryBuilder->expr()->notIn('categoryMM.uid_local', $sysCategoryUids);
		$queryBuilder->andWhere(
			$queryBuilder->expr()->orX(
				$queryBuilder->expr()->isNull('categoryMM.uid_foreign'),
				$queryBuilder->expr()->andX(...$and)
			)
		);
	}
	$queryBuilder->leftJoin(
		$tableName,
		'sys_category_record_mm',
		'categoryMM',
		$queryBuilder->expr()->eq('categoryMM.uid_foreign', $tableName . '.uid')
	)->groupBy('uid');
	return $queryBuilder;
}
Copied!

Db::sortBy() 

\nn\t3::Db()->sortBy($objectArray, $fieldName = 'uid', $uidList = []); 

Sortiert Ergebnisse eines Queries nach einem Array und bestimmten Feld. Löst das Problem, dass eine ->in()-Query die Ergebnisse nicht in der Reihenfolge der übergebenen IDs liefert. Beispiel: | $query->matching($query->in('uid', [3,1,2])); kommt nicht zwingend in der Reihenfolge [3,1,2] zurück.

$insertArr = \nn\t3::Db()->sortBy( $storageOrArray, 'uid', [2,1,5]);
Copied!
@param mixed $objectArray
@param string $fieldName
@param array $uidList
@return array

Source Code 

public function sortBy ( $objectArray, $fieldName = 'uid', $uidList = [] )
{
	if (method_exists( $objectArray, 'toArray')) {
		$objectArray = $objectArray->toArray();
	}
	usort( $objectArray, function ($a, $b) use ( $uidList, $fieldName ) {
		$p1 = array_search( \nn\t3::Obj()->accessSingleProperty($a, $fieldName), $uidList );
		$p2 = array_search( \nn\t3::Obj()->accessSingleProperty($b, $fieldName), $uidList );
		return $p1 > $p2 ? 1 : -1;
	});
	return $objectArray;
}
Copied!

Db::statement() 

\nn\t3::Db()->statement($statement = '', $params = [], $types = []); 

Eine "rohe" Query an die Datenbank absetzen. Näher an der Datenbank geht nicht. Du bist für alles selbst verantwortlich. Injections steht nur Deine (hoffentlich ausreichende :) Intelligenz entgegen.

Hilft z.B. bei Abfragen von Tabellen, die nicht Teil der Typo3 Installation sind und daher über den normal QueryBuilder nicht erreicht werden könnten.

// Variablen IMMER über escapen!
$keyword = \nn\t3::Db()->quote('suchbegriff');
$rows = \nn\t3::Db()->statement( "SELECT  FROM tt_news WHERE bodytext LIKE '%{$keyword}%'");

// oder besser gleich prepared statements verwenden:
$rows = \nn\t3::Db()->statement( 'SELECT  FROM tt_news WHERE bodytext LIKE :str', ['str'=>"%{$keyword}%"] );

// Typen können übergeben werden (bei Array wird das automatisch ermittelt)
$rows = \nn\t3::Db()->statement( 'SELECT  FROM tt_news WHERE uid IN (:uids)', ['uids'=>[1,2,3]], ['uids'=>Connection::PARAM_INT_ARRAY] );
Copied!

Bei einem SELECT Statement werden die Zeilen aus der Datenbank als Array zurückgegeben. Bei allen anderen Statements (z.B. UPDATE oder DELETE) wird die Anzahl der betroffenen Zeilen zurückgegeben.

@param string $statement
@param array $params
@param array $types
@return mixed

Source Code 

public function statement( $statement = '', $params = [], $types = [] )
{
	$connection = $this->getConnection();
	// exec / fetchAll --> @siehe https://bit.ly/3ltPF0S
	// set types automatically if params were used
	foreach ($params as $key=>$val) {
		// was type defined in arguments? then skip
		if (isset($types[$key])) {
			continue;
		}
		// type not defined - and not array? then add type
		if (!is_array($val)) {
			if (is_numeric($val)) {
				$types[$key] = Connection::PARAM_INT;
			} else {
				$types[$key] = Connection::PARAM_STR;
			}
			continue;
		}
		// type not defined and array?
		$allNumeric = count(array_filter($val, 'is_numeric')) === count($val);
		$types[$key] = $allNumeric ? Connection::PARAM_INT_ARRAY : Connection::PARAM_STR_ARRAY;
	}
	if (stripos($statement, 'select ') !== false) {
		$result = $connection->fetchAllAssociative( $statement, $params, $types );
	} else {
		$result = $connection->executeStatement( $statement, $params, $types );
	}
	return $result;
}
Copied!

Db::tableExists() 

\nn\t3::Db()->tableExists($table = ''); 

Existiert eine bestimmte DB-Tabelle?

$exists = \nn\t3::Db()->tableExists('table');
Copied!

| @return boolean

Source Code 

public function tableExists ( $table = '' )
{
	return isset($GLOBALS['TCA'][$table]);
}
Copied!

Db::truncate() 

\nn\t3::Db()->truncate($table = ''); 

Datenbank-Tabelle leeren. Löscht alle Einträge in der angegebenen Tabelle und setzt den Auto-Increment-Wert auf 0 zurück.

\nn\t3::Db()->truncate('table');
Copied!
@param string $table
@return boolean

Source Code 

public function truncate ( $table = '' )
{
	$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable( $table );
	return $connection->truncate( $table );
}
Copied!

Db::undelete() 

\nn\t3::Db()->undelete($table = '', $constraint = []); 

Gelöschten Datenbank-Eintrag wiederherstellen. Dazu wird der Flag für "gelöscht" (deleted) wieder auf 0 gesetzt wird.

\nn\t3::Db()->undelete('table', $uid);
\nn\t3::Db()->undelete('table', ['uid_local'=>$uid]);
Copied!
@param string $table
@param array $constraint
@return boolean

Source Code 

public function undelete ( $table = '', $constraint = [] )
{
	if (!$constraint) return false;
	if (is_numeric($constraint)) {
		$constraint = ['uid' => $constraint];
	}
	if ($deleteColumn = $this->getDeleteColumn( $table )) {
		return $this->update( $table, [$deleteColumn => 0], $constraint );
	}
	return false;
}
Copied!

Db::update() 

\nn\t3::Db()->update($tableNameOrModel = '', $data = [], $uid = NULL); 

Datenbank-Eintrag aktualisieren. Schnell und einfach. Das Update kann entweder per Tabellenname und Daten-Array passieren. Oder man übergibt ein Model.

Beispiele:

// UPDATES table SET title='new' WHERE uid=1
\nn\t3::Db()->update('table', ['title'=>'new'], 1);

// UPDATES table SET title='new' WHERE uid IN (1,2,3)
\nn\t3::Db()->update('table', ['title'=>'new'], ['uid'=>[1,2,3]);

// UPDATE table SET title='new' WHERE email='david@99grad.de' AND pid=12
\nn\t3::Db()->update('table', ['title'=>'new'], ['email'=>'david@99grad.de', 'pid'=>12, ...]);
Copied!

Mit true statt einer $uid werden ALLE Datensätze der Tabelle geupdated.

// UPDATE table SET test='1' WHERE 1
\nn\t3::Db()->update('table', ['test'=>1], true);
Copied!

Statt einem Tabellenname kann auch ein einfach Model übergeben werden. Das Repository wird automatisch ermittelt und das Model direkt persistiert.

$model = $myRepo->findByUid(1);
\nn\t3::Db()->update( $model );
Copied!
@param mixed $tableNameOrModel
@param array $data
@param int $uid
@return mixed

Source Code 

public function update ( $tableNameOrModel = '', $data = [], $uid = null )
{
	if (\nn\t3::Obj()->isModel( $tableNameOrModel )) {
		$persistenceManager = \nn\t3::injectClass( PersistenceManager::class );
		$persistenceManager->update( $tableNameOrModel );
		$persistenceManager->persistAll();
		$this->fixFileReferencesForModel( $tableNameOrModel );
		return $tableNameOrModel;
	}
	$queryBuilder = $this->getQueryBuilder( $tableNameOrModel );
	$queryBuilder->getRestrictions()->removeAll();
	$queryBuilder->update( $tableNameOrModel );
	$data = $this->filterDataForTable( $data, $tableNameOrModel );
	if (!$data) return false;
	foreach ($data as $k=>$v) {
		$queryBuilder->set( $k, $v );
	}
	if ($uid === null) {
		$uid = $data['uid'] ?? null;
	}
	if ($uid !== true) {
		if (is_numeric($uid)) {
			$uid = ['uid' => $uid];
		}
		foreach ($uid as $k=>$v) {
			if (is_array($v)) {
				$v = $this->quote( $v );
				$queryBuilder->andWhere(
					$queryBuilder->expr()->in( $k, $queryBuilder->createNamedParameter($v, Connection::PARAM_STR_ARRAY) )
				);
			} else {
				$queryBuilder->andWhere(
					$queryBuilder->expr()->eq( $k, $queryBuilder->createNamedParameter($v) )
				);
			}
		}
	}
	return $queryBuilder->executeStatement();
}
Copied!

Dom 

\nn\t3::Dom() 

Manipulieren von DOM und XML. Noch in Arbeit :)

Overview of Methods 

\nn\t3::Dom()->absPrefix($html, $attributes = [], $baseUrl = ''); 

Ersetzt Links und Pfade zu Bildern etc. im Quelltext mit absoluter URL z.B. für den Versand von Mails | @return string

| ➜ Go to source code of Dom::absPrefix()

Methods 

Dom::absPrefix() 

\nn\t3::Dom()->absPrefix($html, $attributes = [], $baseUrl = ''); 

Ersetzt Links und Pfade zu Bildern etc. im Quelltext mit absoluter URL z.B. für den Versand von Mails | @return string

Source Code 

public function absPrefix( $html, $attributes = [], $baseUrl = '' ) {
	if (!$baseUrl) $baseUrl = \nn\t3::Environment()->getBaseUrl();
	if (!$attributes) $attributes = ['href', 'src'];
	$dom = new \DOMDocument();
	@$dom->loadHTML($html);
	$xpath = new \DOMXPath($dom);
	foreach ($attributes as $attr) {
		$nodes = $xpath->query('//*[@'.$attr.']');
		foreach ($nodes as $node) {
			if ($val = ltrim($node->getAttribute($attr), '/')) {
				if (strpos($val, ':') === false && $val != '#') {
					$node->setAttribute($attr, $baseUrl . $val);
				}
			}
		}
	}
	return $dom->saveHTML();
}
Copied!

Encrypt 

\nn\t3::Encrypt() 

Verschlüsseln und Hashen von Passworten

Overview of Methods 

\nn\t3::Encrypt()->checkPassword($password = '', $passwordHash = NULL); 

Prüft, ob Hash eines Passwortes und ein Passwort übereinstimmen. Anwendung: Passwort-Hash eines fe_users in der Datenbank mit übergebenem Passwort vergleichen.

\nn\t3::Encrypt()->checkPassword('99grad', '$1$wtnFi81H$mco6DrrtdeqiziRJyisdK1.');
Copied!

| @return boolean

| ➜ Go to source code of Encrypt::checkPassword()

\nn\t3::Encrypt()->createJwtSignature($header = [], $payload = []); 

Signatur für ein JWT (Json Web Token) erzeugen. Die Signatur wird später als Teil des Tokens mit vom User übertragen.

$signature = \nn\t3::Encrypt()->createJwtSignature(['alg'=>'HS256', 'typ'=>'JWT'], ['test'=>123]);
Copied!
@param array $header
@param array $payload
@return string

| ➜ Go to source code of Encrypt::createJwtSignature()

\nn\t3::Encrypt()->decode($data = ''); 

Entschlüsselt einen String oder ein Array. Zum Verschlüsseln der Daten kann \nn\t3::Encrypt()->encode() verwendet werden. Siehe \nn\t3::Encrypt()->encode() für ein komplettes Beispiel.

\nn\t3::Encrypt()->decode( '...' );
Copied!

| @return string

| ➜ Go to source code of Encrypt::decode()

\nn\t3::Encrypt()->encode($data = ''); 

Verschlüsselt einen String oder ein Array.

Im Gegensatz zu \nn\t3::Encrypt()->hash() kann ein verschlüsselter Wert per \nn\t3::Encrypt()->decode() wieder entschlüsselt werden. Diese Methods eignet sich daher nicht, um sensible Daten wie z.B. Passworte in einer Datenbank zu speichern. Dennoch ist der Schutz relativ hoch, da selbst identische Daten, die mit dem gleichen Salting-Key verschlüsselt wurden, unterschiedlich aussehen.

Für die Verschlüsselung wird ein Salting Key generiert und in dem Extension Manager von nnhelpers gespeichert. Dieser Key ist für jede Installation einmalig. Wird er verändert, dann können bereits verschlüsselte Daten nicht wieder entschlüsselt werden.

\nn\t3::Encrypt()->encode( 'mySecretSomething' );
\nn\t3::Encrypt()->encode( ['some'=>'secret'] );
Copied!

Komplettes Beispiel mit Verschlüsselung und Entschlüsselung:

$encryptedResult = \nn\t3::Encrypt()->encode( ['password'=>'mysecretsomething'] );
echo \nn\t3::Encrypt()->decode( $encryptedResult )['password'];

$encryptedResult = \nn\t3::Encrypt()->encode( 'some_secret_phrase' );
echo \nn\t3::Encrypt()->decode( $encryptedResult );
Copied!

| @return string

| ➜ Go to source code of Encrypt::encode()

\nn\t3::Encrypt()->getHashInstance($passwordHash = '', $loginType = 'FE'); 

Gibt den Klassen-Names des aktuellen Hash-Algorithmus eines verschlüsselten Passwortes wieder, z.B. um beim fe_user zu wissen, wie das Passwort in der DB verschlüsselt wurde.

\nn\t3::Encrypt()->getHashInstance('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.');
// => \TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash
Copied!

| @return class

| ➜ Go to source code of Encrypt::getHashInstance()

\nn\t3::Encrypt()->getSaltingKey(); 

Holt den Enryption / Salting Key aus der Extension Konfiguration für nnhelpers. Falls im Extension Manager noch kein Key gesetzt wurde, wird er automatisch generiert und in der LocalConfiguration.php gespeichert.

\nn\t3::Encrypt()->getSaltingKey();
Copied!

| @return string

| ➜ Go to source code of Encrypt::getSaltingKey()

\nn\t3::Encrypt()->hash($string = ''); 

Einfaches Hashing, z.B. beim Check einer uid gegen ein Hash.

\nn\t3::Encrypt()->hash( $uid );
Copied!

Existiert auch als ViewHelper:

{something->nnt3:encrypt.hash()}
Copied!

| @return string

| ➜ Go to source code of Encrypt::hash()

\nn\t3::Encrypt()->hashNeedsUpdate($passwordHash = '', $loginType = 'FE'); 

Prüft, ob Hash aktualisiert werden muss, weil er nicht dem aktuellen Verschlüsselungs-Algorithmus enspricht. Beim Update von Typo3 in eine neue LTS wird gerne auch der Hashing-Algorithmus der Passwörter in der Datenbank verbessert. Diese Methode prüft, ob der übergebene Hash noch aktuell ist oder aktualisert werden muss.

Gibt true zurück, falls ein Update erforderlich ist.

\nn\t3::Encrypt()->hashNeedsUpdate('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.');  // true
Copied!

Ein automatisches Update des Passwortes könnte in einem manuellen FE-User Authentification-Service so aussehen:

$uid = $user['uid'];  // uid des FE-Users
$authResult = \nn\t3::Encrypt()->checkPassword( $passwordHashInDatabase, $clearTextPassword );
if ($authResult & \nn\t3::Encrypt()->hashNeedsUpdate( $passwordHashInDatabase )) {
    \nn\t3::FrontendUserAuthentication()->setPassword( $uid, $clearTextPassword );
}
Copied!

| @return boolean

| ➜ Go to source code of Encrypt::hashNeedsUpdate()

\nn\t3::Encrypt()->hashSessionId($sessionId = NULL); 

Session-Hash für fe_sessions.ses_id holen. Enspricht dem Wert, der für den Cookie fe_typo_user in der Datenbank gespeichert wird.

In TYPO3 < v10 wird hier ein unveränderter Wert zurückgegeben. Ab TYPO3 v10 wird die Session-ID im Cookie fe_typo_user nicht mehr direkt in der Datenbank gespeichert, sondern gehashed. Siehe: TYPO3\CMS\Core\Session\Backend\DatabaseSessionBackend->hash().

\nn\t3::Encrypt()->hashSessionId( $sessionIdFromCookie );
Copied!

Beispiel:

$cookie = $_COOKIE['fe_typo_user'];
$hash = \nn\t3::Encrypt()->hashSessionId( $cookie );
$sessionFromDatabase = \nn\t3::Db()->findOneByValues('fe_sessions', ['ses_id'=>$hash]);
Copied!

Wird unter anderen verwendet von: \nn\t3::FrontendUserAuthentication()->loginBySessionId().

| @return string

| ➜ Go to source code of Encrypt::hashSessionId()

\nn\t3::Encrypt()->jwt($payload = []); 

Ein JWT (Json Web Token) erzeugen, signieren und base64-Encoded zurückgeben.

Nicht vergessen: Ein JWT ist zwar "fälschungssicher", weil der Signatur-Hash nur mit dem korrekten Key/Salt erzeugt werden kann – aber alle Daten im JWT sind für jeden durch base64_decode() einsehbar. Ein JWT eignet sich keinesfalls, um sensible Daten wie Passwörter oder Logins zu speichern!

\nn\t3::Encrypt()->jwt(['test'=>123]);
Copied!
@param array $payload
@return string

| ➜ Go to source code of Encrypt::jwt()

\nn\t3::Encrypt()->parseJwt($token = ''); 

Ein JWT (Json Web Token) parsen und die Signatur überprüfen. Falls die Signatur valide ist (und damit der Payload nicht manipuliert wurde), wird der Payload zurückgegeben. Bei ungültiger Signatur wird FALSE zurückgegeben.

\nn\t3::Encrypt()->parseJwt('adhjdf.fsdfkjds.HKdfgfksfdsf');
Copied!
@param string $token
@return array|false

| ➜ Go to source code of Encrypt::parseJwt()

\nn\t3::Encrypt()->password($clearTextPassword = '', $context = 'FE'); 

Hashing eines Passwortes nach Typo3-Prinzip. Anwendung: Passwort eines fe_users in der Datenbank überschreiben

\nn\t3::Encrypt()->password('99grad');
Copied!

| @return string

| ➜ Go to source code of Encrypt::password()

Methods 

Encrypt::checkPassword() 

\nn\t3::Encrypt()->checkPassword($password = '', $passwordHash = NULL); 

Prüft, ob Hash eines Passwortes und ein Passwort übereinstimmen. Anwendung: Passwort-Hash eines fe_users in der Datenbank mit übergebenem Passwort vergleichen.

\nn\t3::Encrypt()->checkPassword('99grad', '$1$wtnFi81H$mco6DrrtdeqiziRJyisdK1.');
Copied!

| @return boolean

Source Code 

public function checkPassword ( $password = '', $passwordHash = null )
{
	if ($passwordHash === null || $passwordHash === '') {
		return false;
	}
	// siehe localConfiguration.php [FE][passwordHashing][className], default für Typo3 9 ist \TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash
	$hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->getDefaultHashInstance('FE');
	$result = $hashInstance->checkPassword($password, $passwordHash);
	if ($result) return true;
	// Fallback für Passworte, die nach Update auf Typo3 9 noch den md5-Hash oder andere verwenden
	if ($hashInstance = $this->getHashInstance( $passwordHash )) {
		$result = $hashInstance->checkPassword($password, $passwordHash);
		return $result;
	}
	return false;
}
Copied!

Encrypt::createJwtSignature() 

\nn\t3::Encrypt()->createJwtSignature($header = [], $payload = []); 

Signatur für ein JWT (Json Web Token) erzeugen. Die Signatur wird später als Teil des Tokens mit vom User übertragen.

$signature = \nn\t3::Encrypt()->createJwtSignature(['alg'=>'HS256', 'typ'=>'JWT'], ['test'=>123]);
Copied!
@param array $header
@param array $payload
@return string

Source Code 

public function createJwtSignature( $header = [], $payload = [] ) {
	return hash_hmac(
		'sha256',
		base64_encode(json_encode($header)) . '.' . base64_encode(json_encode($payload)),
		$this->getSaltingKey()
	);
}
Copied!

Encrypt::decode() 

\nn\t3::Encrypt()->decode($data = ''); 

Entschlüsselt einen String oder ein Array. Zum Verschlüsseln der Daten kann \nn\t3::Encrypt()->encode() verwendet werden. Siehe \nn\t3::Encrypt()->encode() für ein komplettes Beispiel.

\nn\t3::Encrypt()->decode( '...' );
Copied!

| @return string

Source Code 

public function decode( $data = '' ) {
	[$key1, $key2] = json_decode(base64_decode( $this->getSaltingKey() ), true);
	$mix = base64_decode($data);
	$method = self::ENCRYPTION_METHOD;
	$iv_length = openssl_cipher_iv_length($method);
	$iv = substr($mix, 0, $iv_length);
	$second_encrypted = substr($mix, $iv_length, 64);
	$first_encrypted = substr($mix, $iv_length + 64);
	$data = openssl_decrypt($first_encrypted, $method, base64_decode($key1), OPENSSL_RAW_DATA, $iv);
	$second_encrypted_new = hash_hmac(self::ENCRYPTION_HMAC, $first_encrypted, base64_decode($key2), TRUE);
	if (hash_equals($second_encrypted, $second_encrypted_new)) {
		$data = json_decode( $data, true );
		return $data['_'] ?? null;
	}
	return false;
}
Copied!

Encrypt::encode() 

\nn\t3::Encrypt()->encode($data = ''); 

Verschlüsselt einen String oder ein Array.

Im Gegensatz zu \nn\t3::Encrypt()->hash() kann ein verschlüsselter Wert per \nn\t3::Encrypt()->decode() wieder entschlüsselt werden. Diese Methods eignet sich daher nicht, um sensible Daten wie z.B. Passworte in einer Datenbank zu speichern. Dennoch ist der Schutz relativ hoch, da selbst identische Daten, die mit dem gleichen Salting-Key verschlüsselt wurden, unterschiedlich aussehen.

Für die Verschlüsselung wird ein Salting Key generiert und in dem Extension Manager von nnhelpers gespeichert. Dieser Key ist für jede Installation einmalig. Wird er verändert, dann können bereits verschlüsselte Daten nicht wieder entschlüsselt werden.

\nn\t3::Encrypt()->encode( 'mySecretSomething' );
\nn\t3::Encrypt()->encode( ['some'=>'secret'] );
Copied!

Komplettes Beispiel mit Verschlüsselung und Entschlüsselung:

$encryptedResult = \nn\t3::Encrypt()->encode( ['password'=>'mysecretsomething'] );
echo \nn\t3::Encrypt()->decode( $encryptedResult )['password'];

$encryptedResult = \nn\t3::Encrypt()->encode( 'some_secret_phrase' );
echo \nn\t3::Encrypt()->decode( $encryptedResult );
Copied!

| @return string

Source Code 

public function encode( $data = '' ) {
	[$key1, $key2] = json_decode(base64_decode( $this->getSaltingKey() ), true);
	$data = json_encode(['_'=>$data]);
	$method = self::ENCRYPTION_METHOD;
	$iv_length = openssl_cipher_iv_length($method);
	$iv = openssl_random_pseudo_bytes($iv_length);
	$first_encrypted = openssl_encrypt($data, $method, base64_decode($key1), OPENSSL_RAW_DATA, $iv);
	$second_encrypted = hash_hmac(self::ENCRYPTION_HMAC, $first_encrypted, base64_decode($key2), TRUE);
	$output = base64_encode($iv . $second_encrypted . $first_encrypted);
	return $output;
}
Copied!

Encrypt::getHashInstance() 

\nn\t3::Encrypt()->getHashInstance($passwordHash = '', $loginType = 'FE'); 

Gibt den Klassen-Names des aktuellen Hash-Algorithmus eines verschlüsselten Passwortes wieder, z.B. um beim fe_user zu wissen, wie das Passwort in der DB verschlüsselt wurde.

\nn\t3::Encrypt()->getHashInstance('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.');
// => \TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash
Copied!

| @return class

Source Code 

public function getHashInstance( $passwordHash = '', $loginType = 'FE' ) {
	$saltFactory = GeneralUtility::makeInstance(PasswordHashFactory::class);
	$hashInstance = false;
	try {
		$hashInstance = $saltFactory->get( $passwordHash, $loginType );
	} catch (InvalidPasswordHashException $invalidPasswordHashException) {
		// unknown
	}
	return $hashInstance;
}
Copied!

Encrypt::getSaltingKey() 

\nn\t3::Encrypt()->getSaltingKey(); 

Holt den Enryption / Salting Key aus der Extension Konfiguration für nnhelpers. Falls im Extension Manager noch kein Key gesetzt wurde, wird er automatisch generiert und in der LocalConfiguration.php gespeichert.

\nn\t3::Encrypt()->getSaltingKey();
Copied!

| @return string

Source Code 

public function getSaltingKey() {
	if ($key = \nn\t3::Settings()->getExtConf('nnhelpers')['saltingKey'] ?? false) {
		return $key;
	}
	$key = base64_encode(json_encode([
		base64_encode(openssl_random_pseudo_bytes(32)),
		base64_encode(openssl_random_pseudo_bytes(64))
	]));
	if (!\nn\t3::Settings()->setExtConf( 'nnhelpers', 'saltingKey', $key)) {
		\nn\t3::Exception('Please first set the encryption key in the Extension-Manager for nnhelpers!');
	}
	return $key;
}
Copied!

Encrypt::hash() 

\nn\t3::Encrypt()->hash($string = ''); 

Einfaches Hashing, z.B. beim Check einer uid gegen ein Hash.

\nn\t3::Encrypt()->hash( $uid );
Copied!

Existiert auch als ViewHelper:

{something->nnt3:encrypt.hash()}
Copied!

| @return string

Source Code 

public function hash( $string = '' ) {
	$salt = $this->getSaltingKey();
	return preg_replace('/[^a-zA-Z0-9]/', '', base64_encode( sha1("{$string}-{$salt}", true )));
}
Copied!

Encrypt::hashNeedsUpdate() 

\nn\t3::Encrypt()->hashNeedsUpdate($passwordHash = '', $loginType = 'FE'); 

Prüft, ob Hash aktualisiert werden muss, weil er nicht dem aktuellen Verschlüsselungs-Algorithmus enspricht. Beim Update von Typo3 in eine neue LTS wird gerne auch der Hashing-Algorithmus der Passwörter in der Datenbank verbessert. Diese Methode prüft, ob der übergebene Hash noch aktuell ist oder aktualisert werden muss.

Gibt true zurück, falls ein Update erforderlich ist.

\nn\t3::Encrypt()->hashNeedsUpdate('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.');  // true
Copied!

Ein automatisches Update des Passwortes könnte in einem manuellen FE-User Authentification-Service so aussehen:

$uid = $user['uid'];  // uid des FE-Users
$authResult = \nn\t3::Encrypt()->checkPassword( $passwordHashInDatabase, $clearTextPassword );
if ($authResult & \nn\t3::Encrypt()->hashNeedsUpdate( $passwordHashInDatabase )) {
    \nn\t3::FrontendUserAuthentication()->setPassword( $uid, $clearTextPassword );
}
Copied!

| @return boolean

Source Code 

public function hashNeedsUpdate( $passwordHash = '', $loginType = 'FE' ) {
	// Könnte z.B. `TYPO3\CMS\Core\Crypto\PasswordHashing\PhpassPasswordHash` sein
	$currentHashInstance = $this->getHashInstance( $passwordHash );
	// Könnte z.B. `TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash` sein
	$expectedHashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->getDefaultHashInstance( $loginType );
	return get_class($currentHashInstance) != get_class($expectedHashInstance);
}
Copied!

Encrypt::hashSessionId() 

\nn\t3::Encrypt()->hashSessionId($sessionId = NULL); 

Session-Hash für fe_sessions.ses_id holen. Enspricht dem Wert, der für den Cookie fe_typo_user in der Datenbank gespeichert wird.

In TYPO3 < v10 wird hier ein unveränderter Wert zurückgegeben. Ab TYPO3 v10 wird die Session-ID im Cookie fe_typo_user nicht mehr direkt in der Datenbank gespeichert, sondern gehashed. Siehe: TYPO3\CMS\Core\Session\Backend\DatabaseSessionBackend->hash().

\nn\t3::Encrypt()->hashSessionId( $sessionIdFromCookie );
Copied!

Beispiel:

$cookie = $_COOKIE['fe_typo_user'];
$hash = \nn\t3::Encrypt()->hashSessionId( $cookie );
$sessionFromDatabase = \nn\t3::Db()->findOneByValues('fe_sessions', ['ses_id'=>$hash]);
Copied!

Wird unter anderen verwendet von: \nn\t3::FrontendUserAuthentication()->loginBySessionId().

| @return string

Source Code 

public function hashSessionId( $sessionId = null ) {
	$key = sha1(($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] ?? '') . 'core-session-backend');
	return hash_hmac('sha256', $sessionId, $key);
}
Copied!

Encrypt::jwt() 

\nn\t3::Encrypt()->jwt($payload = []); 

Ein JWT (Json Web Token) erzeugen, signieren und base64-Encoded zurückgeben.

Nicht vergessen: Ein JWT ist zwar "fälschungssicher", weil der Signatur-Hash nur mit dem korrekten Key/Salt erzeugt werden kann – aber alle Daten im JWT sind für jeden durch base64_decode() einsehbar. Ein JWT eignet sich keinesfalls, um sensible Daten wie Passwörter oder Logins zu speichern!

\nn\t3::Encrypt()->jwt(['test'=>123]);
Copied!
@param array $payload
@return string

Source Code 

public function jwt( $payload = [] ) {
	$header = [
		'alg' => 'HS256',
		'typ' => 'JWT',
	];
	$signature = $this->createJwtSignature($header, $payload);
	return join('.', [
		base64_encode(json_encode($header)),
		base64_encode(json_encode($payload)),
		base64_encode($signature)
	]);
}
Copied!

Encrypt::parseJwt() 

\nn\t3::Encrypt()->parseJwt($token = ''); 

Ein JWT (Json Web Token) parsen und die Signatur überprüfen. Falls die Signatur valide ist (und damit der Payload nicht manipuliert wurde), wird der Payload zurückgegeben. Bei ungültiger Signatur wird FALSE zurückgegeben.

\nn\t3::Encrypt()->parseJwt('adhjdf.fsdfkjds.HKdfgfksfdsf');
Copied!
@param string $token
@return array|false

Source Code 

public function parseJwt( $token = '' ) {
	if (!$token) return false;
	if (substr($token, 0, 1) == '[') return false;
	$parts = explode('.', $token);
	if (count($parts) < 3) return false;
	$header = json_decode(base64_decode( array_shift($parts)), true);
	$payload = json_decode(base64_decode( array_shift($parts)), true);
	$signature = base64_decode(array_shift($parts));
	$checkSignature = $this->createJwtSignature($header, $payload);
	if ($signature !== $checkSignature) return false;
	$payload['token'] = $token;
	return $payload;
}
Copied!

Encrypt::password() 

\nn\t3::Encrypt()->password($clearTextPassword = '', $context = 'FE'); 

Hashing eines Passwortes nach Typo3-Prinzip. Anwendung: Passwort eines fe_users in der Datenbank überschreiben

\nn\t3::Encrypt()->password('99grad');
Copied!

| @return string

Source Code 

public function password ( $clearTextPassword = '', $context = 'FE' ) {
	$hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->getDefaultHashInstance( $context );
	$saltedPassword = $hashInstance->getHashedPassword( $clearTextPassword );
	return $saltedPassword;
}
Copied!

Environment 

\nn\t3::Environment() 

Alles, was man über die Umgebung der Anwendung wissen muss. Von Sprach-ID des Users, der baseUrl bis zu der Frage, welche Extensions am Start sind.

Overview of Methods 

\nn\t3::Environment()->extLoaded($extName = ''); 

Prüfen, ob Extension geladen ist.

\nn\t3::Environment()->extLoaded('news');
Copied!

| ➜ Go to source code of Environment::extLoaded()

\nn\t3::Environment()->extPath($extName = ''); 

absoluten Pfad zu einer Extension holen z.B. /var/www/website/ext/nnsite/

\nn\t3::Environment()->extPath('extname');
Copied!

| @return string

| ➜ Go to source code of Environment::extPath()

\nn\t3::Environment()->extRelPath($extName = ''); 

relativen Pfad (vom aktuellen Script aus) zu einer Extension holen z.B. ../typo3conf/ext/nnsite/

\nn\t3::Environment()->extRelPath('extname');
Copied!

| @return string

| ➜ Go to source code of Environment::extRelPath()

\nn\t3::Environment()->getBaseURL(); 

Gibt die baseUrl (config.baseURL) zurück, inkl. http(s) Protokoll z.B. https://www.webseite.de/

\nn\t3::Environment()->getBaseURL();
Copied!

| @return string

| ➜ Go to source code of Environment::getBaseURL()

\nn\t3::Environment()->getCookieDomain($loginType = 'FE'); 

Die Cookie-Domain holen z.B. www.webseite.de

\nn\t3::Environment()->getCookieDomain()
Copied!

| @return string

| ➜ Go to source code of Environment::getCookieDomain()

\nn\t3::Environment()->getCountries($lang = 'de', $key = 'cn_iso_2'); 

Alle im System verfügbaren Ländern holen

\nn\t3::Environment()->getCountries();
Copied!

| @return array

| ➜ Go to source code of Environment::getCountries()

\nn\t3::Environment()->getCountryByIsocode($cn_iso_2 = NULL, $field = 'cn_iso_2'); 

Ein Land aus der Tabelle static_countries anhand seines Ländercodes (z.B. DE) holen

\nn\t3::Environment()->getCountryByIsocode( 'DE' );
\nn\t3::Environment()->getCountryByIsocode( 'DEU', 'cn_iso_3' );
Copied!

| @return array

| ➜ Go to source code of Environment::getCountryByIsocode()

\nn\t3::Environment()->getDefaultLanguage($returnKey = 'typo3Language'); 

Gibt die Standard-Sprache (Default Language) zurück. Bei TYPO3 ist das immer die Sprache mit der ID 0. Die Sprachen müssen in der YAML site configuration festgelegt sein.

// 'de'
\nn\t3::Environment()->getDefaultLanguage();

// 'de-DE'
\nn\t3::Environment()->getDefaultLanguage('hreflang');

// ['title'=>'German', 'typo3Language'=>'de', ...]
\nn\t3::Environment()->getDefaultLanguage( true );
Copied!
@param string|boolean $returnKey
@return string|array

| ➜ Go to source code of Environment::getDefaultLanguage()

\nn\t3::Environment()->getDomain(); 

Die Domain holen z.B. www.webseite.de

\nn\t3::Environment()->getDomain();
Copied!

| @return string

| ➜ Go to source code of Environment::getDomain()

\nn\t3::Environment()->getExtConf($ext = 'nnhelpers', $param = ''); 

Configuration aus ext_conf_template.txt holen (Backend, Extension Configuration)

\nn\t3::Environment()->getExtConf('nnhelpers', 'varname');
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.extConf(path:'nnhelper')}
{nnt3:ts.extConf(path:'nnhelper.varname')}
{nnt3:ts.extConf(path:'nnhelper', key:'varname')}
Copied!

| @return mixed

| ➜ Go to source code of Environment::getExtConf()

\nn\t3::Environment()->getLanguage(); 

Die aktuelle Sprache (als Zahl) des Frontends holen.

\nn\t3::Environment()->getLanguage();
Copied!

| @return int

| ➜ Go to source code of Environment::getLanguage()

\nn\t3::Environment()->getLanguageFallbackChain($langUid = true); 

Gibt eine Liste der Sprachen zurück, die verwendet werden sollen, falls z.B. eine Seite oder ein Element nicht in der gewünschten Sprache existiert.

Wichtig: Die Fallback-Chain enthält an erster Stelle die aktuelle bzw. in $langUid übergebene Sprache.

// Einstellungen für aktuelle Sprache verwenden (s. Site-Config YAML)
\nn\t3::Environment()->getLanguageFallbackChain();   // --> z.B. [0] oder [1,0]

// Einstellungen für eine bestimmte Sprache holen
\nn\t3::Environment()->getLanguageFallbackChain( 1 );
// --> [1,0] - falls Fallback in Site-Config definiert wurde und der fallbackMode auf "fallback" steht
// --> [1] - falls es keinen Fallback gibt oder der fallbackMode auf "strict" steht
Copied!
@param string|boolean $returnKey
@return string|array

| ➜ Go to source code of Environment::getLanguageFallbackChain()

\nn\t3::Environment()->getLanguageKey(); 

Die aktuelle Sprache (als Kürzel wie "de") im Frontend holen

\nn\t3::Environment()->getLanguageKey();
Copied!

| @return string

| ➜ Go to source code of Environment::getLanguageKey()

\nn\t3::Environment()->getLanguages($key = 'languageId', $value = NULL); 

Gibt eine Liste aller definierten Sprachen zurück. Die Sprachen müssen in der YAML site configuration festgelegt sein.

// [['title'=>'German', 'iso-639-1'=>'de', 'typo3Language'=>'de', ....], ['title'=>'English', 'typo3Language'=>'en', ...]]
\nn\t3::Environment()->getLanguages();

// ['de'=>['title'=>'German', 'typo3Language'=>'de'], 'en'=>['title'=>'English', 'typo3Language'=>'en', ...]]
\nn\t3::Environment()->getLanguages('iso-639-1');

// ['de'=>0, 'en'=>1]
\nn\t3::Environment()->getLanguages('iso-639-1', 'languageId');

// [0=>'de', 1=>'en']
\nn\t3::Environment()->getLanguages('languageId', 'iso-639-1');
Copied!

Es gibt auch Helper zum Konvertieren von Sprach-IDs in Sprach-Kürzel und umgekehrt:

// --> 0
\nn\t3::Convert('de')->toLanguageId();

// --> 'de'
\nn\t3::Convert(0)->toLanguage();
Copied!
@param string $key
@param string $value
@return string|array

| ➜ Go to source code of Environment::getLanguages()

\nn\t3::Environment()->getLocalConf($path = ''); 

Konfiguration aus der LocalConfiguration.php holen

\nn\t3::Environment()->getLocalConf('FE.cookieName');
Copied!

| @return string

| ➜ Go to source code of Environment::getLocalConf()

\nn\t3::Environment()->getPathSite(); 

Absoluten Pfad zum Typo3-Root-Verzeichnis holen. z.B. /var/www/website/

\nn\t3::Environment()->getPathSite()
Copied!

früher: PATH_site

| ➜ Go to source code of Environment::getPathSite()

\nn\t3::Environment()->getPostMaxSize(); 

Maximale Upload-Größe für Dateien aus dem Frontend zurückgeben. Diese Angabe ist der Wert, der in der php.ini festgelegt wurde und ggf. über die .htaccess überschrieben wurde.

\nn\t3::Environment()->getPostMaxSize();  // z.B. '1048576' bei 1MB
Copied!

| @return integer

| ➜ Go to source code of Environment::getPostMaxSize()

\nn\t3::Environment()->getPsr4Prefixes(); 

Liste der PSR4 Prefixes zurückgeben.

Das ist ein Array mit allen Ordnern, die beim autoloading / Bootstrap von TYPO3 nach Klassen geparsed werden müssen. In einer TYPO3 Extension ist das per default der Ordern Classes. Die Liste wird von Composer/TYPO3 generiert.

Zurückgegeben wird ein array. Key ist Vendor\Namespace\, Wert ist ein Array mit Pfaden zu den Ordnern, die rekursiv nach Klassen durchsucht werden. Es spielt dabei keine Rolle, ob TYPO3 im composer mode läuft oder nicht.

\nn\t3::Environment()->getPsr4Prefixes();
Copied!

Beispiel für Rückgabe:

[
    'Nng\Nnhelpers\' => ['/pfad/zu/composer/../../public/typo3conf/ext/nnhelpers/Classes', ...],
    'Nng\Nnrestapi\' => ['/pfad/zu/composer/../../public/typo3conf/ext/nnrestapi/Classes', ...]
]
Copied!

| @return array

| ➜ Go to source code of Environment::getPsr4Prefixes()

\nn\t3::Environment()->getRelPathSite(); 

Relativen Pfad zum Typo3-Root-Verzeichnis holen. z.B. ../

\nn\t3::Environment()->getRelPathSite()
Copied!

| @return string

| ➜ Go to source code of Environment::getRelPathSite()

\nn\t3::Environment()->getRequest(); 

Holt den aktuellen Request. Workaround für Sonderfälle – und den Fall, dass das Core-Team diese Option nicht in Zukunft selbst implementiert.

$request = \nn\t3::Environment()->getRequest();
Copied!

| @return \TYPO3\CMS\Core\Http\ServerRequest

| ➜ Go to source code of Environment::getRequest()

\nn\t3::Environment()->getSite($request = NULL); 

Das aktuelle Site Object holen. Über dieses Object kann z.B. ab TYPO3 9 auf die Konfiguration aus der site YAML-Datei zugegriffen werden.

Im Kontext einer MiddleWare ist evtl. die site noch nicht geparsed / geladen. In diesem Fall kann der $request aus der MiddleWare übergeben werden, um die Site zu ermitteln.

Siehe auch \nn\t3::Settings()->getSiteConfig(), um die site-Konfiguration auszulesen.

\nn\t3::Environment()->getSite();
\nn\t3::Environment()->getSite( $request );

\nn\t3::Environment()->getSite()->getConfiguration();
\nn\t3::Environment()->getSite()->getIdentifier();
Copied!

| @return \TYPO3\CMS\Core\Site\Entity\Site

| ➜ Go to source code of Environment::getSite()

\nn\t3::Environment()->getSyntheticFrontendRequest($pageUid = NULL); 

Generiert einen virtuellen Frontend Request, der in jedem Context verwendet werden kann. Initialisiert auch das Frontend TypoScript-Object und alle relevanten Objekte.

$request = \nn\t3::Environment()->getSyntheticFrontendRequest();
Copied!
@param int $pageUid
@return \TYPO3\CMS\Core\Http\ServerRequest

| ➜ Go to source code of Environment::getSyntheticFrontendRequest()

\nn\t3::Environment()->getVarPath(); 

Absoluten Pfad zu dem /var-Verzeichnis von Typo3 holen.

Dieses Verzeichnis speichert temporäre Cache-Dateien. Je nach Version von Typo3 und Installationstyp (Composer oder Non-Composer mode) ist dieses Verzeichnis an unterschiedlichen Orten zu finden.

// /full/path/to/typo3temp/var/
$path = \nn\t3::Environment()->getVarPath();
Copied!

| ➜ Go to source code of Environment::getVarPath()

\nn\t3::Environment()->isBackend(); 

Prüfen, ob wir uns im Backend-Context befinden

\nn\t3::Environment()->isBackend();
Copied!

| @return bool

| ➜ Go to source code of Environment::isBackend()

\nn\t3::Environment()->isFrontend(); 

Prüfen, ob wir uns im Frontend-Context befinden

\nn\t3::Environment()->isFrontend();
Copied!

| @return bool

| ➜ Go to source code of Environment::isFrontend()

\nn\t3::Environment()->isHttps(); 

Gibt true zurück, wenn die Seite über HTTPS aufgerufen wird.

$isHttps = \nn\t3::Environment()->isHttps();
Copied!

| @return boolean

| ➜ Go to source code of Environment::isHttps()

\nn\t3::Environment()->isLocalhost(); 

Prüft, ob Installation auf lokalem Server läuft

\nn\t3::Environment()->isLocalhost()
Copied!

| @return boolean

| ➜ Go to source code of Environment::isLocalhost()

\nn\t3::Environment()->setLanguage($languageId = 0); 

Die aktuelle Sprache setzen.

Hilfreich, wenn wir die Sprache in einem Context brauchen, wo er nicht initialisiert wurde, z.B. in einer MiddleWare oder CLI.

\nn\t3::Environment()->setLanguage(0);
Copied!
@param int $languageId
@return self

| ➜ Go to source code of Environment::setLanguage()

\nn\t3::Environment()->setRequest($request); 

Setzt den aktuellen Request. Wird in der RequestParser-MiddleWare gesetzt

\nn\t3::Environment()->setRequest( $request );
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest
@return self

| ➜ Go to source code of Environment::setRequest()

\nn\t3::Environment()->t3Version(); 

Die Version von Typo3 holen, als Ganzzahl, z.b "8" Alias zu \nn\t3::t3Version()

\nn\t3::Environment()->t3Version();

if (\nn\t3::t3Version() >= 8) {
    // nur für >= Typo3 8 LTS
}
Copied!

| @return int

| ➜ Go to source code of Environment::t3Version()

Methods 

Environment::extLoaded() 

\nn\t3::Environment()->extLoaded($extName = ''); 

Prüfen, ob Extension geladen ist.

\nn\t3::Environment()->extLoaded('news');
Copied!

Source Code 

public function extLoaded ( $extName = '' ) {
	return ExtensionManagementUtility::isLoaded( $extName );
}
Copied!

Environment::extPath() 

\nn\t3::Environment()->extPath($extName = ''); 

absoluten Pfad zu einer Extension holen z.B. /var/www/website/ext/nnsite/

\nn\t3::Environment()->extPath('extname');
Copied!

| @return string

Source Code 

public function extPath ( $extName = '' ) {
	return ExtensionManagementUtility::extPath( $extName );
}
Copied!

Environment::extRelPath() 

\nn\t3::Environment()->extRelPath($extName = ''); 

relativen Pfad (vom aktuellen Script aus) zu einer Extension holen z.B. ../typo3conf/ext/nnsite/

\nn\t3::Environment()->extRelPath('extname');
Copied!

| @return string

Source Code 

public function extRelPath ( $extName = '' ) {
	return PathUtility::getRelativePathTo( $this->extPath($extName) );
}
Copied!

Environment::getBaseURL() 

\nn\t3::Environment()->getBaseURL(); 

Gibt die baseUrl (config.baseURL) zurück, inkl. http(s) Protokoll z.B. https://www.webseite.de/

\nn\t3::Environment()->getBaseURL();
Copied!

| @return string

Source Code 

public function getBaseURL ()
{
	$setup = \nn\t3::Settings()->getFullTyposcript();
	if ($baseUrl = $setup['config']['baseURL'] ?? false) return $baseUrl;
	$host = $_SERVER['HTTP_HOST'] ?? '';
	$server = ($this->isHttps() ? 'https' : 'http') . "://{$host}/";
	return $server;
}
Copied!

Environment::getCookieDomain() 

\nn\t3::Environment()->getCookieDomain($loginType = 'FE'); 

Die Cookie-Domain holen z.B. www.webseite.de

\nn\t3::Environment()->getCookieDomain()
Copied!

| @return string

Source Code 

public function getCookieDomain ( $loginType = 'FE' ) {
	$cookieDomain = $this->getLocalConf( $loginType . '.cookieDomain' )
		?: $this->getLocalConf( 'SYS.cookieDomain' );
	if (!$cookieDomain) {
		return '';
	}
	// Check if cookieDomain is a regex pattern (starts and ends with /)
	if ($cookieDomain[0] === '/') {
		$host = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
		if (@preg_match($cookieDomain, $host, $match)) {
			$cookieDomain = $match[0];
		} else {
			$cookieDomain = '';
		}
	}
	return $cookieDomain;
}
Copied!

Environment::getCountries() 

\nn\t3::Environment()->getCountries($lang = 'de', $key = 'cn_iso_2'); 

Alle im System verfügbaren Ländern holen

\nn\t3::Environment()->getCountries();
Copied!

| @return array

Source Code 

public function getCountries ( $lang = 'de', $key = 'cn_iso_2' ) {
	if (!ExtensionManagementUtility::isLoaded('static_info_tables')) {
		$countryProvider = GeneralUtility::makeInstance(CountryProvider::class);
		$allCountries = \nn\t3::Convert($countryProvider->getAll())->toArray();
		if ($lang != 'en') {
			$languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create($lang);
			foreach ($allCountries as &$country) {
				$country['name'] = $languageService->sL($country['localizedNameLabel']);
				$country['officialName'] = $languageService->sL($country['localizedOfficialNameLabel']);
			}
		}
		if ($key != 'cn_iso_2') {
			$results = array_column($allCountries, 'name', 'alpha3IsoCode');
		} else {
			$results = array_combine(
				array_keys($allCountries),
				array_column($allCountries, 'name')
			);
		}
		if (extension_loaded('intl')) {
			$coll = new \Collator('de_DE');
			uasort($results, function($a, $b) use ($coll) {
				return $coll->compare($a, $b);
			});
		} else {
			$oldLocale = setlocale(LC_COLLATE, 0);
			setlocale(LC_COLLATE, 'de_DE.utf8');
			asort($results, SORT_LOCALE_STRING);
			setlocale(LC_COLLATE, $oldLocale);
		}
		return $results;
	}
	$data = \nn\t3::Db()->findAll( 'static_countries' );
	return \nn\t3::Arrays($data)->key($key)->pluck('cn_short_'.$lang)->toArray();
}
Copied!

Environment::getCountryByIsocode() 

\nn\t3::Environment()->getCountryByIsocode($cn_iso_2 = NULL, $field = 'cn_iso_2'); 

Ein Land aus der Tabelle static_countries anhand seines Ländercodes (z.B. DE) holen

\nn\t3::Environment()->getCountryByIsocode( 'DE' );
\nn\t3::Environment()->getCountryByIsocode( 'DEU', 'cn_iso_3' );
Copied!

| @return array

Source Code 

public function getCountryByIsocode ( $cn_iso_2 = null, $field = 'cn_iso_2' ) {
	if (!ExtensionManagementUtility::isLoaded('static_info_tables')) {
		$countryProvider = GeneralUtility::makeInstance(CountryProvider::class);
		$allCountries = \nn\t3::Convert($countryProvider->getAll())->toArray();
		if ($field == 'cn_iso_2') {
			return $allCountries[$cn_iso_2] ?? [];
		}
		$allCountriesByIso3 = array_combine(
			array_column($allCountries, 'alpha3IsoCode'),
			array_values($allCountries)
		);
		return $allCountriesByIso3[$cn_iso_2] ?? [];
	}
	$data = \nn\t3::Db()->findByValues( 'static_countries', [$field=>$cn_iso_2] );
	return $data ? array_pop($data) : [];
}
Copied!

Environment::getDefaultLanguage() 

\nn\t3::Environment()->getDefaultLanguage($returnKey = 'typo3Language'); 

Gibt die Standard-Sprache (Default Language) zurück. Bei TYPO3 ist das immer die Sprache mit der ID 0. Die Sprachen müssen in der YAML site configuration festgelegt sein.

// 'de'
\nn\t3::Environment()->getDefaultLanguage();

// 'de-DE'
\nn\t3::Environment()->getDefaultLanguage('hreflang');

// ['title'=>'German', 'typo3Language'=>'de', ...]
\nn\t3::Environment()->getDefaultLanguage( true );
Copied!
@param string|boolean $returnKey
@return string|array

Source Code 

public function getDefaultLanguage( $returnKey = 'typo3Language' ) {
	$firstLanguage = $this->getLanguages('languageId')[0] ?? [];
	if ($returnKey === true) return $firstLanguage;
	return $firstLanguage[$returnKey] ?? '';
}
Copied!

Environment::getDomain() 

\nn\t3::Environment()->getDomain(); 

Die Domain holen z.B. www.webseite.de

\nn\t3::Environment()->getDomain();
Copied!

| @return string

Source Code 

public function getDomain () {
	$domain = preg_replace('/(http)([s]*)(:)\/\//i', '', $this->getBaseURL());
	return rtrim($domain, '/');
}
Copied!

Environment::getExtConf() 

\nn\t3::Environment()->getExtConf($ext = 'nnhelpers', $param = ''); 

Configuration aus ext_conf_template.txt holen (Backend, Extension Configuration)

\nn\t3::Environment()->getExtConf('nnhelpers', 'varname');
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.extConf(path:'nnhelper')}
{nnt3:ts.extConf(path:'nnhelper.varname')}
{nnt3:ts.extConf(path:'nnhelper', key:'varname')}
Copied!

| @return mixed

Source Code 

public function getExtConf ( $ext = 'nnhelpers', $param = '' ) {
	$extConfig = $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][$ext] ?? [];
	return $param ? ($extConfig[$param] ?? '') : $extConfig;
}
Copied!

Environment::getLanguage() 

\nn\t3::Environment()->getLanguage(); 

Die aktuelle Sprache (als Zahl) des Frontends holen.

\nn\t3::Environment()->getLanguage();
Copied!

| @return int

Source Code 

public function getLanguage () {
	$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
	return $languageAspect->getId();
}
Copied!

Environment::getLanguageFallbackChain() 

\nn\t3::Environment()->getLanguageFallbackChain($langUid = true); 

Gibt eine Liste der Sprachen zurück, die verwendet werden sollen, falls z.B. eine Seite oder ein Element nicht in der gewünschten Sprache existiert.

Wichtig: Die Fallback-Chain enthält an erster Stelle die aktuelle bzw. in $langUid übergebene Sprache.

// Einstellungen für aktuelle Sprache verwenden (s. Site-Config YAML)
\nn\t3::Environment()->getLanguageFallbackChain();   // --> z.B. [0] oder [1,0]

// Einstellungen für eine bestimmte Sprache holen
\nn\t3::Environment()->getLanguageFallbackChain( 1 );
// --> [1,0] - falls Fallback in Site-Config definiert wurde und der fallbackMode auf "fallback" steht
// --> [1] - falls es keinen Fallback gibt oder der fallbackMode auf "strict" steht
Copied!
@param string|boolean $returnKey
@return string|array

Source Code 

public function getLanguageFallbackChain( $langUid = true )
{
	if ($langUid === true) {
		$langUid = $this->getLanguage();
	}
	$langSettings = $this->getLanguages()[$langUid] ?? [];
	$fallbackType = $langSettings['fallbackType'] ?? 'strict';
	$fallbackChain = $langSettings['fallbacks'] ?? '';
	if ($fallbackType == 'strict') {
		$fallbackChain = '';
	}
	$fallbackChainArray = array_map( function ( $uid ) {
		return intval( $uid );
	}, \nn\t3::Arrays($fallbackChain)->intExplode() );
	array_unshift( $fallbackChainArray, $langUid );
	return $fallbackChainArray;
}
Copied!

Environment::getLanguageKey() 

\nn\t3::Environment()->getLanguageKey(); 

Die aktuelle Sprache (als Kürzel wie "de") im Frontend holen

\nn\t3::Environment()->getLanguageKey();
Copied!

| @return string

Source Code 

public function getLanguageKey () {
	$request = $this->getRequest();
	if ($request instanceof ServerRequestInterface) {
		$data = $request->getAttribute('language', null);
		if ($data) {
			return $data->getTwoLetterIsoCode();
		}
	}
	return '';
}
Copied!

Environment::getLanguages() 

\nn\t3::Environment()->getLanguages($key = 'languageId', $value = NULL); 

Gibt eine Liste aller definierten Sprachen zurück. Die Sprachen müssen in der YAML site configuration festgelegt sein.

// [['title'=>'German', 'iso-639-1'=>'de', 'typo3Language'=>'de', ....], ['title'=>'English', 'typo3Language'=>'en', ...]]
\nn\t3::Environment()->getLanguages();

// ['de'=>['title'=>'German', 'typo3Language'=>'de'], 'en'=>['title'=>'English', 'typo3Language'=>'en', ...]]
\nn\t3::Environment()->getLanguages('iso-639-1');

// ['de'=>0, 'en'=>1]
\nn\t3::Environment()->getLanguages('iso-639-1', 'languageId');

// [0=>'de', 1=>'en']
\nn\t3::Environment()->getLanguages('languageId', 'iso-639-1');
Copied!

Es gibt auch Helper zum Konvertieren von Sprach-IDs in Sprach-Kürzel und umgekehrt:

// --> 0
\nn\t3::Convert('de')->toLanguageId();

// --> 'de'
\nn\t3::Convert(0)->toLanguage();
Copied!
@param string $key
@param string $value
@return string|array

Source Code 

public function getLanguages( $key = 'languageId', $value = null )
{
	$languages = \nn\t3::Settings()->getSiteConfig()['languages'] ?? [];
	array_walk($languages, fn(&$language) => $language['iso-639-1'] = $language['typo3Language'] = $language['iso-639-1'] ?? substr($language['locale'], 0, 2));
	if (!$value) {
		return array_combine( array_column($languages, $key), array_values($languages) );
	}
	return array_combine( array_column($languages, $key), array_column($languages, $value) );
}
Copied!

Environment::getLocalConf() 

\nn\t3::Environment()->getLocalConf($path = ''); 

Konfiguration aus der LocalConfiguration.php holen

\nn\t3::Environment()->getLocalConf('FE.cookieName');
Copied!

| @return string

Source Code 

public function getLocalConf ( $path = '' ) {
	if (!$path) return $GLOBALS['TYPO3_CONF_VARS'];
	return \nn\t3::Settings()->getFromPath( $path, $GLOBALS['TYPO3_CONF_VARS'] ) ?: '';
}
Copied!

Environment::getPathSite() 

\nn\t3::Environment()->getPathSite(); 

Absoluten Pfad zum Typo3-Root-Verzeichnis holen. z.B. /var/www/website/

\nn\t3::Environment()->getPathSite()
Copied!

früher: PATH_site

Source Code 

public function getPathSite () {
	return \TYPO3\CMS\Core\Core\Environment::getPublicPath().'/';
}
Copied!

Environment::getPostMaxSize() 

\nn\t3::Environment()->getPostMaxSize(); 

Maximale Upload-Größe für Dateien aus dem Frontend zurückgeben. Diese Angabe ist der Wert, der in der php.ini festgelegt wurde und ggf. über die .htaccess überschrieben wurde.

\nn\t3::Environment()->getPostMaxSize();  // z.B. '1048576' bei 1MB
Copied!

| @return integer

Source Code 

public function getPostMaxSize() {
	$postMaxSize = ini_get('post_max_size');
	return \nn\t3::Convert($postMaxSize)->toBytes();
}
Copied!

Environment::getPsr4Prefixes() 

\nn\t3::Environment()->getPsr4Prefixes(); 

Liste der PSR4 Prefixes zurückgeben.

Das ist ein Array mit allen Ordnern, die beim autoloading / Bootstrap von TYPO3 nach Klassen geparsed werden müssen. In einer TYPO3 Extension ist das per default der Ordern Classes. Die Liste wird von Composer/TYPO3 generiert.

Zurückgegeben wird ein array. Key ist Vendor\Namespace\, Wert ist ein Array mit Pfaden zu den Ordnern, die rekursiv nach Klassen durchsucht werden. Es spielt dabei keine Rolle, ob TYPO3 im composer mode läuft oder nicht.

\nn\t3::Environment()->getPsr4Prefixes();
Copied!

Beispiel für Rückgabe:

[
    'Nng\Nnhelpers\' => ['/pfad/zu/composer/../../public/typo3conf/ext/nnhelpers/Classes', ...],
    'Nng\Nnrestapi\' => ['/pfad/zu/composer/../../public/typo3conf/ext/nnrestapi/Classes', ...]
]
Copied!

| @return array

Source Code 

public function getPsr4Prefixes() {
	$composerClassLoader = ClassLoadingInformation::getClassLoader();
	$psr4prefixes = $composerClassLoader->getPrefixesPsr4();
	return $psr4prefixes;
}
Copied!

Environment::getRelPathSite() 

\nn\t3::Environment()->getRelPathSite(); 

Relativen Pfad zum Typo3-Root-Verzeichnis holen. z.B. ../

\nn\t3::Environment()->getRelPathSite()
Copied!

| @return string

Source Code 

public function getRelPathSite () {
	return \nn\t3::File()->relPath();
}
Copied!

Environment::getRequest() 

\nn\t3::Environment()->getRequest(); 

Holt den aktuellen Request. Workaround für Sonderfälle – und den Fall, dass das Core-Team diese Option nicht in Zukunft selbst implementiert.

$request = \nn\t3::Environment()->getRequest();
Copied!

| @return \TYPO3\CMS\Core\Http\ServerRequest

Source Code 

public function getRequest()
{
	$request = $GLOBALS['TYPO3_REQUEST'] ?? null ?: $this->TYPO3_REQUEST;
	if ($request) return $request;
	$request = $this->getSyntheticFrontendRequest();
	return $this->TYPO3_REQUEST = $request;
}
Copied!

Environment::getSite() 

\nn\t3::Environment()->getSite($request = NULL); 

Das aktuelle Site Object holen. Über dieses Object kann z.B. ab TYPO3 9 auf die Konfiguration aus der site YAML-Datei zugegriffen werden.

Im Kontext einer MiddleWare ist evtl. die site noch nicht geparsed / geladen. In diesem Fall kann der $request aus der MiddleWare übergeben werden, um die Site zu ermitteln.

Siehe auch \nn\t3::Settings()->getSiteConfig(), um die site-Konfiguration auszulesen.

\nn\t3::Environment()->getSite();
\nn\t3::Environment()->getSite( $request );

\nn\t3::Environment()->getSite()->getConfiguration();
\nn\t3::Environment()->getSite()->getIdentifier();
Copied!

| @return \TYPO3\CMS\Core\Site\Entity\Site

Source Code 

public function getSite ( $request = null )
{
	if (!$request && !\TYPO3\CMS\Core\Core\Environment::isCli()) {
		$request = $this->getRequest();
	}
	// no request set? try getting site by the current pid
	if (!$request) {
		try {
			$pageUid = \nn\t3::Page()->getPid();
			$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageUid);
			return $site;
		} catch ( \Exception $e ) {
			return null;
		}
	};
	// try getting site by baseURL
	$site = $request->getAttribute('site');
	if (!$site || is_a($site, \TYPO3\CMS\Core\Site\Entity\NullSite::class)) {
		$matcher = GeneralUtility::makeInstance( SiteMatcher::class );
		$routeResult = $matcher->matchRequest($request);
		$site = $routeResult->getSite();
	}
	// last resort: Just get the first site
	if (!$site || is_a($site, \TYPO3\CMS\Core\Site\Entity\NullSite::class)) {
		$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
		$sites = $siteFinder->getAllSites();
		$site = reset($sites) ?: null;
	}
	return $site;
}
Copied!

Environment::getSyntheticFrontendRequest() 

\nn\t3::Environment()->getSyntheticFrontendRequest($pageUid = NULL); 

Generiert einen virtuellen Frontend Request, der in jedem Context verwendet werden kann. Initialisiert auch das Frontend TypoScript-Object und alle relevanten Objekte.

$request = \nn\t3::Environment()->getSyntheticFrontendRequest();
Copied!
@param int $pageUid
@return \TYPO3\CMS\Core\Http\ServerRequest

Source Code 

public function getSyntheticFrontendRequest( $pageUid = null )
{
	if (isset($this->SYNTHETIC_FE_REQUEST)) {
		return $this->SYNTHETIC_FE_REQUEST;
	}
	// Resolve site + language + a page id (use site root as default)
	$pageUid  = $pageUid ?: (int) (\nn\t3::Page()->getSiteRoot()['uid'] ?? 0);
	$site	 = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageUid);
	$langId   = $this->getLanguage();
	$language = $site->getLanguageById($langId);
	// Build base URI (fallback if site base is empty)
	$base = (string)$site->getBase();
	if ($base === '' || $base === '/') {
		$base = $this->getBaseURL();
	}
	$uri = new Uri($base);
	// Start request (URI first, then method in v13)
	$queryParams = ['id' => $pageUid]; // make routing happy
	$request = (new ServerRequest($uri, 'GET'))
		->withAttribute('site', $site)
		->withAttribute('language', $language)
		->withQueryParams($queryParams);
	// normalizedParams (what older code used to get from getIndpEnv)
	$serverParams = [
		'HTTP_HOST'	  => $uri->getHost() . ($uri->getPort() ? ':' . $uri->getPort() : ''),
		'REQUEST_METHOD' => 'GET',
		'REQUEST_URI'	=> $uri->getPath() === '' ? '/' : $uri->getPath(),
		'QUERY_STRING'   => http_build_query($queryParams),
		'HTTPS'		  => $uri->getScheme() === 'https' ? 'on' : 'off',
		'SERVER_PORT'	=> $uri->getPort() ?: ($uri->getScheme() === 'https' ? 443 : 80),
	];
	$normalized = NormalizedParams::createFromServerParams($serverParams);
	$request = $request->withAttribute('normalizedParams', $normalized);
	// routing (PageArguments) — minimal but sufficient
	$pageType = 0;
	$routing  = new PageArguments($pageUid, $pageType, $queryParams);
	$request  = $request->withAttribute('routing', $routing);
	$request = $request->withAttribute(
		'applicationType',
		SystemEnvironmentBuilder::REQUESTTYPE_FE
	);
	// ensure full TypoScript even in "cached" context
	$request = \nn\t3::Tsfe()->softDisableCache($request);
	// Tiny handler to capture the mutated request
	$captured = null;
	$handler = new class($captured) implements RequestHandlerInterface {
		public ?\Psr\Http\Message\ServerRequestInterface $captured;
		public function __construct(&$_c) { $this->captured = &$_c; }
		public function handle(\Psr\Http\Message\ServerRequestInterface $request): \Psr\Http\Message\ResponseInterface {
			$this->captured = $request;
			return new HtmlResponse('');
		}
	};
	// needed to prevent cross-contamination when in backend-context
	$oldRequest = $GLOBALS['TYPO3_REQUEST'] ?? null;
	// initialize FE controller (sets frontend.controller / $GLOBALS['TSFE'])
	GeneralUtility::makeInstance(TypoScriptFrontendInitialization::class)->process($request, $handler);
	$request = $handler->captured ?? $request;
	// prepare TypoScript (attaches frontend.typoscript with FULL setup now)
	GeneralUtility::makeInstance(PrepareTypoScriptFrontendRendering::class)->process($request, $handler);
	$request = $handler->captured ?? $request;
	$this->SYNTHETIC_FE_REQUEST = $request;
	// reset to global request before capturing
	$GLOBALS['TYPO3_REQUEST'] = $oldRequest;
	return $request;
}
Copied!

Environment::getVarPath() 

\nn\t3::Environment()->getVarPath(); 

Absoluten Pfad zu dem /var-Verzeichnis von Typo3 holen.

Dieses Verzeichnis speichert temporäre Cache-Dateien. Je nach Version von Typo3 und Installationstyp (Composer oder Non-Composer mode) ist dieses Verzeichnis an unterschiedlichen Orten zu finden.

// /full/path/to/typo3temp/var/
$path = \nn\t3::Environment()->getVarPath();
Copied!

Source Code 

public function getVarPath() {
	return rtrim(\TYPO3\CMS\Core\Core\Environment::getVarPath(), '/').'/';
}
Copied!

Environment::isBackend() 

\nn\t3::Environment()->isBackend(); 

Prüfen, ob wir uns im Backend-Context befinden

\nn\t3::Environment()->isBackend();
Copied!

| @return bool

Source Code 

public function isBackend () {
	return !$this->isFrontend();
}
Copied!

Environment::isFrontend() 

\nn\t3::Environment()->isFrontend(); 

Prüfen, ob wir uns im Frontend-Context befinden

\nn\t3::Environment()->isFrontend();
Copied!

| @return bool

Source Code 

public function isFrontend () {
	if ($this->_isFrontend !== null) {
		return $this->_isFrontend;
	}
	$request = $this->getRequest();
	if ($request instanceof ServerRequestInterface) {
		return $this->_isFrontend = ApplicationType::fromRequest($request)->isFrontend();
	}
	return $this->_isFrontend = false;
}
Copied!

Environment::isHttps() 

\nn\t3::Environment()->isHttps(); 

Gibt true zurück, wenn die Seite über HTTPS aufgerufen wird.

$isHttps = \nn\t3::Environment()->isHttps();
Copied!

| @return boolean

Source Code 

public function isHttps() {
	return (
		(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
		|| (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)
		|| (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
		|| (isset($_SERVER['HTTP_VIA']) && strpos($_SERVER['HTTP_VIA'], 'HTTPS') !== false)
	);
}
Copied!

Environment::isLocalhost() 

\nn\t3::Environment()->isLocalhost(); 

Prüft, ob Installation auf lokalem Server läuft

\nn\t3::Environment()->isLocalhost()
Copied!

| @return boolean

Source Code 

public function isLocalhost () {
	$localhost = ['127.0.0.1', '::1'];
	return in_array($_SERVER['REMOTE_ADDR'], $localhost);
}
Copied!

Environment::setLanguage() 

\nn\t3::Environment()->setLanguage($languageId = 0); 

Die aktuelle Sprache setzen.

Hilfreich, wenn wir die Sprache in einem Context brauchen, wo er nicht initialisiert wurde, z.B. in einer MiddleWare oder CLI.

\nn\t3::Environment()->setLanguage(0);
Copied!
@param int $languageId
@return self

Source Code 

public function setLanguage ( $languageId = 0 )
{
	$site = $this->getSite();
	try {
		$language = $site->getLanguageById( $languageId );
	} catch (\Exception $e) {
		$language = $site->getDefaultLanguage();
	}
	$languageAspect = LanguageAspectFactory::createFromSiteLanguage($language);
	$context = GeneralUtility::makeInstance(Context::class);
	$context->setAspect('language', $languageAspect);
	// keep the TYPO3_REQUEST in sync with the new language in case other extensions are relying on it
	if ($GLOBALS['TYPO3_REQUEST'] ?? false) {
		$GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']->withAttribute('language', $language);
	}
	// Initialize LanguageService for this language (needed for BackendUtility etc.)
	$languageServiceFactory = GeneralUtility::makeInstance(LanguageServiceFactory::class);
	$GLOBALS['LANG'] = $languageServiceFactory->createFromSiteLanguage($language);
	return $this;
}
Copied!

Environment::setRequest() 

\nn\t3::Environment()->setRequest($request); 

Setzt den aktuellen Request. Wird in der RequestParser-MiddleWare gesetzt

\nn\t3::Environment()->setRequest( $request );
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest
@return self

Source Code 

public function setRequest(&$request)
{
	return $this->TYPO3_REQUEST = $request;
}
Copied!

Environment::t3Version() 

\nn\t3::Environment()->t3Version(); 

Die Version von Typo3 holen, als Ganzzahl, z.b "8" Alias zu \nn\t3::t3Version()

\nn\t3::Environment()->t3Version();

if (\nn\t3::t3Version() >= 8) {
    // nur für >= Typo3 8 LTS
}
Copied!

| @return int

Source Code 

public function t3Version () {
	return \nn\t3::t3Version();
}
Copied!

Errors 

\nn\t3::Errors() 

Fehler und Exceptions ausgeben

Overview of Methods 

\nn\t3::Errors()->Error($message, $code = NULL); 

Einen Error werfen mit Backtrace

\nn\t3::Errors()->Error('Damn', 1234);
Copied!

Ist ein Alias zu:

\nn\t3::Error('Damn', 1234);
Copied!

| @return void

| ➜ Go to source code of Errors::Error()

\nn\t3::Errors()->Exception($message, $code = NULL); 

Eine Typo3-Exception werfen mit Backtrace

\nn\t3::Errors()->Exception('Damn', 1234);
Copied!

Ist ein Alias zu:

\nn\t3::Exception('Damn', 1234);
Copied!

| @return void

| ➜ Go to source code of Errors::Exception()

Methods 

Errors::Error() 

\nn\t3::Errors()->Error($message, $code = NULL); 

Einen Error werfen mit Backtrace

\nn\t3::Errors()->Error('Damn', 1234);
Copied!

Ist ein Alias zu:

\nn\t3::Error('Damn', 1234);
Copied!

| @return void

Source Code 

public function Error ( $message, $code = null ) {
	if (!$code) $code = time();
	throw new \Error( $message, $code );
}
Copied!

Errors::Exception() 

\nn\t3::Errors()->Exception($message, $code = NULL); 

Eine Typo3-Exception werfen mit Backtrace

\nn\t3::Errors()->Exception('Damn', 1234);
Copied!

Ist ein Alias zu:

\nn\t3::Exception('Damn', 1234);
Copied!

| @return void

Source Code 

public function Exception ( $message, $code = null ) {
	if (!$code) $code = time();
	throw new Exception( $message, $code );
}
Copied!

Fal 

\nn\t3::Fal() 

Methoden zum Erzeugen von sysFile und sysFileReference-Einträgen.

Spickzettel:

\TYPO3\CMS\Extbase\Persistence\Generic\ObjectStorage
 |
 └─ \TYPO3\CMS\Extbase\Domain\Model\FileReference
        ... getOriginalResource()
                |
                └─ \TYPO3\CMS\Core\Resource\FileReference
                    ... getOriginalFile()
                            |
                            └─ \TYPO3\CMS\Core\Resource\File
Copied!

Overview of Methods 

\nn\t3::Fal()->attach($model, $field, $itemData = NULL); 

Eine Datei zu einem FileReference-Object konvertieren und an die Property oder ObjectStorage eines Models hängen. Siehe auch: \nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet ); mit dem Array von mehreren Bildern an eine ObjectStorage gehängt werden können.

\nn\t3::Fal()->attach( $model, $fieldName, $filePath );
\nn\t3::Fal()->attach( $model, 'image', 'fileadmin/user_uploads/image.jpg' );
\nn\t3::Fal()->attach( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg'] );
\nn\t3::Fal()->attach( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg', 'title'=>'Titel...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference|array

| ➜ Go to source code of Fal::attach()

\nn\t3::Fal()->clearCache($filenameOrSysFile = ''); 

Löscht den Cache für die Bildgrößen eines FAL inkl. der umgerechneten Bilder Wird z.B. der f:image-ViewHelper verwendet, werden alle berechneten Bildgrößen in der Tabelle sys_file_processedfile gespeichert. Ändert sich das Originalbild, wird evtl. noch auf ein Bild aus dem Cache zugegriffen.

\nn\t3::Fal()->clearCache( 'fileadmin/file.jpg' );
\nn\t3::Fal()->clearCache( $fileReference );
\nn\t3::Fal()->clearCache( $falFile );
Copied!
@param $filenameOrSysFile FAL oder Pfad (String) zu der Datei
@return void

| ➜ Go to source code of Fal::clearCache()

\nn\t3::Fal()->createFalFile($storageConfig, $srcFile, $keepSrcFile = false, $forceCreateNew = false); 

Erzeugt ein File (FAL) Object (sys_file)

nnt3::Fal()->createFalFile( $storageConfig, $srcFile, $keepSrcFile, $forceCreateNew );

@param string $storageConfig Pfad/Ordner, in die FAL-Datei gespeichert werden soll (z.B. 'fileadmin/projektdaten/')
@param string $srcFile Quelldatei, die in FAL umgewandelt werden soll (z.B. 'uploads/tx_nnfesubmit/beispiel.jpg') Kann auch URL zu YouTube/Vimeo-Video sein (z.B. https://www.youtube.com/watch?v=7Bb5jXhwnRY)
@param boolean $keepSrcFile Quelldatei nur kopieren, nicht verschieben?
@param boolean $forceCreateNew Soll immer neue Datei erzeugt werden? Falls nicht, gibt er ggf. bereits existierendes File-Object zurück

| @return \Nng\Nnhelpers\Domain\Model\File|\TYPO3\CMS\Core\Resource\File|boolean

| ➜ Go to source code of Fal::createFalFile()

\nn\t3::Fal()->createForModel($model, $field, $itemData = NULL); 

Eine Datei zu einem FileReference-Object konvertieren und für attach() an ein vorhandenes Model und Feld / Property vorbereiten. Die FileReference wird dabei nicht automatisch an das Model gehängt. Um das FAL direkt in dem Model zu setzen, kann der Helper | \nn\t3::Fal()->attach( $model, $field, $itemData ) verwendet werden.

\nn\t3::Fal()->createForModel( $model, $fieldName, $filePath );
\nn\t3::Fal()->createForModel( $model, 'image', 'fileadmin/user_uploads/image.jpg' );
\nn\t3::Fal()->createForModel( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg'] );
\nn\t3::Fal()->createForModel( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg', 'title'=>'Titel...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Fal::createForModel()

\nn\t3::Fal()->createSysFile($file, $autoCreateStorage = true); 

Erstellt neuen Eintrag in sys_file Sucht in allen sys_file_storage-Einträgen, ob der Pfad zum $file bereits als Storage existiert. Falls nicht, wird ein neuer Storage angelegt.

\nn\t3::Fal()->createSysFile( 'fileadmin/bild.jpg' );
\nn\t3::Fal()->createSysFile( '/var/www/mysite/fileadmin/bild.jpg' );
Copied!

| @return false|\TYPO3\CMS\Core\Resource\File

| ➜ Go to source code of Fal::createSysFile()

\nn\t3::Fal()->deleteForModel($model, $field = NULL); 

Löscht die physischen Dateien für ein Model (oder ein einzelnes Feld des Models) vom Server.

// ALLE Dateien des gesamten Models löschen
\nn\t3::Fal()->deleteForModel( $model );

// ALLE Dateien aus dem Feld "images" löschen
\nn\t3::Fal()->deleteForModel( $model, 'images' );
Copied!
@param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $model
@param string $field
@return void

| ➜ Go to source code of Fal::deleteForModel()

\nn\t3::Fal()->deleteProcessedImages($sysFile = ''); 

Löscht alle physischen Thumbnail-Dateien, die für ein Bild generiert wurden inkl. der Datensätze in der Tabelle sys_file_processedfile.

Das Ursprungsbild, das als Argument $path übergeben wurde, wird dabei nicht gelöscht. Das Ganze erzwingt das Neugenerieren der Thumbnails für ein Bild, falls sich z.B. das Quellbild geändert hat aber der Dateiname gleich geblieben ist.

Weiterer Anwendungsfall: Dateien auf dem Server bereinigen, weil z.B. sensible, personenbezogene Daten gelöscht werden sollen inkl. aller generierten Thumbnails.

\nn\t3::Fal()->deleteProcessedImages( 'fileadmin/pfad/beispiel.jpg' );
\nn\t3::Fal()->deleteProcessedImages( $sysFileReference );
\nn\t3::Fal()->deleteProcessedImages( $sysFile );
Copied!

| @return mixed

| ➜ Go to source code of Fal::deleteProcessedImages()

\nn\t3::Fal()->deleteSysFile($uidOrObject = NULL); 

Löscht ein SysFile (Datensatz aus Tabelle sys_file) und alle dazugehörigen SysFileReferences. Eine radikale Art, um ein Bild komplett aus der Indizierung von Typo3 zu nehmen.

Die physische Datei wird nicht vom Server gelöscht! Siehe \nn\t3::File()->unlink() zum Löschen der physischen Datei. Siehe \nn\t3::Fal()->detach( $model, $field ); zum Löschen aus einem Model.

\nn\t3::Fal()->deleteSysFile( 1201 );
\nn\t3::Fal()->deleteSysFile( 'fileadmin/pfad/zum/bild.jpg' );
\nn\t3::Fal()->deleteSysFile( \TYPO3\CMS\Core\Resource\File );
\nn\t3::Fal()->deleteSysFile( \TYPO3\CMS\Core\Resource\FileReference );
Copied!

| @param $uidOrObject

| @return integer

| ➜ Go to source code of Fal::deleteSysFile()

\nn\t3::Fal()->deleteSysFileReference($uidOrFileReference = NULL); 

Löscht eine SysFileReference. Siehe auch \nn\t3::Fal()->detach( $model, $field ); zum Löschen aus einem Model.

\nn\t3::Fal()->deleteSysFileReference( 112 );
\nn\t3::Fal()->deleteSysFileReference( \TYPO3\CMS\Extbase\Domain\Model\FileReference );
Copied!

| @param $uidOrFileReference

| @return mixed

| ➜ Go to source code of Fal::deleteSysFileReference()

\nn\t3::Fal()->detach($model, $field, $obj = NULL); 

Leert eine ObjectStorage in einem Model oder entfernt ein einzelnes Object vom Model oder einer ObjectStorage. Im Beispiel kann image eine ObjectStorage oder eine einzelne FileReference sein:

\nn\t3::Fal()->detach( $model, 'image' );
\nn\t3::Fal()->detach( $model, 'image', $singleObjToRemove );
Copied!

| @return void

| ➜ Go to source code of Fal::detach()

\nn\t3::Fal()->fileReferenceExists($sysFile = NULL, $params = []); 

Prüft, ob für einen Datensatz bereits eine SysFileReference zum gleichen SysFile exisitert

\nn\t3::Fal()->fileReferenceExists( $sysFile, ['uid_foreign'=>123, 'tablenames'=>'tt_content', 'field'=>'media'] );
Copied!
@param $sysFile
@param array $params => uid_foreign, tablenames, fieldname
@return FileReference|false

| ➜ Go to source code of Fal::fileReferenceExists()

\nn\t3::Fal()->fromFalFile($sysFile = NULL); 

Erzeugt eine sys_file_reference aus einem sys_file

$sysFileRef = \nn\t3::Fal()->fromFalFile( $sysFile );
Copied!
@param \TYPO3\CMS\Core\Resource\File $sysFile
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Fal::fromFalFile()

\nn\t3::Fal()->fromFile($params = []); 

Erzeugt ein FileRefence Objekt (Tabelle: sys_file_reference) und verknüpft es mit einem Datensatz. Beispiel: Hochgeladenes JPG soll als FAL an tt_news-Datensatz angehängt werden

Parameter:

key Beschreibung

| src Pfad zur Quelldatei (kann auch http-Link zu YouTube-Video sein)

| dest Pfad zum Zielordner (optional, falls Datei verschoben/kopiert werden soll)

| table Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. tx_myext_domain_model_entry)

| title Titel

| description Beschreibung

| link Link

| crop Beschnitt

| table Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. tx_myext_domain_model_entry)

| sorting (int) Sortierung

| field Column-Name der Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. image)

| uid (int) uid des Datensatzes in der Zieltabelle (tx_myext_domain_model_entry.uid)

| pid (int) pid des Datensatzes in der Zieltabelle

| cruser_id cruser_id des Datensatzes in der Zieltabelle

| copy src-Datei nicht verschieben sondern kopieren (default: true)

| forceNew Im Zielordner neue Datei erzwingen (sonst wird geprüft, ob bereits Datei existiert) default: false

| single Sicherstellen, dass gleiche FileReferenz nur 1x pro Datensatz verknüpft wird (default: true)

Beispiel:

$fal = \nn\t3::Fal()->fromFile([
    'src'         => 'fileadmin/test/bild.jpg',
    'dest'            => 'fileadmin/test/fal/',
    'pid'         => 132,
    'uid'         => 5052,
    'table'           => 'tx_myext_domain_model_entry',
    'field'           => 'fallistimage'
]);
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Fal::fromFile()

\nn\t3::Fal()->getFalFile($srcFile); 

Holt ein File (FAL) Object (sys_file)

\nn\t3::Fal()->getFalFile( 'fileadmin/image.jpg' );
Copied!
@param string $srcFile
@return \TYPO3\CMS\Core\Resource\File|boolean

| ➜ Go to source code of Fal::getFalFile()

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier($file = ''); 

Holt ein SysFile aus der CombinedIdentifier-Schreibweise ('1:/uploads/beispiel.txt'). Falls Datei nicht exisitert wird FALSE zurückgegeben.

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier( '1:/uploads/beispiel.txt' );
Copied!
@param string $file Combined Identifier ('1:/uploads/beispiel.txt')
@return File|boolean

| ➜ Go to source code of Fal::getFileObjectFromCombinedIdentifier()

\nn\t3::Fal()->getFilePath($falReference); 

Die URL zu einer FileReference oder einem FalFile holen. Alias zu \nn\t3::File()->getPublicUrl().

\nn\t3::Fal()->getFilePath( $fileReference );    // ergibt z.B. 'fileadmin/bilder/01.jpg'
Copied!
@param \TYPO3\CMS\Extbase\Domain\Model\FileReference|\TYPO3\CMS\Core\Resource\FileReference $falReference
@return string

| ➜ Go to source code of Fal::getFilePath()

\nn\t3::Fal()->getFileReferenceByUid($uid = NULL); 

Holt eine SysFileReference anhand der uid Alias zu \nn\t3::Convert( $uid )->toFileReference();

\nn\t3::Fal()->getFileReferenceByUid( 123 );
Copied!
@param $uid
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Fal::getFileReferenceByUid()

\nn\t3::Fal()->getImage($src = NULL); 

Holt / konvertiert in ein TYPO3CMSCoreResourceFileReference Object (sys_file_reference) "Smarte" Variante zu \TYPO3\CMS\Extbase\Service\ImageService->getImage()

\nn\t3::Fal()->getImage( 1 );
\nn\t3::Fal()->getImage( 'pfad/zum/bild.jpg' );
\nn\t3::Fal()->getImage( $fileReference );
Copied!
@param string|\TYPO3\CMS\Extbase\Domain\Model\FileReference $src
@return \TYPO3\CMS\Core\Resource\FileReference|boolean

| ➜ Go to source code of Fal::getImage()

\nn\t3::Fal()->process($fileObj = '', $processing = []); 

Berechnet ein Bild über maxWidth, maxHeight, cropVariant etc. Gibt URI zum Bild als String zurück. Hilfreich bei der Berechnung von Thumbnails im Backend. Alias zu \nn\t3::File()->process()

\nn\t3::File()->process( 'fileadmin/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFileReference, ['maxWidth'=>200, 'cropVariant'=>'square'] );
Copied!

| @return string

| ➜ Go to source code of Fal::process()

\nn\t3::Fal()->setInModel($model, $fieldName = '', $imagesToAdd = []); 

Ersetzt eine FileReference oder ObjectStorage in einem Model mit Bildern. Typischer Anwendungsfall: Ein FAL-Bild soll über ein Upload-Formular im Frontend geändert werden können.

Für jedes Bild wird geprüft, ob bereits eine FileReference im Model existiert. Bestehende FileReferences werden nicht überschrieben, sonst würden evtl. Bildunterschriften oder Cropping-Anweisungen verloren gehen!

Achtung! Das Model wird automatisch persistiert!

$newModel = new \My\Extension\Domain\Model\Example();
\nn\t3::Fal()->setInModel( $newModel, 'falslideshow', 'path/to/file.jpg' );
echo $newModel->getUid(); // Model wurde persistiert!
Copied!

Beispiel mit einer einfachen FileReference im Model:

$imageToSet = 'fileadmin/bilder/portrait.jpg';
\nn\t3::Fal()->setInModel( $member, 'falprofileimage', $imageToSet );

\nn\t3::Fal()->setInModel( $member, 'falprofileimage', ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'] );
Copied!

Beispiel mit einem einzelnen SysFile:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'image', $file );
Copied!

Beispiel mit einem einzelnen SysFile, das in eine ObjectStorage soll:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'images', [$file] );
Copied!

Beispiel mit einem ObjectStorage im Model:

$imagesToSet = ['fileadmin/bilder/01.jpg', 'fileadmin/bilder/02.jpg', ...];
\nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet );

\nn\t3::Fal()->setInModel( $member, 'falslideshow', [['publicUrl'=>'01.jpg'], ['publicUrl'=>'02.jpg']] );
\nn\t3::Fal()->setInModel( $member, 'falvideos', [['publicUrl'=>'https://youtube.com/?watch=zagd61231'], ...] );
Copied!

Beispiel mit Videos:

$videosToSet = ['https://www.youtube.com/watch?v=GwlU_wsT20Q', ...];
\nn\t3::Fal()->setInModel( $member, 'videos', $videosToSet );
Copied!
@param mixed $model Das Model, das geändert werden soll
@param string $fieldName Property (Feldname) der ObjectStorage oder FileReference
@param mixed $imagesToAdd String / Array mit Bildern

| @return mixed

| ➜ Go to source code of Fal::setInModel()

\nn\t3::Fal()->toArray($fileReference = NULL); 

Eine FileReference in ein Array konvertieren. Enthält publicUrl, title, alternative, crop etc. der FileReference. Alias zu \nn\t3::Obj()->toArray( $fileReference );

\nn\t3::Fal()->toArray( $fileReference );    // ergibt ['publicUrl'=>'fileadmin/...', 'title'=>'...']
Copied!
@param \TYPO3\CMS\Extbase\Domain\Model\FileReference $falReference
@return array

| ➜ Go to source code of Fal::toArray()

\nn\t3::Fal()->updateMetaData($filenameOrSysFile = '', $data = []); 

Update der Angaben in sys_file_metadata und sys_file

\nn\t3::Fal()->updateMetaData( 'fileadmin/file.jpg' );
\nn\t3::Fal()->updateMetaData( $fileReference );
\nn\t3::Fal()->updateMetaData( $falFile );
Copied!
@param $filenameOrSysFile FAL oder Pfad (String) zu der Datei
@param $data Array mit Daten, die geupdated werden sollen. Falls leer, werden Bilddaten automatisch gelesen
@return void

| ➜ Go to source code of Fal::updateMetaData()

Methods 

Fal::attach() 

\nn\t3::Fal()->attach($model, $field, $itemData = NULL); 

Eine Datei zu einem FileReference-Object konvertieren und an die Property oder ObjectStorage eines Models hängen. Siehe auch: \nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet ); mit dem Array von mehreren Bildern an eine ObjectStorage gehängt werden können.

\nn\t3::Fal()->attach( $model, $fieldName, $filePath );
\nn\t3::Fal()->attach( $model, 'image', 'fileadmin/user_uploads/image.jpg' );
\nn\t3::Fal()->attach( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg'] );
\nn\t3::Fal()->attach( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg', 'title'=>'Titel...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference|array

Source Code 

public function attach ( $model, $field, $itemData = null )
{
	if (!$itemData) return;
	$returnFirstFal = !is_array($itemData);
	$falsCreated = [];
	if ($returnFirstFal) {
		$itemData = [$itemData];
	}
	foreach ($itemData as $item) {
		$fal = $this->createForModel($model, $field, $item);
		$propVal = \nn\t3::Obj()->prop($model, $field);
		$isStorage = \nn\t3::Obj()->isStorage( $propVal );
		if ($fal) {
			$falsCreated[] = $fal;
			if ($isStorage) {
				$propVal->attach( $fal );
			} else {
				\nn\t3::Obj()->set( $model, $field, $fal );
			}
		}
	}
	return $returnFirstFal ? array_pop($falsCreated) : $falsCreated;;
}
Copied!

Fal::clearCache() 

\nn\t3::Fal()->clearCache($filenameOrSysFile = ''); 

Löscht den Cache für die Bildgrößen eines FAL inkl. der umgerechneten Bilder Wird z.B. der f:image-ViewHelper verwendet, werden alle berechneten Bildgrößen in der Tabelle sys_file_processedfile gespeichert. Ändert sich das Originalbild, wird evtl. noch auf ein Bild aus dem Cache zugegriffen.

\nn\t3::Fal()->clearCache( 'fileadmin/file.jpg' );
\nn\t3::Fal()->clearCache( $fileReference );
\nn\t3::Fal()->clearCache( $falFile );
Copied!
@param $filenameOrSysFile FAL oder Pfad (String) zu der Datei
@return void

Source Code 

public function clearCache ( $filenameOrSysFile = '' )
{
	if (is_string($filenameOrSysFile)) {
		if ($falFile = $this->getFalFile( $filenameOrSysFile )) {
			$filenameOrSysFile = $falFile;
		}
	}
	$processedFileRepository = \nn\t3::injectClass( ProcessedFileRepository::class );
	if (is_string($filenameOrSysFile)) return;
	if (is_a($filenameOrSysFile, \TYPO3\CMS\Extbase\Domain\Model\File::class)) {
		$filenameOrSysFile = $filenameOrSysFile->getOriginalResource();
	}
	if ($processedFiles = $processedFileRepository->findAllByOriginalFile( $filenameOrSysFile )) {
		foreach ($processedFiles as $file) {
			$file->delete( true );
			\nn\t3::Db()->delete('sys_file_processedfile', $file->getUid());
		}
	}
}
Copied!

Fal::createFalFile() 

\nn\t3::Fal()->createFalFile($storageConfig, $srcFile, $keepSrcFile = false, $forceCreateNew = false); 

Erzeugt ein File (FAL) Object (sys_file)

nnt3::Fal()->createFalFile( $storageConfig, $srcFile, $keepSrcFile, $forceCreateNew );

@param string $storageConfig Pfad/Ordner, in die FAL-Datei gespeichert werden soll (z.B. 'fileadmin/projektdaten/')
@param string $srcFile Quelldatei, die in FAL umgewandelt werden soll (z.B. 'uploads/tx_nnfesubmit/beispiel.jpg') Kann auch URL zu YouTube/Vimeo-Video sein (z.B. https://www.youtube.com/watch?v=7Bb5jXhwnRY)
@param boolean $keepSrcFile Quelldatei nur kopieren, nicht verschieben?
@param boolean $forceCreateNew Soll immer neue Datei erzeugt werden? Falls nicht, gibt er ggf. bereits existierendes File-Object zurück

| @return \Nng\Nnhelpers\Domain\Model\File|\TYPO3\CMS\Core\Resource\File|boolean

Source Code 

public function createFalFile ( $storageConfig, $srcFile, $keepSrcFile = false, $forceCreateNew = false )
{
	$fileHelper = \nn\t3::File();
	$fileRepository = \nn\t3::injectClass( FileRepository::class );
	$srcFile = $fileHelper->stripBaseUrl( $srcFile );
	$isExternalMedia = strpos( $srcFile, 'http://') !== false || strpos( $srcFile, 'https://') !== false;
	if (!$storageConfig) {
		$storageConfig = $isExternalMedia ? 'fileadmin/videos/' : $srcFile;
	}
	// Absoluter Pfad zur Quell-Datei ('/var/www/website/uploads/bild.jpg')
	$absSrcFile = $fileHelper->absPath( $srcFile );
	// Keine externe URL (YouTube...) und Datei existiert nicht? Dann abbrechen!
	if (!$isExternalMedia && !$fileHelper->exists($srcFile)) {
		return false;
	}
	// Object, Storage-Model für Zielverzeichnis (z.B. Object für 'fileadmin/' wenn $storageConfig = 'fileadmin/test/was/')
	$storage = $fileHelper->getStorage($storageConfig, true);
	// Object, relativer Unterordner innerhalb der Storage, (z.B. Object für 'test/was/' wenn $storageConfig = 'fileadmin/test/was/')
	$subfolderInStorage = \nn\t3::Storage()->getFolder($storageConfig, $storage);
	// String, absoluter Pfad zum Zielverzeichnis
	$absDestFolderPath = $fileHelper->absPath( $subfolderInStorage );
	// Dateiname, ohne Pfad ('fileadmin/test/bild.jpg' => 'bild.jpg')
	$srcFileBaseName = basename($srcFile);
	if (!$forceCreateNew && $storage->hasFileInFolder( $srcFileBaseName, $subfolderInStorage )) {
		$existingFile = $storage->getFileInFolder( $srcFileBaseName, $subfolderInStorage );
		// @returns \TYPO3\CMS\Core\Resource\File
		return $existingFile;
	}
	if ($isExternalMedia) {
		// YouTube und Vimeo-Videos: Physische lokale .youtube/.vimeo-Datei anlegen
		$helper = \nn\t3::injectClass( OnlineMediaHelperRegistry::class );
		// \TYPO3\CMS\Core\Resource\File
		$newFileObject = $helper->transformUrlToFile( $srcFile, $subfolderInStorage );
	} else {
		// "Normale" Datei: Datei in Ordner kopieren und FAL erstellen
		// Name der Datei im Zielverzeichnis
		$absTmpName = $absDestFolderPath . $srcFileBaseName;
		// Kopieren
		if ($forceCreateNew) {
			$success = $fileHelper->copy( $absSrcFile, $absTmpName, $forceCreateNew );
			$absTmpName = $success;
		} else {
			if ($keepSrcFile) {
				$success = $fileHelper->copy( $absSrcFile, $absTmpName );
				$absTmpName = $success;
			} else {
				$success = $fileHelper->move( $absSrcFile, $absTmpName );
			}
		}
		if (!$success) return false;
		// Nutze die File-Indexer-Funktion, um die temporäre Datei in der Tabelle sys_file einzufügen
		$this->clearCache($absTmpName);
		// String, relativer Pfad der Datei innerhalb der Storage. Ermittelt selbstständig die passende Storage ()
		$relPathInStorage = $fileHelper->getRelativePathInStorage( $absTmpName );
		// File-Object für tmp-Datei holen
		$tmpFileObject = $storage->getFile($relPathInStorage);
		if (!$tmpFileObject) return false;
		// $newFileObject = $tmpFileObject->moveTo($subfolderInStorage, $srcFileBaseName, DuplicationBehavior::RENAME);
		$newFileObject = $tmpFileObject;
	}
	if (!$newFileObject) return false;
	// Exif-Daten für Datei ermitteln
	if ($exif = $fileHelper->getExifData( $srcFile )) {
		\nn\t3::Db()->update('sys_file', ['exif'=>json_encode($exif)], $newFileObject->getUid());
	}
	// @returns \TYPO3\CMS\Core\Resource\File
	return $newFileObject;
}
Copied!

Fal::createForModel() 

\nn\t3::Fal()->createForModel($model, $field, $itemData = NULL); 

Eine Datei zu einem FileReference-Object konvertieren und für attach() an ein vorhandenes Model und Feld / Property vorbereiten. Die FileReference wird dabei nicht automatisch an das Model gehängt. Um das FAL direkt in dem Model zu setzen, kann der Helper | \nn\t3::Fal()->attach( $model, $field, $itemData ) verwendet werden.

\nn\t3::Fal()->createForModel( $model, $fieldName, $filePath );
\nn\t3::Fal()->createForModel( $model, 'image', 'fileadmin/user_uploads/image.jpg' );
\nn\t3::Fal()->createForModel( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg'] );
\nn\t3::Fal()->createForModel( $model, 'image', ['publicUrl'=>'fileadmin/user_uploads/image.jpg', 'title'=>'Titel...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference

Source Code 

public function createForModel( $model, $field, $itemData = null )
{
	$objHelper = \nn\t3::Obj();
	if (is_string($itemData)) {
		$itemData = ['publicUrl'=>$itemData];
	}
	if ($objHelper->isFile($itemData)) {
		return $this->fromFalFile($itemData);
	}
	$filePath = $itemData['publicUrl'];
	if (!$filePath || !\nn\t3::File()->exists($filePath)) {
		\nn\t3::Exception('\nn\t3::Fal()->attach() :: File not found.');
	}
	$propVal = $objHelper->prop($model, $field);
	$isStorage = $objHelper->isStorage( $propVal );
	$table = $objHelper->getTableName( $model );
	$cruser_id = \nn\t3::FrontendUser()->getCurrentUserUid();
	$sorting = $isStorage ? count($propVal) : 0;
	$fal = $this->fromFile([
		'src'			=> $filePath,
		'title'			=> $itemData['title'] ?? null,
		'description'	=> $itemData['description'] ?? null,
		'link'			=> $itemData['link'] ?? '',
		'crop'			=> $itemData['crop'] ?? '',
		'sorting'		=> $itemData['sorting'] ?? $sorting,
		'pid'			=> $model->getPid(),
		'uid'			=> $model->getUid(),
		'table'			=> $table,
		'field'			=> $field,
		'cruser_id'		=> $cruser_id,
	]);
	return $fal;
}
Copied!

Fal::createSysFile() 

\nn\t3::Fal()->createSysFile($file, $autoCreateStorage = true); 

Erstellt neuen Eintrag in sys_file Sucht in allen sys_file_storage-Einträgen, ob der Pfad zum $file bereits als Storage existiert. Falls nicht, wird ein neuer Storage angelegt.

\nn\t3::Fal()->createSysFile( 'fileadmin/bild.jpg' );
\nn\t3::Fal()->createSysFile( '/var/www/mysite/fileadmin/bild.jpg' );
Copied!

| @return false|\TYPO3\CMS\Core\Resource\File

Source Code 

public function createSysFile ( $file, $autoCreateStorage = true )
{
	$file = \nn\t3::File()->stripPathSite( $file );
	$storage = \nn\t3::File()->getStorage( $file, $autoCreateStorage );
	if (!$storage) return false;
	$fileRepository = \nn\t3::injectClass( FileRepository::class );
	$storageConfiguration = $storage->getConfiguration();
	$storageFolder = $storageConfiguration['basePath'];
	$basename = substr( $file, strlen($storageFolder) );
	$sysFile = $storage->getFile($basename);
	// @return \TYPO3\CMS\Core\Resource\File
	$file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObject($sysFile->getUid());
	return $file;
}
Copied!

Fal::deleteForModel() 

\nn\t3::Fal()->deleteForModel($model, $field = NULL); 

Löscht die physischen Dateien für ein Model (oder ein einzelnes Feld des Models) vom Server.

// ALLE Dateien des gesamten Models löschen
\nn\t3::Fal()->deleteForModel( $model );

// ALLE Dateien aus dem Feld "images" löschen
\nn\t3::Fal()->deleteForModel( $model, 'images' );
Copied!
@param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $model
@param string $field
@return void

Source Code 

public function deleteForModel ( $model, $field = null )
{
	$tableName = \nn\t3::Obj()->getTableName( $model );
	$modelUid = $model->getUid();
	if (!$tableName || !$modelUid) return;
	$fileReferences = \nn\t3::Db()->findByValues('sys_file_reference', [
		'tablenames' 	=> $tableName,
		'uid_foreign'	=> $modelUid,
	]);
	$props = \nn\t3::Obj()->getProps( $model );
	if ($fileReferences) {
		try {
			$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
			foreach ($fileReferences as $row) {
				$fieldname = $row['fieldname'];
				if ($field && $fieldname !== $field) {
					continue;
				}
				if ($file = $resourceFactory->getFileObject( $row['uid_local'] )) {
					\nn\t3::Fal()->clearCache( $file );
					$file->delete();
					\nn\t3::Obj()->set( $model, $fieldname, null );
				}
			}
		} catch( \Exception $e ) {}
	}
}
Copied!

Fal::deleteProcessedImages() 

\nn\t3::Fal()->deleteProcessedImages($sysFile = ''); 

Löscht alle physischen Thumbnail-Dateien, die für ein Bild generiert wurden inkl. der Datensätze in der Tabelle sys_file_processedfile.

Das Ursprungsbild, das als Argument $path übergeben wurde, wird dabei nicht gelöscht. Das Ganze erzwingt das Neugenerieren der Thumbnails für ein Bild, falls sich z.B. das Quellbild geändert hat aber der Dateiname gleich geblieben ist.

Weiterer Anwendungsfall: Dateien auf dem Server bereinigen, weil z.B. sensible, personenbezogene Daten gelöscht werden sollen inkl. aller generierten Thumbnails.

\nn\t3::Fal()->deleteProcessedImages( 'fileadmin/pfad/beispiel.jpg' );
\nn\t3::Fal()->deleteProcessedImages( $sysFileReference );
\nn\t3::Fal()->deleteProcessedImages( $sysFile );
Copied!

| @return mixed

Source Code 

public function deleteProcessedImages( $sysFile = '' )
{
	if (is_string($sysFile)) {
		$sysFile = $this->getFalFile( $sysFile );
	} else if (is_a($sysFile, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class, true)) {
		$sysFile = $sysFile->getOriginalResource()->getOriginalFile();
	}
	if (!$sysFile) return;
	if ($sysFileUid = $sysFile->getUid()) {
		$rows = \nn\t3::Db()->findByValues('sys_file_processedfile', ['original'=>$sysFileUid]);
		foreach ($rows as $row) {
			\nn\t3::File()->unlink("{$row['storage']}:{$row['identifier']}");
		}
		\nn\t3::Db()->delete('sys_file_processedfile', ['original'=>$sysFileUid]);
	}
}
Copied!

Fal::deleteSysFile() 

\nn\t3::Fal()->deleteSysFile($uidOrObject = NULL); 

Löscht ein SysFile (Datensatz aus Tabelle sys_file) und alle dazugehörigen SysFileReferences. Eine radikale Art, um ein Bild komplett aus der Indizierung von Typo3 zu nehmen.

Die physische Datei wird nicht vom Server gelöscht! Siehe \nn\t3::File()->unlink() zum Löschen der physischen Datei. Siehe \nn\t3::Fal()->detach( $model, $field ); zum Löschen aus einem Model.

\nn\t3::Fal()->deleteSysFile( 1201 );
\nn\t3::Fal()->deleteSysFile( 'fileadmin/pfad/zum/bild.jpg' );
\nn\t3::Fal()->deleteSysFile( \TYPO3\CMS\Core\Resource\File );
\nn\t3::Fal()->deleteSysFile( \TYPO3\CMS\Core\Resource\FileReference );
Copied!

| @param $uidOrObject

| @return integer

Source Code 

public function deleteSysFile( $uidOrObject = null )
{
	$resourceFactory = \nn\t3::injectClass( \TYPO3\CMS\Core\Resource\ResourceFactory::class );
	if (!$uidOrObject) return false;
	if (is_string($uidOrObject) && !is_numeric($uidOrObject)) {
		// Pfad wurde übergeben
		$uidOrObject = \nn\t3::File()->relPath( $uidOrObject );
		$storage = \nn\t3::File()->getStorage($uidOrObject, false);
		if (!$storage) return false;
		$basePath = $storage->getConfiguration()['basePath'];
		$filepathInStorage = substr( $uidOrObject, strlen($basePath) );
		$identifier = '/'.ltrim($filepathInStorage, '/');
		$entry = \nn\t3::Db()->findOneByValues('sys_file', [
			'storage' => $storage->getUid(),
			'identifier' => $identifier,
		]);
		if ($entry) {
			$uid = $entry['uid'];
			$uidOrObject = $uid;
		}
	}
	if (is_a($uidOrObject, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class )) {
		/* \TYPO3\CMS\Core\Resource\FileReference */
		$uid = $uidOrObject->getUid();
		$fileReferenceObject = $resourceFactory->getFileReferenceObject( $uid );
		$fileReferenceObject->getOriginalFile()->delete();
	} else if (is_a($uidOrObject, \TYPO3\CMS\Core\Resource\File::class )) {
		/* \TYPO3\CMS\Core\Resource\File */
		$uid = $uidOrObject->getUid();
		$uidOrObject->delete();
	} else if (is_numeric($uidOrObject)) {
		// uid wurde übergeben
		$uid = $uidOrObject;
		\nn\t3::Db()->delete('sys_file', $uidOrObject);
	}
	if ($uid) {
		// Zugehörge Datensätze aus `sys_file_references` löschen
		\nn\t3::Db()->delete('sys_file_reference', ['uid_local' => $uid], true);
	}
	return $uid;
}
Copied!

Fal::deleteSysFileReference() 

\nn\t3::Fal()->deleteSysFileReference($uidOrFileReference = NULL); 

Löscht eine SysFileReference. Siehe auch \nn\t3::Fal()->detach( $model, $field ); zum Löschen aus einem Model.

\nn\t3::Fal()->deleteSysFileReference( 112 );
\nn\t3::Fal()->deleteSysFileReference( \TYPO3\CMS\Extbase\Domain\Model\FileReference );
Copied!

| @param $uidOrFileReference

| @return mixed

Source Code 

public function deleteSysFileReference( $uidOrFileReference = null )
{
	$uid = null;
	if (is_a($uidOrFileReference, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class )) {
		$uid = $uidOrFileReference->getUid();
	} else if (is_numeric($uidOrFileReference)) {
		$uid = $uidOrFileReference;
	}
	if ($uid) {
		// ToDo: Ab Typo3 v10 prüfen, ob delete() implementiert wurde
		/*
		$resourceFactory = \nn\t3::injectClass( \TYPO3\CMS\Core\Resource\ResourceFactory::class );
		$fileReferenceObject = $resourceFactory->getFileReferenceObject( $uid );
		$fileReferenceObject->delete();
		*/
		// ToDo: Ab Typo3 v8 prüfen, ob das hier nicht einfacher wäre:
		/*
		$fal = $this->persistenceManager->getObjectByIdentifier($uid, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class, false);
		$this->persistenceManager->remove( $fal );
		*/
		\nn\t3::Db()->delete('sys_file_reference', $uid);
	}
}
Copied!

Fal::detach() 

\nn\t3::Fal()->detach($model, $field, $obj = NULL); 

Leert eine ObjectStorage in einem Model oder entfernt ein einzelnes Object vom Model oder einer ObjectStorage. Im Beispiel kann image eine ObjectStorage oder eine einzelne FileReference sein:

\nn\t3::Fal()->detach( $model, 'image' );
\nn\t3::Fal()->detach( $model, 'image', $singleObjToRemove );
Copied!

| @return void

Source Code 

public function detach ( $model, $field, $obj = null )
{
	$propVal = \nn\t3::Obj()->prop($model, $field);
	$isStorage = \nn\t3::Obj()->isStorage( $propVal );
	if ($isStorage) {
		foreach ($propVal->toArray() as $item) {
			if (!$obj || $obj->getUid() == $item->getUid()) {
				$propVal->detach( $item );
			}
		}
	} else if ($propVal) {
		$this->deleteSysFileReference( $propVal );
		\nn\t3::Obj()->set( $model, $field, null, false );
	}
}
Copied!

Fal::fileReferenceExists() 

\nn\t3::Fal()->fileReferenceExists($sysFile = NULL, $params = []); 

Prüft, ob für einen Datensatz bereits eine SysFileReference zum gleichen SysFile exisitert

\nn\t3::Fal()->fileReferenceExists( $sysFile, ['uid_foreign'=>123, 'tablenames'=>'tt_content', 'field'=>'media'] );
Copied!
@param $sysFile
@param array $params => uid_foreign, tablenames, fieldname
@return FileReference|false

Source Code 

public function fileReferenceExists( $sysFile = null, $params = [] )
{
	$where = [
		'uid_local' 	=> $sysFile->getUid(),
		'uid_foreign' 	=> $params['uid'] ?? '',
		'tablenames' 	=> $params['table'],
		'fieldname' 	=> GeneralUtility::camelCaseToLowerCaseUnderscored($params['field']),
	];
	$ref = \nn\t3::Db()->findByValues( 'sys_file_reference', $where );
	if (!$ref) return [];
	// @returns \TYPO3\CMS\Extbase\Domain\Model\FileReference
	return $this->persistenceManager->getObjectByIdentifier($ref[0]['uid'], \TYPO3\CMS\Extbase\Domain\Model\FileReference::class, false);
}
Copied!

Fal::fromFalFile() 

\nn\t3::Fal()->fromFalFile($sysFile = NULL); 

Erzeugt eine sys_file_reference aus einem sys_file

$sysFileRef = \nn\t3::Fal()->fromFalFile( $sysFile );
Copied!
@param \TYPO3\CMS\Core\Resource\File $sysFile
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

Source Code 

public function fromFalFile( $sysFile = null )
{
	$fal = new \TYPO3\CMS\Extbase\Domain\Model\FileReference();
	$falFile = new \TYPO3\CMS\Core\Resource\FileReference([
		'uid_local' => $sysFile->getUid(),
		'uid_foreign' => 0,
		'tablenames' => '',
		'uid' => null,
	]);
	$fal->setOriginalResource( $falFile );
	return $fal;
}
Copied!

Fal::fromFile() 

\nn\t3::Fal()->fromFile($params = []); 

Erzeugt ein FileRefence Objekt (Tabelle: sys_file_reference) und verknüpft es mit einem Datensatz. Beispiel: Hochgeladenes JPG soll als FAL an tt_news-Datensatz angehängt werden

Parameter:

key Beschreibung

| src Pfad zur Quelldatei (kann auch http-Link zu YouTube-Video sein)

| dest Pfad zum Zielordner (optional, falls Datei verschoben/kopiert werden soll)

| table Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. tx_myext_domain_model_entry)

| title Titel

| description Beschreibung

| link Link

| crop Beschnitt

| table Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. tx_myext_domain_model_entry)

| sorting (int) Sortierung

| field Column-Name der Ziel-Tabelle, dem die FileReference zugeordnet werden soll (z.B. image)

| uid (int) uid des Datensatzes in der Zieltabelle (tx_myext_domain_model_entry.uid)

| pid (int) pid des Datensatzes in der Zieltabelle

| cruser_id cruser_id des Datensatzes in der Zieltabelle

| copy src-Datei nicht verschieben sondern kopieren (default: true)

| forceNew Im Zielordner neue Datei erzwingen (sonst wird geprüft, ob bereits Datei existiert) default: false

| single Sicherstellen, dass gleiche FileReferenz nur 1x pro Datensatz verknüpft wird (default: true)

Beispiel:

$fal = \nn\t3::Fal()->fromFile([
    'src'         => 'fileadmin/test/bild.jpg',
    'dest'            => 'fileadmin/test/fal/',
    'pid'         => 132,
    'uid'         => 5052,
    'table'           => 'tx_myext_domain_model_entry',
    'field'           => 'fallistimage'
]);
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference

Source Code 

public function fromFile ( $params = [] )
{
	$params = \nn\t3::Arrays([
		'dest'		=> '',
		'forceNew'	=> false,
		'copy'		=> true,
		'single'	=> true,
	])->merge( $params );
	$fileReferenceRepository = \nn\t3::injectClass( FileReferenceRepository::class );
	$newFile = $this->createFalFile( $params['dest'], $params['src'], $params['copy'], $params['forceNew'] );
	if (!$newFile) return false;
	if ($params['single']) {
		if ($fileReferenceExists = $this->fileReferenceExists( $newFile, $params )) {
			return $fileReferenceExists;
		}
	}
	$fieldname = GeneralUtility::camelCaseToLowerCaseUnderscored($params['field']);
	$entry = [
		'fieldname' 		=> $fieldname,
		'tablenames' 		=> $params['table'],
		'table_local' 		=> 'sys_file',
		'uid_local' 		=> $newFile->getUid(),
		'uid_foreign' 		=> 0,
		'sorting_foreign' 	=> $params['sorting_foreign'] ?? $params['sorting'] ?? time(),
		'pid' 				=> $params['pid'] ?? 0,
		'description' 		=> $params['description'] ?? null,
		'title' 			=> $params['title'] ?? null,
		'link' 				=> $params['link'] ?? '',
		'crop' 				=> $params['crop'] ?? '',
		'tstamp'			=> time(),
		'crdate'			=> time(),
	];
	if ($uid = $params['uid'] ?? null) {
		$entry['uid_foreign'] = $uid;
	}
	$entry = \nn\t3::Db()->insert('sys_file_reference', $entry);
	// @returns \TYPO3\CMS\Extbase\Domain\Model\FileReference
	$persistenceManager = \nn\t3::injectClass(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class);
	return $persistenceManager->getObjectByIdentifier($entry['uid'], \TYPO3\CMS\Extbase\Domain\Model\FileReference::class, false);
}
Copied!

Fal::getFalFile() 

\nn\t3::Fal()->getFalFile($srcFile); 

Holt ein File (FAL) Object (sys_file)

\nn\t3::Fal()->getFalFile( 'fileadmin/image.jpg' );
Copied!
@param string $srcFile
@return \TYPO3\CMS\Core\Resource\File|boolean

Source Code 

public function getFalFile ( $srcFile )
{
	try {
		$srcFile = \nn\t3::File()->stripPathSite( $srcFile );
		$storage = \nn\t3::File()->getStorage( $srcFile, true );
		if (!$storage) return false;
		// \TYPO3\CMS\Core\Resource\File
		$storageBasePath = $storage->getConfiguration()['basePath'];
		$file = $storage->getFile( substr( $srcFile, strlen($storageBasePath) ) );
		return $file;
	} catch( \Exception $e ) {
		return false;
	}
}
Copied!

Fal::getFileObjectFromCombinedIdentifier() 

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier($file = ''); 

Holt ein SysFile aus der CombinedIdentifier-Schreibweise ('1:/uploads/beispiel.txt'). Falls Datei nicht exisitert wird FALSE zurückgegeben.

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier( '1:/uploads/beispiel.txt' );
Copied!
@param string $file Combined Identifier ('1:/uploads/beispiel.txt')
@return File|boolean

Source Code 

public function getFileObjectFromCombinedIdentifier( $file = '' )
{
	$resourceFactory = GeneralUtility::makeInstance( ResourceFactory::class );
	$parts = \nn\t3::Arrays($file)->trimExplode(':');
	$storageUid = (int) ($parts[0] ?? 0);
	$filePath = $parts[1] ?? '';
	
	if (!$storageUid || !$filePath) {
		return false;
	}
	
	try {
		$storage = $resourceFactory->getStorageObject($storageUid);
		if ($storage && $storage->hasFile($filePath)) {
			return $resourceFactory->getFileObjectFromCombinedIdentifier($file);
		}
	} catch (\Exception $e) {
		return false;
	}
	
	return false;
}
Copied!

Fal::getFilePath() 

\nn\t3::Fal()->getFilePath($falReference); 

Die URL zu einer FileReference oder einem FalFile holen. Alias zu \nn\t3::File()->getPublicUrl().

\nn\t3::Fal()->getFilePath( $fileReference );    // ergibt z.B. 'fileadmin/bilder/01.jpg'
Copied!
@param \TYPO3\CMS\Extbase\Domain\Model\FileReference|\TYPO3\CMS\Core\Resource\FileReference $falReference
@return string

Source Code 

public function getFilePath($falReference)
{
	return \nn\t3::File()->getPublicUrl( $falReference );
}
Copied!

Fal::getFileReferenceByUid() 

\nn\t3::Fal()->getFileReferenceByUid($uid = NULL); 

Holt eine SysFileReference anhand der uid Alias zu \nn\t3::Convert( $uid )->toFileReference();

\nn\t3::Fal()->getFileReferenceByUid( 123 );
Copied!
@param $uid
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

Source Code 

public function getFileReferenceByUid( $uid = null )
{
	return \nn\t3::Convert( $uid )->toFileReference();
}
Copied!

Fal::getImage() 

\nn\t3::Fal()->getImage($src = NULL); 

Holt / konvertiert in ein TYPO3CMSCoreResourceFileReference Object (sys_file_reference) "Smarte" Variante zu \TYPO3\CMS\Extbase\Service\ImageService->getImage()

\nn\t3::Fal()->getImage( 1 );
\nn\t3::Fal()->getImage( 'pfad/zum/bild.jpg' );
\nn\t3::Fal()->getImage( $fileReference );
Copied!
@param string|\TYPO3\CMS\Extbase\Domain\Model\FileReference $src
@return \TYPO3\CMS\Core\Resource\FileReference|boolean

Source Code 

public function getImage ( $src = null )
{
	if (!$src) return null;
	$imageService = \nn\t3::injectClass( ImageService::class );
	$treatIdAsReference = is_numeric($src);
	if (is_string($src) || $treatIdAsReference) {
		return $imageService->getImage( $src, null, $treatIdAsReference );
	}
	return $imageService->getImage( '', $src, false );
}
Copied!

Fal::process() 

\nn\t3::Fal()->process($fileObj = '', $processing = []); 

Berechnet ein Bild über maxWidth, maxHeight, cropVariant etc. Gibt URI zum Bild als String zurück. Hilfreich bei der Berechnung von Thumbnails im Backend. Alias zu \nn\t3::File()->process()

\nn\t3::File()->process( 'fileadmin/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFileReference, ['maxWidth'=>200, 'cropVariant'=>'square'] );
Copied!

| @return string

Source Code 

public function process ( $fileObj = '', $processing = [] )
{
	return \nn\t3::File()->process( $fileObj, $processing );
}
Copied!

Fal::setInModel() 

\nn\t3::Fal()->setInModel($model, $fieldName = '', $imagesToAdd = []); 

Ersetzt eine FileReference oder ObjectStorage in einem Model mit Bildern. Typischer Anwendungsfall: Ein FAL-Bild soll über ein Upload-Formular im Frontend geändert werden können.

Für jedes Bild wird geprüft, ob bereits eine FileReference im Model existiert. Bestehende FileReferences werden nicht überschrieben, sonst würden evtl. Bildunterschriften oder Cropping-Anweisungen verloren gehen!

Achtung! Das Model wird automatisch persistiert!

$newModel = new \My\Extension\Domain\Model\Example();
\nn\t3::Fal()->setInModel( $newModel, 'falslideshow', 'path/to/file.jpg' );
echo $newModel->getUid(); // Model wurde persistiert!
Copied!

Beispiel mit einer einfachen FileReference im Model:

$imageToSet = 'fileadmin/bilder/portrait.jpg';
\nn\t3::Fal()->setInModel( $member, 'falprofileimage', $imageToSet );

\nn\t3::Fal()->setInModel( $member, 'falprofileimage', ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'] );
Copied!

Beispiel mit einem einzelnen SysFile:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'image', $file );
Copied!

Beispiel mit einem einzelnen SysFile, das in eine ObjectStorage soll:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'images', [$file] );
Copied!

Beispiel mit einem ObjectStorage im Model:

$imagesToSet = ['fileadmin/bilder/01.jpg', 'fileadmin/bilder/02.jpg', ...];
\nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet );

\nn\t3::Fal()->setInModel( $member, 'falslideshow', [['publicUrl'=>'01.jpg'], ['publicUrl'=>'02.jpg']] );
\nn\t3::Fal()->setInModel( $member, 'falvideos', [['publicUrl'=>'https://youtube.com/?watch=zagd61231'], ...] );
Copied!

Beispiel mit Videos:

$videosToSet = ['https://www.youtube.com/watch?v=GwlU_wsT20Q', ...];
\nn\t3::Fal()->setInModel( $member, 'videos', $videosToSet );
Copied!
@param mixed $model Das Model, das geändert werden soll
@param string $fieldName Property (Feldname) der ObjectStorage oder FileReference
@param mixed $imagesToAdd String / Array mit Bildern

| @return mixed

Source Code 

public function setInModel( $model, $fieldName = '', $imagesToAdd = [] )
{
	if (!$model) \nn\t3::Exception( 'Parameter $model is not a Model' );
	$objHelper = \nn\t3::Obj();
	$repository = \nn\t3::Db()->getRepositoryForModel( $model );
	// Sicher gehen, dass das Model bereits persistiert wurde – ohne uid keine FileReference!
	if (!$model->getUid()) {
		if ($repository) {
			$repository->add( $model );
		}
		\nn\t3::Db()->persistAll();
	}
	$modelUid = $model->getUid();
	if (!$modelUid) return false;
	// Der passende Tabellen-Name in der DB zum Model
	$modelTableName = $objHelper->getTableName( $model );
	// Aktuellen Wert auslesen und ermitteln, ob das Feld eine FileReference oder ObjectStorage ist
	$props = $objHelper->getProps( $model );
	$fieldValue = $objHelper->prop( $model, $fieldName );
	$isObjectStorage = is_a( $props[$fieldName], ObjectStorage::class, true );
	$isSysFileReference = is_a($props[$fieldName], SysFileReference::class, true );
	if ($isObjectStorage && !$fieldValue) {
		$objHelper->set( $model, $fieldName, new ObjectStorage() );
	}
	// Array der bereits bestehenden FileReferences erzeugen mit Pfad zu Bildern als Key
	$existingFileReferencesByPublicUrl = [];
	if ($fieldValue) {
		if (!$isObjectStorage) {
			$fieldValue = [$fieldValue];
		}
		foreach ($fieldValue as $sysFileRef) {
			$publicUrl = $sysFileRef->getOriginalResource()->getPublicUrl();
			$existingFileReferencesByPublicUrl[$publicUrl] = $sysFileRef;
		}
	}
	// Normalisieren der Pfadangaben zu den Bildern.
	// Aus 'pfad/zum/bild.jpg' wird ['publicUrl'=>'pfad/zum/bild.jpg']
	if (is_string($imagesToAdd)) {
		$imagesToAdd = ['publicUrl'=>$imagesToAdd];
	}
	// Grundsätzlich mit Arrays arbeiten, vereinfacht die Logik unten.
	// Aus ['publicUrl'=>'pfad/zum/bild.jpg'] wird [['publicUrl'=>'pfad/zum/bild.jpg']]
	if (is_array($imagesToAdd) && isset($imagesToAdd['publicUrl'])) {
		$imagesToAdd = [$imagesToAdd];
	}
	// sysFiles und sysFileReferences erlauben
	if ($objHelper->isFalFile($imagesToAdd) || $objHelper->isFile($imagesToAdd)) {
		$imagesToAdd = [$imagesToAdd];
	}
	// Aus ['01.jpg', '02.jpg', ...] wird [['publicUrl'=>'01.jpg'], ['publicUrl'=>'02.jpg'], ...]
	foreach ($imagesToAdd as $k=>$v) {
		if (is_string($v)) {
			$imagesToAdd[$k] = ['publicUrl'=>$v];
		}
	}
	// Durch die Liste der neuen Bilder gehen ...
	foreach ($imagesToAdd as $n=>$imgObj) {
		// Bereits ein falFile oder eine sysFileReference
		if ($objHelper->isFile($imgObj) || $objHelper->isFalFile($imgObj)) {
			continue;
		}
		$imgToAdd = $imgObj['publicUrl'];
		$publicUrl = \nn\t3::File()->stripPathSite( $imgToAdd );
		// Falls bereits eine FileReference zu dem gleichen Bild existiert, diese verwenden
		$value = $existingFileReferencesByPublicUrl[$publicUrl] ?? '' ?: $publicUrl;
		// Falls das Bild noch nicht im Model existierte, eine neue FileReference erzeugen
		if (is_string($value)) {
			$falParams = [
				'src'		   => $value,
				'title'			=> $imgObj['title'] ?? '',
				'description'	=> $imgObj['description'] ?? '',
				'link'			=> $imgObj['link'] ?? '',
				'crop'			=> $imgObj['crop'] ?? '',
				'pid'		   => $model->getPid(),
				'uid'		   => $model->getUid(),
				'table'		 => $modelTableName,
				'field'		 => $fieldName,
			];
			$value = $this->fromFile( $falParams );
		}
		// Sollte etwas schief gegangen sein, ist $value == FALSE
		if ($value) {
			$imagesToAdd[$n] = $value;
		}
	}
	if ($isSysFileReference) {
		// Feld ist eine SysFileReference (ohne ObjectStorage)
		$objectToSet = $imagesToAdd[0] ?? false;
	} else if ($isObjectStorage) {
		// Feld ist eine ObjectStorage: Neue ObjectStorage zum Ersetzen der bisherigen erzeugen
		$objectToSet = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage;
		foreach ($imagesToAdd as $n=>$imgToAdd) {
			if ($objHelper->isFile( $imgToAdd )) {
				$imgToAdd = \nn\t3::Fal()->fromFalFile( $imgToAdd );
			}
			$objectToSet->attach( $imgToAdd );
		}
	} else {
		// Feld ist keine ObjectStorage: Also einfach die erste FileReference verwenden.
		$objectToSet = array_shift($imagesToAdd);
		if (!$objectToSet && $existingFileReferencesByPublicUrl) {
			// FileReference soll entfernt werden
			foreach ($existingFileReferencesByPublicUrl as $sysFileRef) {
				$this->deleteSysFileReference( $sysFileRef );
			}
		}
	}
	// Property im Model aktualisieren
	if ($objectToSet) {
		$objHelper->set( $model, $fieldName, $objectToSet );
	}
	// Model aktualisieren
	if ($repository) {
		$repository->update( $model );
		\nn\t3::Db()->update( $model );
	}
	return $model;
}
Copied!

Fal::toArray() 

\nn\t3::Fal()->toArray($fileReference = NULL); 

Eine FileReference in ein Array konvertieren. Enthält publicUrl, title, alternative, crop etc. der FileReference. Alias zu \nn\t3::Obj()->toArray( $fileReference );

\nn\t3::Fal()->toArray( $fileReference );    // ergibt ['publicUrl'=>'fileadmin/...', 'title'=>'...']
Copied!
@param \TYPO3\CMS\Extbase\Domain\Model\FileReference $falReference
@return array

Source Code 

public function toArray(\TYPO3\CMS\Extbase\Domain\Model\FileReference $fileReference = NULL)
{
	return \nn\t3::Obj()->toArray( $fileReference );
}
Copied!

Fal::updateMetaData() 

\nn\t3::Fal()->updateMetaData($filenameOrSysFile = '', $data = []); 

Update der Angaben in sys_file_metadata und sys_file

\nn\t3::Fal()->updateMetaData( 'fileadmin/file.jpg' );
\nn\t3::Fal()->updateMetaData( $fileReference );
\nn\t3::Fal()->updateMetaData( $falFile );
Copied!
@param $filenameOrSysFile FAL oder Pfad (String) zu der Datei
@param $data Array mit Daten, die geupdated werden sollen. Falls leer, werden Bilddaten automatisch gelesen
@return void

Source Code 

public function updateMetaData ( $filenameOrSysFile = '', $data = [] )
{
	if (is_string($filenameOrSysFile)) {
		if ($falFile = $this->getFalFile( $filenameOrSysFile )) {
			$filenameOrSysFile = $falFile;
		}
	}
	if (!$data) {
		$data = \nn\t3::File()->getData( $filenameOrSysFile );
	}
	$storage = \nn\t3::File()->getStorage( $filenameOrSysFile );
	$publicUrl = \nn\t3::File()->getPublicUrl( $filenameOrSysFile );
	$destinationFile = GeneralUtility::makeInstance( ResourceFactory::class )->retrieveFileOrFolderObject($publicUrl);
	$indexer = GeneralUtility::makeInstance(Indexer::class, $storage);
	$indexer->updateIndexEntry($destinationFile);
}
Copied!

File 

\nn\t3::File() 

Methoden rund um das Dateisystem: Lesen, Schreiben, Kopieren, Verschieben und Bereinigen von Dateien.

Overview of Methods 

\nn\t3::File()->absUrl($file = NULL); 

Absolute URL zu einer Datei generieren. Gibt den kompletten Pfad zur Datei inkl. https://.../ zurück.

// => https://www.myweb.de/fileadmin/bild.jpg
\nn\t3::File()->absUrl( 'fileadmin/bild.jpg' );
\nn\t3::File()->absUrl( 'https://www.myweb.de/fileadmin/bild.jpg' );
\nn\t3::File()->absUrl( $sysFileReference );
\nn\t3::File()->absUrl( $falFile );
Copied!
@param string|\TYPO3\CMS\Core\Resource\FileReference|\TYPO3\CMS\Core\Resource\File $file
@return string

| ➜ Go to source code of File::absUrl()

\nn\t3::File()->addPathSite($file); 

Gibt Pfad zu Datei / Ordner MIT absoluten Pfad

Beispiel:

\nn\t3::File()->addPathSite('fileadmin/test.jpg');
 // ==> gibt var/www/website/fileadmin/test.jpg zurück
Copied!

| @return string

| ➜ Go to source code of File::addPathSite()

\nn\t3::File()->addSuffix($filename = NULL, $newSuffix = ''); 

Ersetzt den suffix für einen Dateinamen.

\nn\t3::File()->addSuffix('bild', 'jpg');                //  => bild.jpg
\nn\t3::File()->addSuffix('bild.png', 'jpg');            //  => bild.jpg
\nn\t3::File()->addSuffix('pfad/zu/bild.png', 'jpg');    //  => pfad/zu/bild.jpg
Copied!

| @return string

| ➜ Go to source code of File::addSuffix()

\nn\t3::File()->cleanFilename($filename = ''); 

Bereinigt einen Dateinamen

$clean = \nn\t3::File()->cleanFilename('fileadmin/nö:so nicht.jpg');   // 'fileadmin/noe_so_nicht.jpg'
Copied!

| @return string

| ➜ Go to source code of File::cleanFilename()

\nn\t3::File()->copy($src = NULL, $dest = NULL, $renameIfFileExists = true); 

Kopiert eine Datei. Gibt false zurück, falls die Datei nicht kopiert werden konnte. Gibt (neuen) Dateinamen zurück, falls das Kopieren erfolgreich war.

$filename = \nn\t3::File()->copy('fileadmin/bild.jpg', 'fileadmin/bild-kopie.jpg');
Copied!
@param string $src Pfad zur Quelldatei
@param string $dest Pfad zur Zieldatei
@param boolean $renameIfFileExists Datei umbenennen, falls am Zielort bereits Datei mit gleichem Namen existiert
@return string|boolean

| ➜ Go to source code of File::copy()

\nn\t3::File()->createFolder($path = NULL); 

Einen Ordner im fileadmin/ erzeugen. Um einen Ordner außerhalb des fileadmin anzulegen, die Methode \nn\t3::File()->mkdir() verwenden.

\nn\t3::File()->createFolder('tests');
Copied!

| @return boolean

| ➜ Go to source code of File::createFolder()

\nn\t3::File()->download($files = NULL, $filename = NULL); 

Download einer einzelnen Datei oder eines gezippten Archives.

Download als ZIP erfordert die PHP-Extension gmp. Falls Extension nicht vorhanden ist, wird auf .tar-Variante ausgewichen. Bei Mac verwendet die Funktion aufgrund von Sicherheitswarnungen des Finders grundsätzlich tar

\nn\t3::File()->download( 'fileadmin/test.pdf' );
\nn\t3::File()->download( $fileReference );
\nn\t3::File()->download( $sysFile );
\nn\t3::File()->download( 'fileadmin/test.pdf', 'download.pdf' );
Copied!

Wird ein Array übergeben, wird ein tar/zip-Download gestartet. Durch Übergabe eines assoziativen Arrays mit Dateiname als key und Pfad im Archiv als value Kann die Datei- und Ordnerstruktur im zip-Archiv bestimmt werden.

\nn\t3::File()->download( ['fileadmin/test-1.pdf', 'fileadmin/test-2.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'eins.pdf', 'fileadmin/test-2.pdf'=>'zwei.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'zip-folder-1/eins.pdf', 'fileadmin/test-2.pdf'=>'zip-folder-2/zwei.pdf'], 'archive.zip' );
Copied!
@param mixed $files String oder Array der Dateien, die geladen werden sollen
@param mixed $filename Optional: Dateinamen überschreiben beim Download
@return void

| ➜ Go to source code of File::download()

\nn\t3::File()->exists($src = NULL); 

Prüft, ob eine Datei existiert. Gibt absoluten Pfad zur Datei zurück.

\nn\t3::File()->exists('fileadmin/bild.jpg');
Copied!

Existiert auch als ViewHelper:

{nnt3:file.exists(file:'pfad/zum/bild.jpg')}
Copied!

| @return string|boolean

| ➜ Go to source code of File::exists()

\nn\t3::File()->extractExifData($filename = ''); 

EXIF Daten für Datei in JSON speichern.

\nn\t3::File()->extractExifData( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::extractExifData()

\nn\t3::File()->getData($file = ''); 

Imageinfo + EXIF Data für Datei holen. Sucht auch nach JSON-Datei, die evtl. nach processImage() generiert wurde

| @return array

| ➜ Go to source code of File::getData()

\nn\t3::File()->getExifData($filename = ''); 

ALLE EXIF Daten für Datei holen.

\nn\t3::File()->getExif( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getExifData()

\nn\t3::File()->getFolder($file); 

Gibt den Ordner zu einer Datei zurück

Beispiel:

\nn\t3::File()->getFolder('fileadmin/test/beispiel.txt');
// ==> gibt 'fileadmin/test/' zurück
Copied!

| @return string

| ➜ Go to source code of File::getFolder()

\nn\t3::File()->getImageData($filename = ''); 

EXIF Bild-Daten für Datei holen.

\nn\t3::File()->getImageData( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getImageData()

\nn\t3::File()->getImageSize($filename = ''); 

imagesize für Datei holen.

\nn\t3::File()->getImageSize( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getImageSize()

\nn\t3::File()->getLocationData($filename = ''); 

EXIF GEO-Daten für Datei holen. Adressdaten werden automatisch ermittelt, falls möglich

\nn\t3::File()->getLocationData( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getLocationData()

\nn\t3::File()->getPath($file, $storage = NULL, $absolute = true); 

Gibt den Pfad einer Datei anhand eines Dateinamens und der Storage wieder. Beispiel:

\nn\t3::File()->getPath('media/bild.jpg', $storage);
// ==> gibt '/var/www/.../fileadmin/media/bild.jpg' zurück
\nn\t3::File()->getPath('fileadmin/media/bild.jpg');
// ==> gibt '/var/www/.../fileadmin/media/bild.jpg' zurück
Copied!

| @return string

| ➜ Go to source code of File::getPath()

\nn\t3::File()->getPublicUrl($obj = NULL, $absolute = false); 

Holt Pfad zur Datei, relativ zum Typo3-Installtionsverzeichnis (PATH_site). Kann mit allen Arten von Objekten umgehen.

\nn\t3::File()->getPublicUrl( $falFile );        // \TYPO3\CMS\Core\Resource\FileReference
\nn\t3::File()->getPublicUrl( $fileReference );  // \TYPO3\CMS\Extbase\Domain\Model\FileReference
\nn\t3::File()->getPublicUrl( $folder );         // \TYPO3\CMS\Core\Resource\Folder
\nn\t3::File()->getPublicUrl( $folder, true );   // https://.../fileadmin/bild.jpg
Copied!

| @return string

| ➜ Go to source code of File::getPublicUrl()

\nn\t3::File()->getRelativePathInStorage($file, $storage = NULL); 

Gibt den relativen Pfad einer Datei zur angegebenen Storage wieder.

Beispiel:

\nn\t3::File()->getRelativePathInStorage('fileadmin/media/bild.jpg', $storage);
// ==> gibt 'media/bild.jpg' zurück
Copied!

| @return string

| ➜ Go to source code of File::getRelativePathInStorage()

\nn\t3::File()->getStorage($file, $createIfNotExists = false); 

Findet ein passendes sys_file_storage zu einem Datei- oder Ordnerpfad. Durchsucht dazu alle sys_file_storage-Einträge und vergleicht, ob der basePath des Storages zum Pfad der Datei passt.

\nn\t3::File()->getStorage('fileadmin/test/beispiel.txt');
\nn\t3::File()->getStorage( $falFile );
\nn\t3::File()->getStorage( $sysFileReference );
// gibt ResourceStorage mit basePath "fileadmin/" zurück
Copied!

| @return ResourceStorage

| ➜ Go to source code of File::getStorage()

\nn\t3::File()->isAllowed($filename = NULL); 

Gibt an, ob der Dateityp erlaubt ist

\nn\t3::File()->isForbidden('bild.jpg');   => gibt 'true' zurück
\nn\t3::File()->isForbidden('hack.php');   => gibt 'false' zurück
Copied!

| @return boolean

| ➜ Go to source code of File::isAllowed()

\nn\t3::File()->isConvertableToImage($filename = NULL); 

Gibt an, ob die Datei in ein Bild konvertiert werden kann

\nn\t3::File()->isConvertableToImage('bild.jpg');  => gibt true zurück
\nn\t3::File()->isConvertableToImage('text.ppt');  => gibt false zurück
Copied!

| @return boolean

| ➜ Go to source code of File::isConvertableToImage()

\nn\t3::File()->isExternalVideo($url = NULL); 

Gibt an, ob es ein Video auf YouTube / Vimeo ist. Falls ja, wird ein Array mit Angaben zum Einbetten zurückgegeben.

\nn\t3::File()->isExternalVideo('http://...');
Copied!

| @return array|boolean

| ➜ Go to source code of File::isExternalVideo()

\nn\t3::File()->isFolder($file); 

Gibt zurück, ob angegebener Pfad ein Ordner ist

Beispiel:

\nn\t3::File()->isFolder('fileadmin'); // => gibt true zurück
Copied!

| @return boolean

| ➜ Go to source code of File::isFolder()

\nn\t3::File()->isForbidden($filename = NULL, $allowed = []); 

Gibt an, ob der Dateityp verboten ist

\nn\t3::File()->isForbidden('bild.jpg');                   => gibt 'false' zurück
\nn\t3::File()->isForbidden('bild.xyz', ['xyz']);        => gibt 'false' zurück
\nn\t3::File()->isForbidden('hack.php');                   => gibt 'true' zurück
\nn\t3::File()->isForbidden('.htaccess');              => gibt 'true' zurück
Copied!
@param string $filename
@param array $allowed
@return boolean

| ➜ Go to source code of File::isForbidden()

\nn\t3::File()->isImage($filename = NULL); 

Gibt an, ob die Datei in ein Bild ist

\nn\t3::File()->isImage('bild.jpg');   => gibt true zurück
\nn\t3::File()->isImage('text.ppt');   => gibt false zurück
Copied!

| @return boolean

| ➜ Go to source code of File::isImage()

\nn\t3::File()->isVideo($filename = NULL); 

Gibt an, ob die Datei ein Video ist

\nn\t3::File()->isVideo('pfad/zum/video.mp4');     => gibt true zurück
Copied!

| @return boolean

| ➜ Go to source code of File::isVideo()

\nn\t3::File()->mkdir($path = ''); 

Einen Ordner anlegen

\nn\t3::File()->mkdir( 'fileadmin/mein/ordner/' );
\nn\t3::File()->mkdir( '1:/mein/ordner/' );
Copied!

| @return boolean

| ➜ Go to source code of File::mkdir()

\nn\t3::File()->move($src = NULL, $dest = NULL); 

Verschiebt eine Datei

\nn\t3::File()->move('fileadmin/bild.jpg', 'fileadmin/bild-kopie.jpg');
Copied!

| @return boolean

| ➜ Go to source code of File::move()

\nn\t3::File()->moveUploadedFile($src = NULL, $dest = NULL); 

Eine Upload-Datei ins Zielverzeichnis verschieben.

Kann absoluter Pfad zur tmp-Datei des Uploads sein – oder ein TYPO3\CMS\Core\Http\UploadedFile, das sich im Controller über $this->request->getUploadedFiles() holen lässt.

\nn\t3::File()->moveUploadedFile('/tmp/xjauGSaudsha', 'fileadmin/bild-kopie.jpg');
\nn\t3::File()->moveUploadedFile( $fileObj, 'fileadmin/bild-kopie.jpg');
Copied!

| @return string

| ➜ Go to source code of File::moveUploadedFile()

\nn\t3::File()->normalizePath($path); 

Löst ../../-Angaben in Pfad auf. Funktioniert sowohl mit existierenden Pfaden (per realpath) als auch nicht-existierenden Pfaden.

\nn\t3::File()->normalizePath( 'fileadmin/test/../bild.jpg' );     =>   fileadmin/bild.jpg
Copied!

| @return string

| ➜ Go to source code of File::normalizePath()

\nn\t3::File()->process($fileObj = '', $processing = [], $returnProcessedImage = false); 

Berechnet ein Bild über maxWidth, maxHeight etc. Einfache Version von \nn\t3::File()->processImage() Kann verwendet werden, wenn es nur um das Generieren von verkleinerten Bilder geht ohne Berücksichtigung von Korrekturen der Kamera-Ausrichtung etc.

Da die Crop-Einstellungen in FileReference und nicht File gespeichert sind, funktioniert cropVariant nur bei Übergabe einer FileReference.

\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200, 'absolute'=>true] );
\nn\t3::File()->process( $sysFileReference, ['maxWidth'=>200, 'cropVariant'=>'square'] );
Copied!

Mit dem Parameter $returnProcessedImage = true wird nicht der Dateipfad zum neuen Bild sondern das processedImage-Object zurückgegeben.

\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200], true );
Copied!

| @return string

| ➜ Go to source code of File::process()

\nn\t3::File()->processImage($filenameOrSysFile = '', $processing = []); 

Kann direkt nach dem upload_copy_move() aufgerufen werden. Korrigiert die Ausrichtung des Bildes, die evtl. in EXIF-Daten gespeichert wurde. Für einfach maxWidth-Anweis ungen die Methode \nn\t3::File()->process() verwenden.

Anweisungen für $processing:

| correctOrientation => Drehung korrigieren (z.B. weil Foto vom Smartphone hochgeladen wurde)

| @return string

| ➜ Go to source code of File::processImage()

\nn\t3::File()->read($src = NULL); 

Holt den Inhalt einer Datei

\nn\t3::File()->read('fileadmin/text.txt');
Copied!

| @return string|boolean

| ➜ Go to source code of File::read()

\nn\t3::File()->relPath($path = ''); 

relativen Pfad (vom aktuellen Script aus) zum einer Datei / Verzeichnis zurück. Wird kein Pfad angegeben, wird das Typo3-Root-Verzeichnis zurückgegeben.

\nn\t3::File()->relPath( $file );        => ../fileadmin/bild.jpg
\nn\t3::File()->relPath();               => ../
Copied!

| @return string

| ➜ Go to source code of File::relPath()

\nn\t3::File()->resolvePathPrefixes($file = NULL, $absolute = false); 

EXT: Prefix auflösen zu relativer Pfadangabe

\nn\t3::File()->resolvePathPrefixes('EXT:extname');                    => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/');               => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/bild.jpg');       => /typo3conf/ext/extname/bild.jpg
\nn\t3::File()->resolvePathPrefixes('1:/uploads/bild.jpg', true);  => /var/www/website/fileadmin/uploads/bild.jpg
Copied!

| @return string

| ➜ Go to source code of File::resolvePathPrefixes()

\nn\t3::File()->sendDownloadHeader($filename = '', $filesize = NULL); 

PHP Header für Download senden. Wenn die Datei physisch existiert, wird die filesize automatisch ermittelt.

\nn\t3::File()->sendDownloadHeader( 'download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'pfad/zur/datei/download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'fakedatei.jpg', 1200 );
Copied!

| @return void

| ➜ Go to source code of File::sendDownloadHeader()

\nn\t3::File()->size($src = NULL); 

Gibt Dateigröße zu einer Datei in Bytes zurück Falls Datei nicht exisitert, wird 0 zurückgegeben.

\nn\t3::File()->size('fileadmin/bild.jpg');
Copied!

| @return integer

| ➜ Go to source code of File::size()

\nn\t3::File()->stripBaseUrl($file); 

Entfernt die URL, falls sie der aktuellen Domain entspricht

Beispiel:

\nn\t3::File()->stripBaseUrl('https://www.my-web.de/fileadmin/test.jpg');  ==> fileadmin/test.jpg
\nn\t3::File()->stripBaseUrl('https://www.other-web.de/example.jpg');      ==> https://www.other-web.de/example.jpg
Copied!

| @return string

| ➜ Go to source code of File::stripBaseUrl()

\nn\t3::File()->stripPathSite($file, $prefix = false); 

Gibt Pfad zu Datei / Ordner OHNE absoluten Pfad. Optional kann ein Prefix angegeben werden.

Beispiel:

\nn\t3::File()->stripPathSite('var/www/website/fileadmin/test.jpg');       ==>  fileadmin/test.jpg
\nn\t3::File()->stripPathSite('var/www/website/fileadmin/test.jpg', true); ==>  var/www/website/fileadmin/test.jpg
\nn\t3::File()->stripPathSite('fileadmin/test.jpg', true);                 ==>  var/www/website/fileadmin/test.jpg
\nn\t3::File()->stripPathSite('fileadmin/test.jpg', '../../');               ==>  ../../fileadmin/test.jpg
Copied!

| @return string

| ➜ Go to source code of File::stripPathSite()

\nn\t3::File()->suffix($filename = NULL); 

Gibt den Suffix der Datei zurück

\nn\t3::File()->suffix('bild.jpg');    => gibt 'jpg' zurück
Copied!

| @return string

| ➜ Go to source code of File::suffix()

\nn\t3::File()->suffixForMimeType($mime = ''); 

Gibt den Suffix für einen bestimmten Mime-Type / Content-Type zurück. Sehr reduzierte Variante – nur wenige Typen abgedeckt. Umfangreiche Version: https://bit.ly/3B9KrNA

\nn\t3::File()->suffixForMimeType('image/jpeg');   => gibt 'jpg' zurück
Copied!

| @return string

| ➜ Go to source code of File::suffixForMimeType()

\nn\t3::File()->type($filename = NULL); 

Gibt die Art der Datei anhand des Datei-Suffixes zurück

\nn\t3::File()->type('bild.jpg');  => gibt 'image' zurück
\nn\t3::File()->type('text.doc');  => gibt 'document' zurück
Copied!

| @return string

| ➜ Go to source code of File::type()

\nn\t3::File()->uniqueFilename($filename = ''); 

Erzeugt einen eindeutigen Dateinamen für die Datei, falls im Zielverzeichnis bereits eine Datei mit identischem Namen existiert.

$name = \nn\t3::File()->uniqueFilename('fileadmin/01.jpg');    // 'fileadmin/01-1.jpg'
Copied!

| @return string

| ➜ Go to source code of File::uniqueFilename()

\nn\t3::File()->write($path = NULL, $content = NULL); 

Einen Ordner und/oder Datei erzeugen. Legt auch die Ordner an, falls sie nicht existieren.

\nn\t3::File()->write('fileadmin/some/deep/folder/');
\nn\t3::File()->write('1:/some/deep/folder/');
\nn\t3::File()->write('fileadmin/some/deep/folder/file.json', 'TEXT');
Copied!

| @return boolean

| ➜ Go to source code of File::write()

Methods 

File::absPath() 

File::absUrl() 

\nn\t3::File()->absUrl($file = NULL); 

Absolute URL zu einer Datei generieren. Gibt den kompletten Pfad zur Datei inkl. https://.../ zurück.

// => https://www.myweb.de/fileadmin/bild.jpg
\nn\t3::File()->absUrl( 'fileadmin/bild.jpg' );
\nn\t3::File()->absUrl( 'https://www.myweb.de/fileadmin/bild.jpg' );
\nn\t3::File()->absUrl( $sysFileReference );
\nn\t3::File()->absUrl( $falFile );
Copied!
@param string|\TYPO3\CMS\Core\Resource\FileReference|\TYPO3\CMS\Core\Resource\File $file
@return string

Source Code 

public function absUrl($file = null)
{
	if (is_object($file)) {
		$file = $this->getPublicUrl($file);
	}
	if (substr($file, 0, 4) == 'EXT:') {
		$absoluteFilePath = GeneralUtility::getFileAbsFileName($file);
		$file = PathUtility::getAbsoluteWebPath($absoluteFilePath);
	}
	$baseUrl = \nn\t3::Environment()->getBaseURL();
	$file = $this->stripPathSite($file);
	$file = str_replace($baseUrl, '', $file);
	return $baseUrl . ltrim($file, '/');
}
Copied!

File::addPathSite() 

\nn\t3::File()->addPathSite($file); 

Gibt Pfad zu Datei / Ordner MIT absoluten Pfad

Beispiel:

\nn\t3::File()->addPathSite('fileadmin/test.jpg');
 // ==> gibt var/www/website/fileadmin/test.jpg zurück
Copied!

| @return string

Source Code 

public function addPathSite($file)
{
	return $this->stripPathSite($file, true);
}
Copied!

File::addSuffix() 

\nn\t3::File()->addSuffix($filename = NULL, $newSuffix = ''); 

Ersetzt den suffix für einen Dateinamen.

\nn\t3::File()->addSuffix('bild', 'jpg');                //  => bild.jpg
\nn\t3::File()->addSuffix('bild.png', 'jpg');            //  => bild.jpg
\nn\t3::File()->addSuffix('pfad/zu/bild.png', 'jpg');    //  => pfad/zu/bild.jpg
Copied!

| @return string

Source Code 

public function addSuffix($filename = null, $newSuffix = '')
{
	$suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
	if ($suffix) {
		$filename = substr($filename, 0, -strlen($suffix) - 1);
	}
	return $filename . '.' . $newSuffix;
}
Copied!

File::cleanFilename() 

\nn\t3::File()->cleanFilename($filename = ''); 

Bereinigt einen Dateinamen

$clean = \nn\t3::File()->cleanFilename('fileadmin/nö:so nicht.jpg');   // 'fileadmin/noe_so_nicht.jpg'
Copied!

| @return string

Source Code 

public function cleanFilename($filename = '')
{
	$path = pathinfo($filename, PATHINFO_DIRNAME) . '/';
	$suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
	$filename = pathinfo($filename, PATHINFO_FILENAME);
	$filename = GeneralUtility::makeInstance(CharsetConverter::class)->utf8_char_mapping($filename);
	$cleanFilename = utf8_decode($filename);
	$cleanFilename = strtolower(preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . '\\xC0-\\xFF]/', '_', trim($cleanFilename)));
	$cleanFilename = str_replace(['@'], '_', $cleanFilename);
	if ($secondSuffix = pathinfo($cleanFilename, PATHINFO_EXTENSION)) {
		$cleanFilename = substr($cleanFilename, 0, -strlen($secondSuffix));
		$suffix = "{$secondSuffix}.{$suffix}";
	}
	$cleanFilename = preg_replace('/_+/', '_', $cleanFilename);
	$cleanFilename = substr($cleanFilename, 0, 64 - strlen($suffix) - 1);
	return $path . rtrim($cleanFilename, '.') . ".{$suffix}";
}
Copied!

File::copy() 

\nn\t3::File()->copy($src = NULL, $dest = NULL, $renameIfFileExists = true); 

Kopiert eine Datei. Gibt false zurück, falls die Datei nicht kopiert werden konnte. Gibt (neuen) Dateinamen zurück, falls das Kopieren erfolgreich war.

$filename = \nn\t3::File()->copy('fileadmin/bild.jpg', 'fileadmin/bild-kopie.jpg');
Copied!
@param string $src Pfad zur Quelldatei
@param string $dest Pfad zur Zieldatei
@param boolean $renameIfFileExists Datei umbenennen, falls am Zielort bereits Datei mit gleichem Namen existiert
@return string|boolean

Source Code 

public function copy($src = null, $dest = null, $renameIfFileExists = true)
{
	if (!file_exists($src)) return false;
	if (!$renameIfFileExists && $this->exists($dest)) return false;
	$dest = $this->uniqueFilename($dest);
	$path = pathinfo($dest, PATHINFO_DIRNAME) . '/';
	// Ordner anlegen, falls noch nicht vorhanden
	\nn\t3::Storage()->getFolder($path);
	\TYPO3\CMS\Core\Utility\GeneralUtility::upload_copy_move($src, $dest);
	return $this->exists($dest) ? $dest : false;
}
Copied!

File::createFolder() 

\nn\t3::File()->createFolder($path = NULL); 

Einen Ordner im fileadmin/ erzeugen. Um einen Ordner außerhalb des fileadmin anzulegen, die Methode \nn\t3::File()->mkdir() verwenden.

\nn\t3::File()->createFolder('tests');
Copied!

| @return boolean

Source Code 

public function createFolder($path = null)
{
	$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
	$defaultStorage = $resourceFactory->getDefaultStorage();
	$basePath = \nn\t3::Environment()->getPathSite() . $defaultStorage->getConfiguration()['basePath'];
	if (file_exists($basePath . $path)) return true;
	$defaultStorage->createFolder($path);
}
Copied!

File::download() 

\nn\t3::File()->download($files = NULL, $filename = NULL); 

Download einer einzelnen Datei oder eines gezippten Archives.

Download als ZIP erfordert die PHP-Extension gmp. Falls Extension nicht vorhanden ist, wird auf .tar-Variante ausgewichen. Bei Mac verwendet die Funktion aufgrund von Sicherheitswarnungen des Finders grundsätzlich tar

\nn\t3::File()->download( 'fileadmin/test.pdf' );
\nn\t3::File()->download( $fileReference );
\nn\t3::File()->download( $sysFile );
\nn\t3::File()->download( 'fileadmin/test.pdf', 'download.pdf' );
Copied!

Wird ein Array übergeben, wird ein tar/zip-Download gestartet. Durch Übergabe eines assoziativen Arrays mit Dateiname als key und Pfad im Archiv als value Kann die Datei- und Ordnerstruktur im zip-Archiv bestimmt werden.

\nn\t3::File()->download( ['fileadmin/test-1.pdf', 'fileadmin/test-2.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'eins.pdf', 'fileadmin/test-2.pdf'=>'zwei.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'zip-folder-1/eins.pdf', 'fileadmin/test-2.pdf'=>'zip-folder-2/zwei.pdf'], 'archive.zip' );
Copied!
@param mixed $files String oder Array der Dateien, die geladen werden sollen
@param mixed $filename Optional: Dateinamen überschreiben beim Download
@return void

Source Code 

public function download($files = null, $filename = null)
{
	\nn\t3::autoload();
	ob_end_clean();
	if (!is_array($files)) $files = [$files];
	// FE.compressionLevel in der LocalConfiguration angegeben? Dann hier deaktivieren!
	if ($GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel']) {
		header('Content-Encoding: none');
		if (function_exists('apache_setenv')) {
			apache_setenv('no-gzip', '1');
		}
		if (extension_loaded('zlib')) {
			@ini_set('zlib.output_compression', 'off');
			@ini_set('zlib.output_compression_level', '0');
		}
	}
	// Nur eine Datei angegeben, dann einfacher Download
	if (count($files) == 1) {
		$k = key($files);
		if (!is_numeric($k)) {
			// ['pfad/zur/datei.pdf' => 'downloadname.pdf']
			$path = $this->absPath($k);
			$filenameForDownload = $files[$k];
		} else {
			// ['pfad/zur/datei.pdf']
			$path = $this->absPath($files[$k]);
			$filenameForDownload = pathinfo($path, PATHINFO_BASENAME);
		}
		if (!$path) {
			die('Could not resolve absolute file path for download.');
		}
		\nn\t3::File()->sendDownloadHeader($filenameForDownload);
		readfile($path);
		die();
	}
	$archiveFilename = $filename ?: 'download-' . date('Y-m-d');
	$stream = fopen('php://output', 'w');
	$opt = [];
	// gmp_init ist auf dem Server erforderlich für zip-Stream. Falls nicht vorhanden, auf .tar ausweichen
	if (function_exists('gmp_init')) {
		$zipStream = \Barracuda\ArchiveStream\Archive::instance_by_useragent($archiveFilename, $opt, $stream);
	} else {
		$zipStream = new \Barracuda\ArchiveStream\TarArchive($archiveFilename . '.tar', $opt, null, $stream);
	}
	$filesInArchive = [];
	foreach ($files as $k => $file) {
		$filenameInArchive = basename($file);
		// ['fileadmin/test.pdf' => 'ordername_im_archiv/beispiel.pdf'] wurde übergeben
		if (!is_numeric($k)) {
			$filenameInArchive = $file;
			$file = $k;
		}
		$file = $this->absPath($file);
		if ($filesize = $this->size($file)) {
			// Gleicher Dateiname bereits im Archiv vorhanden? Dann "-cnt" anhängen
			if ($filesInArchive[$filenameInArchive]) {
				$cnt = $filesInArchive[$filenameInArchive]++;
				$filenameInArchive = pathinfo($filenameInArchive, PATHINFO_FILENAME) . '-' . $cnt . '.' . pathinfo($filenameInArchive, PATHINFO_EXTENSION);
			} else {
				$filesInArchive[$filenameInArchive] = 1;
			}
			$zipStream->init_file_stream_transfer($filenameInArchive, $filesize);
			$fileStream = fopen($file, 'r');
			while ($buffer = fread($fileStream, 256000)) {
				$zipStream->stream_file_part($buffer);
			}
			fclose($fileStream);
			$zipStream->complete_file_stream();
		}
	}
	$zipStream->finish();
	die();
}
Copied!

File::exists() 

\nn\t3::File()->exists($src = NULL); 

Prüft, ob eine Datei existiert. Gibt absoluten Pfad zur Datei zurück.

\nn\t3::File()->exists('fileadmin/bild.jpg');
Copied!

Existiert auch als ViewHelper:

{nnt3:file.exists(file:'pfad/zum/bild.jpg')}
Copied!

| @return string|boolean

Source Code 

public function exists($src = null)
{
	if (file_exists($src)) return $src;
	$src = $this->absPath($src);
	if (file_exists($src)) return $src;
	return false;
}
Copied!

File::extractExifData() 

\nn\t3::File()->extractExifData($filename = ''); 

EXIF Daten für Datei in JSON speichern.

\nn\t3::File()->extractExifData( 'yellowstone.jpg' );
Copied!

| @return array

Source Code 

public function extractExifData($filename = '')
{
	$exif = $this->getData($filename);
	$pathParts = pathinfo($filename);
	$jsonFilename = $pathParts['dirname'] . '/' . $pathParts['filename'] . '.json';
	file_put_contents($jsonFilename, json_encode($exif));
	return $exif;
}
Copied!

File::getData() 

\nn\t3::File()->getData($file = ''); 

Imageinfo + EXIF Data für Datei holen. Sucht auch nach JSON-Datei, die evtl. nach processImage() generiert wurde

| @return array

Source Code 

public function getData($file = '')
{
	if (!is_string($file)) {
		$file = $this->getPath($file);
	}
	if (!file_exists($file)) $file = \nn\t3::Environment()->getPathSite() . $file;
	if (!file_exists($file)) return [];
	// Dateiname der JSON-Datei: Identisch mit Bildname, aber suffix .json
	$pathParts = pathinfo($file);
	$jsonFilename = $pathParts['dirname'] . '/' . $pathParts['filename'] . '.json';
	// Wurde kein JSON für Datei generiert? Dann über Library EXIF-Daten extrahieren
	if (!file_exists($jsonFilename)) {
		return $this->getExifData($file);
	}
	// JSON existiert. imageSize trotzdem aktualisieren, weil evtl. processImage() im Einsatz war
	if ($rawData = file_get_contents($jsonFilename)) {
		$jsonData = json_decode($rawData, true);
		return \nn\t3::Arrays($jsonData)->merge($this->getImageSize($file));
	}
	return [];
}
Copied!

File::getExifData() 

\nn\t3::File()->getExifData($filename = ''); 

ALLE EXIF Daten für Datei holen.

\nn\t3::File()->getExif( 'yellowstone.jpg' );
Copied!

| @return array

Source Code 

public function getExifData($filename = '')
{
	return array_merge(
		$this->getImageSize($filename),
		$this->getImageData($filename),
		$this->getLocationData($filename)
	);
}
Copied!

File::getFolder() 

\nn\t3::File()->getFolder($file); 

Gibt den Ordner zu einer Datei zurück

Beispiel:

\nn\t3::File()->getFolder('fileadmin/test/beispiel.txt');
// ==> gibt 'fileadmin/test/' zurück
Copied!

| @return string

Source Code 

public function getFolder($file)
{
	$pathSite = \nn\t3::Environment()->getPathSite();
	$file = str_replace($pathSite, '', $file);
	if (substr($file, -1) == '/') return $file;
	if (is_dir($pathSite . $file)) return $file;
	if (!pathinfo($file, PATHINFO_EXTENSION)) return $file . '/';
	return dirname($file) . '/';
}
Copied!

File::getImageData() 

\nn\t3::File()->getImageData($filename = ''); 

EXIF Bild-Daten für Datei holen.

\nn\t3::File()->getImageData( 'yellowstone.jpg' );
Copied!

| @return array

Source Code 

public function getImageData($filename = '')
{
	if (!function_exists('exif_read_data')) return [];
	$exif = @\exif_read_data($filename);
	if (!$exif) return [];
	$orientation = $exif['Orientation'];
	$imageProcessingMap = array(
		'r2' => '-flop',
		'r3' => '-flop -flip',
		'r4' => '-rotate 180 -flop',
		'r5' => '-flop -rotate 270',
		'r6' => '-rotate 90',
		'r7' => '-flop -rotate 90',
		'r8' => '-rotate 270',
	);
	return [
		'orient' => $orientation,
		'time' => $exif['FileDateTime'],
		'type' => $exif['FileType'],
		'im' => $imageProcessingMap['r' . $orientation] ?? false,
	];
}
Copied!

File::getImageSize() 

\nn\t3::File()->getImageSize($filename = ''); 

imagesize für Datei holen.

\nn\t3::File()->getImageSize( 'yellowstone.jpg' );
Copied!

| @return array

Source Code 

public function getImageSize($filename = '')
{
	if (!file_exists($filename)) return [];
	$imageinfo = getimagesize($filename);
	return [
		'width' => $imageinfo[0],
		'height' => $imageinfo[1],
		'mime' => $imageinfo['mime'],
	];
}
Copied!

File::getLocationData() 

\nn\t3::File()->getLocationData($filename = ''); 

EXIF GEO-Daten für Datei holen. Adressdaten werden automatisch ermittelt, falls möglich

\nn\t3::File()->getLocationData( 'yellowstone.jpg' );
Copied!

| @return array

Source Code 

public function getLocationData($filename = '')
{
	if (!function_exists('exif_read_data')) return [];
	$rawExif = @\exif_read_data($filename);
	$exif = [];
	if ($rawExif) {
		$exif['lat'] = \nn\t3::Geo()->toGps($rawExif['GPSLatitude'], $rawExif['GPSLatitudeRef']);
		$exif['lng'] = \nn\t3::Geo()->toGps($rawExif['GPSLongitude'], $rawExif['GPSLongitudeRef']);
		$exif = \nn\t3::Arrays($exif)->merge(\nn\t3::Geo()->getAddress($exif['lng'], $exif['lat']));
	}
	return $exif;
}
Copied!

File::getPath() 

\nn\t3::File()->getPath($file, $storage = NULL, $absolute = true); 

Gibt den Pfad einer Datei anhand eines Dateinamens und der Storage wieder. Beispiel:

\nn\t3::File()->getPath('media/bild.jpg', $storage);
// ==> gibt '/var/www/.../fileadmin/media/bild.jpg' zurück
\nn\t3::File()->getPath('fileadmin/media/bild.jpg');
// ==> gibt '/var/www/.../fileadmin/media/bild.jpg' zurück
Copied!

| @return string

Source Code 

public function getPath($file, $storage = null, $absolute = true)
{
	// ToDo: Prüfen, ob über ResourceFactory lösbar ResourceFactory::getInstance()->retrieveFileOrFolderObject($filenameOrSysFile->getOriginalResource()->getPublicUrl());
	if (is_string($file)) {
		$file = ltrim($file, '/');
		$storage = $storage ?: $this->getStorage($file);
		if (!$storage) return false;
		$storageConfiguration = $storage->getConfiguration();
		$storageFolder = $storageConfiguration['basePath'];
	} else {
		$file = $this->getPublicUrl($file);
		$storageFolder = '';
	}
	$relPath = $storageFolder . $file;
	$absPath = \nn\t3::Environment()->getPathSite() . $storageFolder . $file;
	if (file_exists($absPath)) return $absolute ? $absPath : $relPath;
	return false;
}
Copied!

File::getPublicUrl() 

\nn\t3::File()->getPublicUrl($obj = NULL, $absolute = false); 

Holt Pfad zur Datei, relativ zum Typo3-Installtionsverzeichnis (PATH_site). Kann mit allen Arten von Objekten umgehen.

\nn\t3::File()->getPublicUrl( $falFile );        // \TYPO3\CMS\Core\Resource\FileReference
\nn\t3::File()->getPublicUrl( $fileReference );  // \TYPO3\CMS\Extbase\Domain\Model\FileReference
\nn\t3::File()->getPublicUrl( $folder );         // \TYPO3\CMS\Core\Resource\Folder
\nn\t3::File()->getPublicUrl( $folder, true );   // https://.../fileadmin/bild.jpg
Copied!

| @return string

Source Code 

public function getPublicUrl($obj = null, $absolute = false)
{
	$url = false;
	if (is_string($obj)) {
		$url = $obj;
	} else if (\nn\t3::Obj()->isFalFile($obj) || \nn\t3::Obj()->isFile($obj)) {
		$url = $obj->getPublicUrl();
	} else if (\nn\t3::Obj()->isFileReference($obj)) {
		$url = $obj->getOriginalResource()->getPublicUrl();
	} else if (is_array($obj) && $url = ($obj['publicUrl'] ?? false)) {
		// $url kann genutzt werden!
	} else if (is_a($obj, \TYPO3\CMS\Core\Resource\Folder::class, true)) {
		$url = $obj->getPublicUrl();
	}
	$url = ltrim($url, '/');
	return !$absolute ? $url : $this->absUrl($url);
}
Copied!

File::getRelativePathInStorage() 

\nn\t3::File()->getRelativePathInStorage($file, $storage = NULL); 

Gibt den relativen Pfad einer Datei zur angegebenen Storage wieder.

Beispiel:

\nn\t3::File()->getRelativePathInStorage('fileadmin/media/bild.jpg', $storage);
// ==> gibt 'media/bild.jpg' zurück
Copied!

| @return string

Source Code 

public function getRelativePathInStorage($file, $storage = null)
{
	$file = $this->stripPathSite($file);
	$resource = GeneralUtility::makeInstance(ResourceFactory::class)->retrieveFileOrFolderObject($file);
	if (!$resource) return false;
	return ltrim($resource->getIdentifier(), '/');
	// ToDo: Prüfen, ob über ResourceFactory lösbar ResourceFactory::getInstance()->retrieveFileOrFolderObject($filenameOrSysFile->getOriginalResource()->getPublicUrl());
	$storage = $storage ?: $this->getStorage($file);
	if (!$storage) return false;
	$storageConfiguration = $storage->getConfiguration();
	$storageFolder = $storageConfiguration['basePath'];
	$basename = substr($file, strlen($storageFolder));
	if (!file_exists(\nn\t3::Environment()->getPathSite() . $storageFolder . $basename)) return false;
	return $basename;
}
Copied!

File::getStorage() 

\nn\t3::File()->getStorage($file, $createIfNotExists = false); 

Findet ein passendes sys_file_storage zu einem Datei- oder Ordnerpfad. Durchsucht dazu alle sys_file_storage-Einträge und vergleicht, ob der basePath des Storages zum Pfad der Datei passt.

\nn\t3::File()->getStorage('fileadmin/test/beispiel.txt');
\nn\t3::File()->getStorage( $falFile );
\nn\t3::File()->getStorage( $sysFileReference );
// gibt ResourceStorage mit basePath "fileadmin/" zurück
Copied!

| @return ResourceStorage

Source Code 

public function getStorage($file, $createIfNotExists = false)
{
	if (!is_string($file)) {
		if (\nn\t3::Obj()->isFalFile($file) || \nn\t3::Obj()->isFile($file)) {
			return $file->getStorage();
		} else if (\nn\t3::Obj()->isFileReference($file)) {
			return $file->getOriginalResource()->getStorage();
		}
		return false;
	}
	$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
	try {
		$resource = $resourceFactory->retrieveFileOrFolderObject($file);
		if ($resource && $resource->getStorage()?->getUid()) {
			return $resource->getStorage();
		}
	} catch (\Exception $e) {
		// File/folder not found in any storage
	}
	$allowCreateConf = \nn\t3::Settings()->getExtConf('nnhelpers')['autoCreateFilemounts'] ?? true;
	if (!($allowCreateConf && $createIfNotExists)) {
		\nn\t3::Exception("nnhelpers: Storage for file {$file} was not found and autocreate was disabled.");
	}
	$storageRepository = \nn\t3::Storage();
	$file = ltrim($file, '/');
	$dirname = $this->getFolder($file);
	$uid = $storageRepository->createLocalStorage($dirname . ' (nnhelpers)', $dirname, 'relative');
	$storageRepository->clearStorageRowCache();
	$storage = $storageRepository->findByUid($uid);
	if (!$storage) {
		\nn\t3::Exception("nnhelpers: Error autocreating storage for file {$file}.");
	}
	return $storage;
}
Copied!

File::isAllowed() 

\nn\t3::File()->isAllowed($filename = NULL); 

Gibt an, ob der Dateityp erlaubt ist

\nn\t3::File()->isForbidden('bild.jpg');   => gibt 'true' zurück
\nn\t3::File()->isForbidden('hack.php');   => gibt 'false' zurück
Copied!

| @return boolean

Source Code 

public function isAllowed($filename = null)
{
	return !$this->isForbidden($filename);
}
Copied!

File::isConvertableToImage() 

\nn\t3::File()->isConvertableToImage($filename = NULL); 

Gibt an, ob die Datei in ein Bild konvertiert werden kann

\nn\t3::File()->isConvertableToImage('bild.jpg');  => gibt true zurück
\nn\t3::File()->isConvertableToImage('text.ppt');  => gibt false zurück
Copied!

| @return boolean

Source Code 

public function isConvertableToImage($filename = null)
{
	if (!$filename) return false;
	$suffix = $this->suffix($filename);
	$arr = array_merge(self::$TYPES['image'], self::$TYPES['pdf']);
	return in_array($suffix, $arr);
}
Copied!

File::isExternalVideo() 

\nn\t3::File()->isExternalVideo($url = NULL); 

Gibt an, ob es ein Video auf YouTube / Vimeo ist. Falls ja, wird ein Array mit Angaben zum Einbetten zurückgegeben.

\nn\t3::File()->isExternalVideo('http://...');
Copied!

| @return array|boolean

Source Code 

public function isExternalVideo($url = null)
{
	return \nn\t3::Video()->getExternalType($url);
}
Copied!

File::isFolder() 

\nn\t3::File()->isFolder($file); 

Gibt zurück, ob angegebener Pfad ein Ordner ist

Beispiel:

\nn\t3::File()->isFolder('fileadmin'); // => gibt true zurück
Copied!

| @return boolean

Source Code 

public function isFolder($file)
{
	if (substr($file, -1) == '/') return true;
	return is_dir($this->absPath($file));
}
Copied!

File::isForbidden() 

\nn\t3::File()->isForbidden($filename = NULL, $allowed = []); 

Gibt an, ob der Dateityp verboten ist

\nn\t3::File()->isForbidden('bild.jpg');                   => gibt 'false' zurück
\nn\t3::File()->isForbidden('bild.xyz', ['xyz']);        => gibt 'false' zurück
\nn\t3::File()->isForbidden('hack.php');                   => gibt 'true' zurück
\nn\t3::File()->isForbidden('.htaccess');              => gibt 'true' zurück
Copied!
@param string $filename
@param array $allowed
@return boolean

Source Code 

public function isForbidden($filename = null, $allowed = [])
{
	if (!$filename) return false;
	if (substr($filename, 0, 1) == '.') return true;
	if (!$allowed) {
		$types = array_values(self::$TYPES);
		$allowed = array_merge(...$types);
	}
	$suffix = $this->suffix($filename);
	return !in_array($suffix, $allowed);
}
Copied!

File::isImage() 

\nn\t3::File()->isImage($filename = NULL); 

Gibt an, ob die Datei in ein Bild ist

\nn\t3::File()->isImage('bild.jpg');   => gibt true zurück
\nn\t3::File()->isImage('text.ppt');   => gibt false zurück
Copied!

| @return boolean

Source Code 

public function isImage($filename = null)
{
	if (!$filename) return false;
	$suffix = $this->suffix($filename);
	$arr = array_merge(self::$TYPES['image']);
	return in_array($suffix, $arr);
}
Copied!

File::isVideo() 

\nn\t3::File()->isVideo($filename = NULL); 

Gibt an, ob die Datei ein Video ist

\nn\t3::File()->isVideo('pfad/zum/video.mp4');     => gibt true zurück
Copied!

| @return boolean

Source Code 

public function isVideo($filename = null)
{
	return $this->type($filename) == 'video';
}
Copied!

File::mkdir() 

\nn\t3::File()->mkdir($path = ''); 

Einen Ordner anlegen

\nn\t3::File()->mkdir( 'fileadmin/mein/ordner/' );
\nn\t3::File()->mkdir( '1:/mein/ordner/' );
Copied!

| @return boolean

Source Code 

public function mkdir($path = '')
{
	if (\nn\t3::File()->exists($path)) return true;
	$path = \nn\t3::File()->absPath(rtrim($path, '/') . '/');
	\TYPO3\CMS\Core\Utility\GeneralUtility::mkdir_deep($path);
	return \nn\t3::File()->exists($path);
}
Copied!

File::move() 

\nn\t3::File()->move($src = NULL, $dest = NULL); 

Verschiebt eine Datei

\nn\t3::File()->move('fileadmin/bild.jpg', 'fileadmin/bild-kopie.jpg');
Copied!

| @return boolean

Source Code 

public function move($src = null, $dest = null)
{
	if (!file_exists($src)) return false;
	if (file_exists($dest)) return false;
	rename($src, $dest);
	return file_exists($dest);
}
Copied!

File::moveUploadedFile() 

\nn\t3::File()->moveUploadedFile($src = NULL, $dest = NULL); 

Eine Upload-Datei ins Zielverzeichnis verschieben.

Kann absoluter Pfad zur tmp-Datei des Uploads sein – oder ein TYPO3\CMS\Core\Http\UploadedFile, das sich im Controller über $this->request->getUploadedFiles() holen lässt.

\nn\t3::File()->moveUploadedFile('/tmp/xjauGSaudsha', 'fileadmin/bild-kopie.jpg');
\nn\t3::File()->moveUploadedFile( $fileObj, 'fileadmin/bild-kopie.jpg');
Copied!

| @return string

Source Code 

public function moveUploadedFile($src = null, $dest = null)
{
	$dest = $this->uniqueFilename($this->absPath($dest));
	if (!$this->isAllowed($dest)) {
		\nn\t3::Exception('\nn\t3::File()->moveUploadedFile() :: Filetype not allowed.');
		return false;
	}
	if (!is_string($src) && is_a($src, \TYPO3\CMS\Core\Http\UploadedFile::class)) {
		if ($stream = $src->getStream()) {
			$handle = fopen($dest, 'wb+');
			if ($handle === false) return false;
			$stream->rewind();
			while (!$stream->eof()) {
				$bytes = $stream->read(4096);
				fwrite($handle, $bytes);
			}
			fclose($handle);
		}
	} else {
		$src = $this->absPath($src);
		move_uploaded_file($src, $dest);
	}
	if (file_exists($dest)) {
		return $dest;
	}
	return false;
}
Copied!

File::normalizePath() 

\nn\t3::File()->normalizePath($path); 

Löst ../../-Angaben in Pfad auf. Funktioniert sowohl mit existierenden Pfaden (per realpath) als auch nicht-existierenden Pfaden.

\nn\t3::File()->normalizePath( 'fileadmin/test/../bild.jpg' );     =>   fileadmin/bild.jpg
Copied!

| @return string

Source Code 

public function normalizePath($path)
{
	$hasTrailingSlash = substr($path, -1) == '/';
	$hasStartingSlash = substr($path, 0, 1) == '/';
	$path = array_reduce(explode('/', $path), function ($a, $b) {
		if ($a === 0 || $a === null) $a = '/';
		if ($b === '' || $b === '.') return $a;
		if ($b === '..') return dirname($a);
		return preg_replace('/\/+/', '/', "{$a}/{$b}");
	}, 0);
	if (!$hasStartingSlash) $path = ltrim($path, '/');
	$isFolder = is_dir($path) || $hasTrailingSlash;
	$path = rtrim($path, '/');
	if ($isFolder) $path .= '/';
	return $path;
}
Copied!

File::process() 

\nn\t3::File()->process($fileObj = '', $processing = [], $returnProcessedImage = false); 

Berechnet ein Bild über maxWidth, maxHeight etc. Einfache Version von \nn\t3::File()->processImage() Kann verwendet werden, wenn es nur um das Generieren von verkleinerten Bilder geht ohne Berücksichtigung von Korrekturen der Kamera-Ausrichtung etc.

Da die Crop-Einstellungen in FileReference und nicht File gespeichert sind, funktioniert cropVariant nur bei Übergabe einer FileReference.

\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/bilder/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200] );
\nn\t3::File()->process( $sysFile, ['maxWidth'=>200, 'absolute'=>true] );
\nn\t3::File()->process( $sysFileReference, ['maxWidth'=>200, 'cropVariant'=>'square'] );
Copied!

Mit dem Parameter $returnProcessedImage = true wird nicht der Dateipfad zum neuen Bild sondern das processedImage-Object zurückgegeben.

\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200], true );
Copied!

| @return string

Source Code 

public function process($fileObj = '', $processing = [], $returnProcessedImage = false)
{
	$filename = '';
	$cropString = '';
	$imageService = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Service\ImageService::class);
	if ($fileObj instanceof \TYPO3\CMS\Core\Resource\FileReference) {
		$fileObj = \nn\t3::Convert($fileObj)->toFileReference();
	}
	if ($fileObj instanceof \TYPO3\CMS\Core\Resource\File) {
		// sys_file-Object
		$filename = $fileObj->getPublicUrl();
	} else if (is_a($fileObj, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class)) {
		// sys_file_reference-Object
		if (method_exists($fileObj, 'getProperty')) {
			$cropString = $fileObj->getProperty('crop');
		} else if ($originalResource = $fileObj->getOriginalResource()) {
			$cropString = $originalResource->getProperty('crop');
		}
		$image = $fileObj->getOriginalResource();
	} else if (is_string($fileObj) && strpos($fileObj, ':/') !== false) {
		// String mit file_storage-Angabe (1:/uploads/test.jpg)
		$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
		$file = $resourceFactory->getFileObjectFromCombinedIdentifier($fileObj);
		$filename = $file->getPublicUrl();
	} else if (is_string($fileObj)) {
		// String (fileadmin/uploads/test.jpg)
		$filename = $fileObj;
	}
	if ($filename) {
		$image = $imageService->getImage($filename, null, false);
	}
	if ($image) {
		$cropVariantCollection = CropVariantCollection::create((string)$cropString);
		$cropVariant = $processing['cropVariant'] ?? 'default';
		$cropArea = $cropVariantCollection->getCropArea($cropVariant);
		$processing['crop'] = $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image);
		$processedImage = $imageService->applyProcessingInstructions($image, $processing);
		if ($returnProcessedImage) return $processedImage;
		return $imageService->getImageUri($processedImage, $processing['absolute'] ?? false);
	}
	return false;
}
Copied!

File::processImage() 

\nn\t3::File()->processImage($filenameOrSysFile = '', $processing = []); 

Kann direkt nach dem upload_copy_move() aufgerufen werden. Korrigiert die Ausrichtung des Bildes, die evtl. in EXIF-Daten gespeichert wurde. Für einfach maxWidth-Anweis ungen die Methode \nn\t3::File()->process() verwenden.

Anweisungen für $processing:

| correctOrientation => Drehung korrigieren (z.B. weil Foto vom Smartphone hochgeladen wurde)

| @return string

Source Code 

public function processImage($filenameOrSysFile = '', $processing = [])
{
	if (is_string($filenameOrSysFile)) {
		if ($falFile = \nn\t3::Fal()->getFalFile($filenameOrSysFile)) {
			$filenameOrSysFile = $falFile;
		}
	}
	// Bereits berechnete Bildgrößen löschen
	\nn\t3::Fal()->clearCache($filenameOrSysFile);
	if (is_string($filenameOrSysFile)) {
		$filename = $filenameOrSysFile;
	} else if (is_a($filenameOrSysFile, \TYPO3\CMS\Core\Resource\File::class)) {
		$filename = $filenameOrSysFile->getPublicUrl();
	}
	if (!trim($filename)) return;
	$pathSite = \nn\t3::Environment()->getPathSite();
	$processing = \nn\t3::Arrays([
		'correctOrientation' => true,
		'maxWidth' => 6000,
		'maxHeight' => 6000,
	])->merge($processing);
	$processingInstructions = [
		'file' => $filename,
		'file.' => [],
	];
	if ($maxWidth = $processing['maxWidth']) {
		$processingInstructions['file.']['maxW'] = $maxWidth;
	}
	if ($maxHeight = $processing['maxHeight']) {
		$processingInstructions['file.']['maxH'] = $maxHeight;
	}
	// EXIF-Daten vorhanden? Dann als JSON speichern, weil sie nach dem Processing verloren gehen würden.
	if (is_object($filenameOrSysFile)) {
		$uid = $filenameOrSysFile->getUid();
		$exif = \nn\t3::Db()->findByUid('sys_file', $uid)['exif'] ?? [];
	} else if ($exif = $this->getImageData($filename)) {
		$exif = $this->extractExifData($filename);
	}
	// $exif['im'] enthält z.B. "-rotate 90" als ImageMagick Anweisung
	if ($exif['im'] && $processing['correctOrientation']) {
		$processingInstructions['file.']['params'] = $exif['im'];
	}
	$processedImageFilename = \nn\t3::Tsfe()->cObjGetSingle('IMG_RESOURCE', $processingInstructions);
	if ($processedImageFilename) {
		\TYPO3\CMS\Core\Utility\GeneralUtility::upload_copy_move($pathSite . $processedImageFilename, $pathSite . $filename);
	}
	$exif = array_merge($this->getData($filename), ['file' => $filename]);
	// Update der Meta-Daten für das Bild
	if (is_object($filenameOrSysFile)) {
		\nn\t3::Fal()->updateMetaData($filenameOrSysFile);
	}
	return $exif;
}
Copied!

File::read() 

\nn\t3::File()->read($src = NULL); 

Holt den Inhalt einer Datei

\nn\t3::File()->read('fileadmin/text.txt');
Copied!

| @return string|boolean

Source Code 

public function read($src = null)
{
	if (!$src || !$this->exists($src)) return '';
	$absPath = $this->absPath($src);
	if (!$absPath) return '';
	return file_get_contents($absPath);
}
Copied!

File::relPath() 

\nn\t3::File()->relPath($path = ''); 

relativen Pfad (vom aktuellen Script aus) zum einer Datei / Verzeichnis zurück. Wird kein Pfad angegeben, wird das Typo3-Root-Verzeichnis zurückgegeben.

\nn\t3::File()->relPath( $file );        => ../fileadmin/bild.jpg
\nn\t3::File()->relPath();               => ../
Copied!

| @return string

Source Code 

public function relPath($path = '')
{
	if (!$path) $path = \nn\t3::Environment()->getPathSite();
	$isFolder = $this->isFolder($path);
	$path = $this->absPath($path);
	$name = rtrim(PathUtility::getRelativePathTo($path), '/');
	if ($isFolder) $name .= '/';
	return $name;
}
Copied!

File::resolvePathPrefixes() 

\nn\t3::File()->resolvePathPrefixes($file = NULL, $absolute = false); 

EXT: Prefix auflösen zu relativer Pfadangabe

\nn\t3::File()->resolvePathPrefixes('EXT:extname');                    => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/');               => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/bild.jpg');       => /typo3conf/ext/extname/bild.jpg
\nn\t3::File()->resolvePathPrefixes('1:/uploads/bild.jpg', true);  => /var/www/website/fileadmin/uploads/bild.jpg
Copied!

| @return string

Source Code 

public function resolvePathPrefixes($file = null, $absolute = false)
{
	// `1:/uploads`
	if (preg_match('/^([0-9]*)(:\/)(.*)/i', $file, $matches)) {
		$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
		$storage = $resourceFactory->getStorageObject($matches[1]);
		if (!$storage) return $file;
		$basePath = $storage->getConfiguration()['basePath'];
		$file = $basePath . $matches[3];
	}
	// `EXT:extname` => `EXT:extname/`
	if (strpos($file, 'EXT:') == 0 && !pathinfo($file, PATHINFO_EXTENSION)) {
		$file = rtrim($file, '/') . '/';
	}
	// `EXT:extname/` => `typo3conf/ext/extname/`
	$absPathName = GeneralUtility::getFileAbsFileName($file);
	if (!$absPathName) return $file;
	if ($absolute) return $this->absPath($absPathName);
	$pathSite = \nn\t3::Environment()->getPathSite();
	return str_replace($pathSite, '', $absPathName);
}
Copied!

File::sendDownloadHeader() 

\nn\t3::File()->sendDownloadHeader($filename = '', $filesize = NULL); 

PHP Header für Download senden. Wenn die Datei physisch existiert, wird die filesize automatisch ermittelt.

\nn\t3::File()->sendDownloadHeader( 'download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'pfad/zur/datei/download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'fakedatei.jpg', 1200 );
Copied!

| @return void

Source Code 

public function sendDownloadHeader($filename = '', $filesize = null)
{
	ob_end_clean();
	if (!$filesize && $size = \nn\t3::File()->size($filename)) {
		$filesize = $size;
	}
	$filename = pathinfo($filename, PATHINFO_BASENAME);
	$type = pathinfo($filename, PATHINFO_EXTENSION);
	header("Content-Transfer-Encoding: Binary");
	header("Content-Type: application/{$type}");
	//header('Content-Type: application/octet-stream');
	header('Content-Disposition: attachment; filename="' . $filename . '"');
	if ($filesize) header("Content-Length: " . $filesize);
}
Copied!

File::size() 

\nn\t3::File()->size($src = NULL); 

Gibt Dateigröße zu einer Datei in Bytes zurück Falls Datei nicht exisitert, wird 0 zurückgegeben.

\nn\t3::File()->size('fileadmin/bild.jpg');
Copied!

| @return integer

Source Code 

public function size($src = null)
{
	$src = $this->exists($src);
	if (!$src) return 0;
	return filesize($src);
}
Copied!

File::stripBaseUrl() 

\nn\t3::File()->stripBaseUrl($file); 

Entfernt die URL, falls sie der aktuellen Domain entspricht

Beispiel:

\nn\t3::File()->stripBaseUrl('https://www.my-web.de/fileadmin/test.jpg');  ==> fileadmin/test.jpg
\nn\t3::File()->stripBaseUrl('https://www.other-web.de/example.jpg');      ==> https://www.other-web.de/example.jpg
Copied!

| @return string

Source Code 

public function stripBaseUrl($file)
{
	$baseUrl = \nn\t3::Environment()->getBaseURL();
	$file = str_replace($baseUrl, '', $file);
	return $file;
}
Copied!

File::stripPathSite() 

\nn\t3::File()->stripPathSite($file, $prefix = false); 

Gibt Pfad zu Datei / Ordner OHNE absoluten Pfad. Optional kann ein Prefix angegeben werden.

Beispiel:

\nn\t3::File()->stripPathSite('var/www/website/fileadmin/test.jpg');       ==>  fileadmin/test.jpg
\nn\t3::File()->stripPathSite('var/www/website/fileadmin/test.jpg', true); ==>  var/www/website/fileadmin/test.jpg
\nn\t3::File()->stripPathSite('fileadmin/test.jpg', true);                 ==>  var/www/website/fileadmin/test.jpg
\nn\t3::File()->stripPathSite('fileadmin/test.jpg', '../../');               ==>  ../../fileadmin/test.jpg
Copied!

| @return string

Source Code 

public function stripPathSite($file, $prefix = false)
{
	$pathSite = \nn\t3::Environment()->getPathSite();
	$file = str_replace($pathSite, '', $file);
	if ($prefix === true) {
		$file = $pathSite . $file;
	} else if ($prefix !== false) {
		$file = $prefix . $file;
	}
	return $file;
}
Copied!

File::suffix() 

\nn\t3::File()->suffix($filename = NULL); 

Gibt den Suffix der Datei zurück

\nn\t3::File()->suffix('bild.jpg');    => gibt 'jpg' zurück
Copied!

| @return string

Source Code 

public function suffix($filename = null)
{
	if (!$filename) return false;
	$suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
	$suffix = preg_replace('/\?.*/', '', $suffix);
	if ($suffix == 'jpeg') $suffix = 'jpg';
	return $suffix;
}
Copied!

File::suffixForMimeType() 

\nn\t3::File()->suffixForMimeType($mime = ''); 

Gibt den Suffix für einen bestimmten Mime-Type / Content-Type zurück. Sehr reduzierte Variante – nur wenige Typen abgedeckt. Umfangreiche Version: https://bit.ly/3B9KrNA

\nn\t3::File()->suffixForMimeType('image/jpeg');   => gibt 'jpg' zurück
Copied!

| @return string

Source Code 

public function suffixForMimeType($mime = '')
{
	$mime = array_pop(explode('/', strtolower($mime)));
	$map = [
		'jpeg' => 'jpg',
		'jpg' => 'jpg',
		'gif' => 'gif',
		'png' => 'png',
		'pdf' => 'pdf',
		'tiff' => 'tif',
	];
	foreach ($map as $sword => $suffix) {
		if (strpos($mime, $sword) !== false) {
			return $suffix;
		}
	}
	return $mime;
}
Copied!

File::type() 

\nn\t3::File()->type($filename = NULL); 

Gibt die Art der Datei anhand des Datei-Suffixes zurück

\nn\t3::File()->type('bild.jpg');  => gibt 'image' zurück
\nn\t3::File()->type('text.doc');  => gibt 'document' zurück
Copied!

| @return string

Source Code 

public function type($filename = null)
{
	if (!$filename) return false;
	$suffix = $this->suffix($filename);
	foreach (self::$TYPES as $k => $arr) {
		if (in_array($suffix, $arr)) return $k;
	}
	return 'other';
}
Copied!

File::uniqueFilename() 

\nn\t3::File()->uniqueFilename($filename = ''); 

Erzeugt einen eindeutigen Dateinamen für die Datei, falls im Zielverzeichnis bereits eine Datei mit identischem Namen existiert.

$name = \nn\t3::File()->uniqueFilename('fileadmin/01.jpg');    // 'fileadmin/01-1.jpg'
Copied!

| @return string

Source Code 

public function uniqueFilename($filename = '')
{
	$filename = $this->cleanFilename($filename);
	if (!$this->exists($filename)) return $filename;
	$path = pathinfo($filename, PATHINFO_DIRNAME) . '/';
	$suffix = pathinfo($filename, PATHINFO_EXTENSION);
	$filename = preg_replace('/-[0-9][0-9]$/', '', pathinfo($filename, PATHINFO_FILENAME));
	$i = 0;
	while ($i < 99) {
		$i++;
		$newName = $path . $filename . '-' . sprintf('%02d', $i) . '.' . $suffix;
		if (!$this->exists($newName)) return $newName;
	}
	return $path . $filename . '-' . uniqid() . '.' . $suffix;
}
Copied!

File::write() 

\nn\t3::File()->write($path = NULL, $content = NULL); 

Einen Ordner und/oder Datei erzeugen. Legt auch die Ordner an, falls sie nicht existieren.

\nn\t3::File()->write('fileadmin/some/deep/folder/');
\nn\t3::File()->write('1:/some/deep/folder/');
\nn\t3::File()->write('fileadmin/some/deep/folder/file.json', 'TEXT');
Copied!

| @return boolean

Source Code 

public function write($path = null, $content = null)
{
	$path = \nn\t3::File()->absPath($path);
	$folder = pathinfo($path, PATHINFO_DIRNAME);
	$exists = \nn\t3::File()->mkdir($folder);
	if ($exists && $content !== null) {
		return file_put_contents($path, $content) !== false;
	}
	return $exists;
}
Copied!

Flexform 

\nn\t3::Flexform() 

FlexForms laden und parsen

Overview of Methods 

\nn\t3::Flexform()->getFalMedia($ttContentUid = NULL, $field = ''); 

Lädt FAL-Media, die in direkt im FlexForm angegeben wurden

\nn\t3::Flexform()->getFalMedia( 'falmedia' );
\nn\t3::Flexform()->getFalMedia( 'settings.falmedia' );
\nn\t3::Flexform()->getFalMedia( 1201, 'falmedia' );
Copied!
$cObjData = \nn\t3::Tsfe()->cObjData();
$falMedia = \nn\t3::Flexform()->getFalMedia( $cObjData['uid'], 'falmedia' );
Copied!

| @return array

| ➜ Go to source code of Flexform::getFalMedia()

\nn\t3::Flexform()->getFlexform($ttContentUid = NULL); 

Holt das Flexform eines bestimmten Inhaltselementes als Array

\nn\t3::Flexform()->getFlexform( 1201 );
Copied!

| @return array

| ➜ Go to source code of Flexform::getFlexform()

\nn\t3::Flexform()->insertCountries($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein FlexForm oder TCA ein.

<config>
    <type>select</type>
    <items type="array"></items>
    <itemsProcFunc>nn\t3\Flexform->insertCountries</itemsProcFunc>
    <insertEmpty>1</insertEmpty>
</config>
Copied!

| @return array

| ➜ Go to source code of Flexform::insertCountries()

\nn\t3::Flexform()->insertOptions($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein FlexForm oder TCA ein.

<config>
    <type>select</type>
    <items type="array"></items>
    <itemsProcFunc>nn\t3\Flexform->insertOptions</itemsProcFunc>
    <typoscriptPath>plugin.tx_extname.settings.templates</typoscriptPath>
    <!-- Alternativ: Settings aus PageTSConfig laden: -->
    <pageconfigPath>tx_extname.colors</pageconfigPath>
    <!-- Optional: Eigenen Key aus TypoScript verwenden -->
    <customKey>value</customKey>
    <insertEmpty>1</insertEmpty>
    <insertEmptyLabel>Nichts</insertEmptyLabel>
    <insertEmptyValue></insertEmptyValue>
    <hideKey>1</hideKey>
</config>
Copied!

Beim Typoscript sind verschiedene Arten des Aufbaus erlaubt:

plugin.tx_extname.settings.templates {
    # Direkte key => label Paare
    small = Small Design
    # ... oder: Label im Subarray gesetzt
    mid {
        label = Mid Design
    }
    # ... oder: Key im Subarray gesetzt, praktisch z.B. für CSS-Klassen
    10 {
        label = Big Design
        classes = big big-thing
    }
    # ... oder eine userFunc. Gibt eine der Varianten oben als Array zurück
    30 {
        userFunc = nn\t3\Flexform->getOptions
    }
}
Copied!

Die Auswahl kann im TypoScript auf bestimmte Controller-Actions beschränkt werden. In diesem Beispiel wird die Option "Gelb" nur angezeigt, wenn in der switchableControllerAction | Category->list gewählt wurde.

plugin.tx_extname.settings.templates {
    yellow {
        label = Gelb
        controllerAction = Category->list,...
    }
}
Copied!

| @return array

| ➜ Go to source code of Flexform::insertOptions()

\nn\t3::Flexform()->parse($xml = ''); 

Wandelt ein Flexform-XML in ein Array um

\nn\t3::Flexform()->parse('<?xml...>');
Copied!

Existiert auch als ViewHelper:

{rawXmlString->nnt3:parse.flexForm()->f:debug()}
Copied!

| @return array

| ➜ Go to source code of Flexform::parse()

Methods 

Flexform::getFalMedia() 

\nn\t3::Flexform()->getFalMedia($ttContentUid = NULL, $field = ''); 

Lädt FAL-Media, die in direkt im FlexForm angegeben wurden

\nn\t3::Flexform()->getFalMedia( 'falmedia' );
\nn\t3::Flexform()->getFalMedia( 'settings.falmedia' );
\nn\t3::Flexform()->getFalMedia( 1201, 'falmedia' );
Copied!
$cObjData = \nn\t3::Tsfe()->cObjData();
$falMedia = \nn\t3::Flexform()->getFalMedia( $cObjData['uid'], 'falmedia' );
Copied!

| @return array

Source Code 

public function getFalMedia( $ttContentUid = null, $field = '' )
{
	if (!$field && $ttContentUid) {
		$field = $ttContentUid;
		$ttContentUid = \nn\t3::Tsfe()->cObjData()['uid'];
	}
	$fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class);
	$fileObjects = $fileRepository->findByRelation('tt_content', $field, $ttContentUid);
	foreach ($fileObjects as $n=>$fal) {
		$fileObjects[$n] = \nn\t3::Convert( $fal )->toFileReference();
	}
	return $fileObjects;
}
Copied!

Flexform::getFlexform() 

\nn\t3::Flexform()->getFlexform($ttContentUid = NULL); 

Holt das Flexform eines bestimmten Inhaltselementes als Array

\nn\t3::Flexform()->getFlexform( 1201 );
Copied!

| @return array

Source Code 

public function getFlexform( $ttContentUid = null ) {
	$data = \nn\t3::Content()->get( $ttContentUid );
	if (!$data) return [];
	$flexformData = $this->parse($data['pi_flexform']);
	return $flexformData;
}
Copied!

Flexform::insertCountries() 

\nn\t3::Flexform()->insertCountries($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein FlexForm oder TCA ein.

<config>
    <type>select</type>
    <items type="array"></items>
    <itemsProcFunc>nn\t3\Flexform->insertCountries</itemsProcFunc>
    <insertEmpty>1</insertEmpty>
</config>
Copied!

| @return array

Source Code 

public function insertCountries ( $config, $a = null )
{
	if ($config['config']['insertEmpty'] ?? false) {
		$config['items'] = array_merge( $config['items'], [['', '0', '']] );
	}
	$countriesByShortCode = \nn\t3::Environment()->getCountries() ?: [];
	if (!$countriesByShortCode) {
		$countriesByShortCode['DE'] = 'static_info_tables installieren!';
	}
	foreach ($countriesByShortCode as $cn => $title) {
		$config['items'][] = [$title, $cn];
	}
	return $config;
}
Copied!

Flexform::insertOptions() 

\nn\t3::Flexform()->insertOptions($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein FlexForm oder TCA ein.

<config>
    <type>select</type>
    <items type="array"></items>
    <itemsProcFunc>nn\t3\Flexform->insertOptions</itemsProcFunc>
    <typoscriptPath>plugin.tx_extname.settings.templates</typoscriptPath>
    <!-- Alternativ: Settings aus PageTSConfig laden: -->
    <pageconfigPath>tx_extname.colors</pageconfigPath>
    <!-- Optional: Eigenen Key aus TypoScript verwenden -->
    <customKey>value</customKey>
    <insertEmpty>1</insertEmpty>
    <insertEmptyLabel>Nichts</insertEmptyLabel>
    <insertEmptyValue></insertEmptyValue>
    <hideKey>1</hideKey>
</config>
Copied!

Beim Typoscript sind verschiedene Arten des Aufbaus erlaubt:

plugin.tx_extname.settings.templates {
    # Direkte key => label Paare
    small = Small Design
    # ... oder: Label im Subarray gesetzt
    mid {
        label = Mid Design
    }
    # ... oder: Key im Subarray gesetzt, praktisch z.B. für CSS-Klassen
    10 {
        label = Big Design
        classes = big big-thing
    }
    # ... oder eine userFunc. Gibt eine der Varianten oben als Array zurück
    30 {
        userFunc = nn\t3\Flexform->getOptions
    }
}
Copied!

Die Auswahl kann im TypoScript auf bestimmte Controller-Actions beschränkt werden. In diesem Beispiel wird die Option "Gelb" nur angezeigt, wenn in der switchableControllerAction | Category->list gewählt wurde.

plugin.tx_extname.settings.templates {
    yellow {
        label = Gelb
        controllerAction = Category->list,...
    }
}
Copied!

| @return array

Source Code 

public function insertOptions( $config, $a = null )
{
	if ($path = $config['config']['typoscriptPath'] ?? false) {
		// 'typoscriptPath' angegeben: Standard TypoScript-Setup verwenden
		$setup = \nn\t3::Settings()->getFromPath( $path );
	} elseif ( $path = $config['config']['pageconfigPath'] ?? false) {
		// 'pageconfigPath' angegeben: PageTSConfig verwenden
		$setup = \nn\t3::Settings()->getPageConfig( $path );
	}
	if (!$setup) {
		if ($config['items'] ?? false) return $config;
		$config['items'] = [
			['label' => 'Keine Konfiguration gefunden - Auswahl kann in '.$path.' definiert werden', 'value'=>'']
		];
		return $config;
	}
	$respectControllerAction = false;
	// TypoScript setup vorbereiten
	foreach ($setup as $k=>$v) {
		// controllerAction in Typoscript gesetzt?
		if (is_array($v) && ($v['controllerAction'] ?? false)) {
			$respectControllerAction = true;
		}
		// userFunc vorhanden? Dann auflösen...
		if (is_array($v) && ($v['userFunc'] ?? false)) {
			$result = \nn\t3::call( $v['userFunc'], $v );
			unset($setup[$k]);
			$setup = \nn\t3::Arrays($result)->merge($setup);
		}
	}
	// eigenen Key verwenden?
	$customKey = $config['config']['customKey'] ?? '';
	// Ausgewählte Action aus FlexForm 'switchableControllerActions' holen
	$selectedAction = $config['row']['switchableControllerActions'] ?? false;
	// Leeren Wert einfügen?
	if ($config['config']['insertEmpty'] ?? false) {
		$label = $config['config']['insertEmptyLabel'] ?? '';
		$value = $config['config']['insertEmptyValue'] ?? 0;
		$config['items'] = array_merge( $config['items'], [[$label, $value, '']] );
	}
	// Key in Klammern zeigen?
	$hideKey = ($config['config']['hideKey'] ?? 0) == 1;
	foreach ($setup as $k=>$v) {
		if (is_array($v)) {
			$label = $v['_typoScriptNodeValue'] ?? $v['label'] ?? $v['title'] ?? $v;
			$key = $v[$customKey] ?? $v['classes'] ?? $k;
			$keyStr = $hideKey ? '' : " ({$key})";
			$limitToAction = \nn\t3::Arrays($v['controllerAction'] ?? '')->trimExplode();
			if ($limitToAction && $selectedAction) {
				if (array_intersect($limitToAction, $selectedAction)) {
					$config['items'] = array_merge( $config['items'], [['label'=>$label.$keyStr, 'value'=>$key]] );
				}
			} else {
				$config['items'] = array_merge( $config['items'], [['label'=>$label.$keyStr, 'value'=>$key]] );
			}
		} else {
			$key = $v[$customKey] ?? $v['classes'] ?? $k;
			$keyStr = $hideKey ? '' : " ({$key})";
			$config['items'] = array_merge( $config['items'], [['label'=>$v.$keyStr, 'value'=>$key]] );
		}
	}
	return $config;
}
Copied!

Flexform::parse() 

\nn\t3::Flexform()->parse($xml = ''); 

Wandelt ein Flexform-XML in ein Array um

\nn\t3::Flexform()->parse('<?xml...>');
Copied!

Existiert auch als ViewHelper:

{rawXmlString->nnt3:parse.flexForm()->f:debug()}
Copied!

| @return array

Source Code 

public function parse( $xml = '' )
{
	$flexFormService = \nn\t3::injectClass( \TYPO3\CMS\Core\Service\FlexFormService::class );
	if (!$xml) return [];
	if (is_array($xml)) {
		$data = [];
		foreach (($xml['data']['sDEF']['lDEF'] ?? []) as $k=>$node) {
			$data[$k] = $node['vDEF'];
		}
		return $data;
	}
	return $flexFormService->convertFlexFormContentToArray( $xml ) ?: [];
}
Copied!

FrontendUser 

\nn\t3::FrontendUser() 

Overview of Methods 

\nn\t3::FrontendUser()->get(); 

Den aktuellen FE-User holen. Alias zu \nn\t3::FrontendUser()->getCurrentUser();

\nn\t3::FrontendUser()->get();
Copied!

Existiert auch als ViewHelper:

{nnt3:frontendUser.get(key:'first_name')}
{nnt3:frontendUser.get()->f:variable.set(name:'feUser')}
Copied!

| @return array

| ➜ Go to source code of FrontendUser::get()

\nn\t3::FrontendUser()->getAvailableUserGroups($returnRowData = false); 

Alle existierende User-Gruppen zurückgeben. Gibt ein assoziatives Array zurück, key ist die uid, value der title.

\nn\t3::FrontendUser()->getAvailableUserGroups();
Copied!

Alternativ kann mit true der komplette Datensatz für die Benutzergruppen zurückgegeben werden:

\nn\t3::FrontendUser()->getAvailableUserGroups( true );
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getAvailableUserGroups()

\nn\t3::FrontendUser()->getCookie(); 

Holt den aktuellen fe_typo_user Cookie.

$cookie = \nn\t3::FrontendUser()->getCookie();
Copied!

| @return string

| ➜ Go to source code of FrontendUser::getCookie()

\nn\t3::FrontendUser()->getCookieName(); 

Cookie-Name des Frontend-User-Cookies holen. Üblicherweise fe_typo_user, außer es wurde in der LocalConfiguration geändert.

\nn\t3::FrontendUser()->getCookieName();
Copied!

return string

| ➜ Go to source code of FrontendUser::getCookieName()

\nn\t3::FrontendUser()->getCurrentUser(); 

Array mit den Daten des aktuellen FE-Users holen.

\nn\t3::FrontendUser()->getCurrentUser();
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getCurrentUser()

\nn\t3::FrontendUser()->getCurrentUserGroups($returnRowData = false); 

Benutzergruppen des aktuellen FE-Users als Array holen. Die uids der Benutzergruppen werden im zurückgegebenen Array als Key verwendet.

// Minimalversion: Per default gibt Typo3 nur title, uid und pid zurück
\nn\t3::FrontendUser()->getCurrentUserGroups();          // [1 => ['title'=>'Gruppe A', 'uid' => 1, 'pid'=>5]]

// Mit true kann der komplette Datensatz für die fe_user_group aus der DB gelesen werden
\nn\t3::FrontendUser()->getCurrentUserGroups( true );    // [1 => [... alle Felder der DB] ]
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getCurrentUserGroups()

\nn\t3::FrontendUser()->getCurrentUserUid(); 

UID des aktuellen Frontend-Users holen

$uid = \nn\t3::FrontendUser()->getCurrentUserUid();
Copied!

| @return int

| ➜ Go to source code of FrontendUser::getCurrentUserUid()

\nn\t3::FrontendUser()->getGroups($returnRowData = false); 

Benutzergruppen des aktuellen FE-User holen. Alias zu \nn\t3::FrontendUser()->getCurrentUserGroups();

// nur title, uid und pid der Gruppen laden
\nn\t3::FrontendUser()->getGroups();
// kompletten Datensatz der Gruppen laden
\nn\t3::FrontendUser()->getGroups( true );
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getGroups()

\nn\t3::FrontendUser()->getLanguage(); 

Sprach-UID des aktuellen Users holen

$languageUid = \nn\t3::FrontendUser()->getLanguage();
Copied!

| @return int

| ➜ Go to source code of FrontendUser::getLanguage()

\nn\t3::FrontendUser()->getSession(); 

Die aktuelle User-Session holen.

\nn\t3::FrontendUser()->getSession();
Copied!

| @return \TYPO3\CMS\Core\Session\UserSession

| ➜ Go to source code of FrontendUser::getSession()

\nn\t3::FrontendUser()->getSessionData($key = NULL); 

Session-Data für FE-User holen

\nn\t3::FrontendUser()->getSessionData('shop')
Copied!

| @return mixed

| ➜ Go to source code of FrontendUser::getSessionData()

\nn\t3::FrontendUser()->getSessionId(); 

Session-ID des aktuellen Frontend-Users holen

$sessionId = \nn\t3::FrontendUser()->getSessionId();
Copied!

| @return string

| ➜ Go to source code of FrontendUser::getSessionId()

\nn\t3::FrontendUser()->hasRole($roleUid); 

Prüft, ob der User eine bestimmte Rolle hat.

\nn\t3::FrontendUser()->hasRole( $roleUid );
Copied!
@param $role
@return bool

| ➜ Go to source code of FrontendUser::hasRole()

\nn\t3::FrontendUser()->isInUserGroup($feGroups = NULL); 

Prüft, ob der aktuelle Frontend-User innerhalb einer bestimmte Benutzergruppe ist.

\nn\t3::FrontendUser()->isInUserGroup( 1 );
\nn\t3::FrontendUser()->isInUserGroup( ObjectStorage<FrontendUserGroup> );
\nn\t3::FrontendUser()->isInUserGroup( [FrontendUserGroup, FrontendUserGroup, ...] );
\nn\t3::FrontendUser()->isInUserGroup( [['uid'=>1, ...], ['uid'=>2, ...]] );
Copied!

| @return boolean

| ➜ Go to source code of FrontendUser::isInUserGroup()

\nn\t3::FrontendUser()->isLoggedIn($request = NULL); 

Prüft, ob der User aktuell als FE-User eingeloggt ist. Früher: isset($GLOBALS['TSFE']) && $GLOBALS['TSFE']->loginUser

// Prüfen nach vollständiger Initialisierung des Front/Backends
\nn\t3::FrontendUser()->isLoggedIn();

// Prüfen anhand des JWT, z.B. in einem eID-script vor Authentifizierung
\nn\t3::FrontendUser()->isLoggedIn( $request );
Copied!
@param ServerRequest $request
@return boolean

| ➜ Go to source code of FrontendUser::isLoggedIn()

\nn\t3::FrontendUser()->login($username, $password = NULL); 

User manuell einloggen. ab v10: Alias zu \nn\t3::FrontendUserAuthentication()->loginByUsername( $username );

\nn\t3::FrontendUser()->login('99grad');
Copied!
@param $username
@param $password @throws ReflectionException

| ➜ Go to source code of FrontendUser::login()

\nn\t3::FrontendUser()->logout(); 

Aktuellen FE-USer manuell ausloggen

\nn\t3::FrontendUser()->logout();
Copied!

| @return void

| ➜ Go to source code of FrontendUser::logout()

\nn\t3::FrontendUser()->removeCookie(); 

Aktuellen fe_typo_user-Cookie manuell löschen

\nn\t3::FrontendUser()->removeCookie()
Copied!

| @return void

| ➜ Go to source code of FrontendUser::removeCookie()

\nn\t3::FrontendUser()->resolveUserGroups($arr = [], $ignoreUids = []); 

Wandelt ein Array oder eine kommaseparierte Liste mit Benutzergrupen-UIDs in | fe_user_groups-Daten aus der Datenbank auf. Prüft auf geerbte Untergruppe.

\nn\t3::FrontendUser()->resolveUserGroups( [1,2,3] );
\nn\t3::FrontendUser()->resolveUserGroups( '1,2,3' );
Copied!

| @return array

| ➜ Go to source code of FrontendUser::resolveUserGroups()

\nn\t3::FrontendUser()->setCookie($sessionId = NULL, $request = NULL); 

Den fe_typo_user-Cookie manuell setzen.

Wird keine sessionID übergeben, sucht Typo3 selbst nach der Session-ID des FE-Users.

Bei Aufruf dieser Methode aus einer MiddleWare sollte der Request mit übergeben werden. Dadurch kann z.B. der globale $_COOKIE-Wert und der cookieParams.fe_typo_user im Request vor Authentifizierung über typo3/cms-frontend/authentication in einer eigenen MiddleWare gesetzt werden. Hilfreich, falls eine Crossdomain-Authentifizierung erforderlich ist (z.B. per Json Web Token / JWT).

\nn\t3::FrontendUser()->setCookie();
\nn\t3::FrontendUser()->setCookie( $sessionId );
\nn\t3::FrontendUser()->setCookie( $sessionId, $request );
Copied!

| @return void

| ➜ Go to source code of FrontendUser::setCookie()

\nn\t3::FrontendUser()->setPassword($feUserUid = NULL, $password = NULL); 

Passwort eines FE-Users ändern. Alias zu \nn\t3::FrontendUserAuthentication()->setPassword().

\nn\t3::FrontendUser()->setPassword( 12, '123passwort$#' );
\nn\t3::FrontendUser()->setPassword( $frontendUserModel, '123Passwort#$' );
Copied!

| @return boolean

| ➜ Go to source code of FrontendUser::setPassword()

\nn\t3::FrontendUser()->setSessionData($key = NULL, $val = NULL, $merge = true); 

Session-Data für FE-User setzen

// Session-data für `shop` mit neuen Daten mergen (bereits existierende keys in `shop` werden nicht gelöscht)
\nn\t3::FrontendUser()->setSessionData('shop', ['a'=>1]);

// Session-data für `shop` überschreiben (`a` aus dem Beispiel oben wird gelöscht)
\nn\t3::FrontendUser()->setSessionData('shop', ['b'=>1], false);
Copied!

| @return mixed

| ➜ Go to source code of FrontendUser::setSessionData()

Methods 

FrontendUser::get() 

\nn\t3::FrontendUser()->get(); 

Den aktuellen FE-User holen. Alias zu \nn\t3::FrontendUser()->getCurrentUser();

\nn\t3::FrontendUser()->get();
Copied!

Existiert auch als ViewHelper:

{nnt3:frontendUser.get(key:'first_name')}
{nnt3:frontendUser.get()->f:variable.set(name:'feUser')}
Copied!

| @return array

Source Code 

public function get()
{
	return $this->getCurrentUser();
}
Copied!

FrontendUser::getAvailableUserGroups() 

\nn\t3::FrontendUser()->getAvailableUserGroups($returnRowData = false); 

Alle existierende User-Gruppen zurückgeben. Gibt ein assoziatives Array zurück, key ist die uid, value der title.

\nn\t3::FrontendUser()->getAvailableUserGroups();
Copied!

Alternativ kann mit true der komplette Datensatz für die Benutzergruppen zurückgegeben werden:

\nn\t3::FrontendUser()->getAvailableUserGroups( true );
Copied!

| @return array

Source Code 

public function getAvailableUserGroups( $returnRowData = false )
{
	if (!($userGroupsByUid = $this->cache['userGroupsByUid'] ?? false)) {
		$userGroups = \nn\t3::Db()->findAll('fe_groups');
		$userGroupsByUid = \nn\t3::Arrays( $userGroups )->key('uid');
		$userGroupsByUid = $this->cache['userGroupsByUid'] = $userGroupsByUid->toArray();
	}
	if ($returnRowData) {
		return $userGroupsByUid;
	}
	return \nn\t3::Arrays($userGroupsByUid)->pluck('title')->toArray();
}
Copied!

FrontendUser::getCookie() 

\nn\t3::FrontendUser()->getCookie(); 

Holt den aktuellen fe_typo_user Cookie.

$cookie = \nn\t3::FrontendUser()->getCookie();
Copied!

| @return string

Source Code 

public function getCookie()
{
	$cookieName = $this->getCookieName();
	if ($request = &$GLOBALS['TYPO3_REQUEST']) {
		$cookieParams = $request->getCookieParams();
		if ($value = $cookieParams[$cookieName] ?? false) {
			return $value;
		}
	}
	if ($cookie = $_COOKIE[$cookieName] ?? false) {
		return $cookie;
	}
	if ($cookies = \nn\t3::Cookies()->getAll()) {
		return $cookies[$cookieName]['value'] ?? '';
	}
	return '';
}
Copied!

FrontendUser::getCookieName() 

\nn\t3::FrontendUser()->getCookieName(); 

Cookie-Name des Frontend-User-Cookies holen. Üblicherweise fe_typo_user, außer es wurde in der LocalConfiguration geändert.

\nn\t3::FrontendUser()->getCookieName();
Copied!

return string

Source Code 

public function getCookieName()
{
	if ($cookieName = $GLOBALS['TYPO3_CONF_VARS']['FE']['cookieName'] ?? false) {
		return $cookieName;
	}
	return \nn\t3::Environment()->getLocalConf('FE.cookieName');
}
Copied!

FrontendUser::getCurrentUser() 

\nn\t3::FrontendUser()->getCurrentUser(); 

Array mit den Daten des aktuellen FE-Users holen.

\nn\t3::FrontendUser()->getCurrentUser();
Copied!

| @return array

Source Code 

public function getCurrentUser()
{
	if (!$this->isLoggedIn()) return [];
	$user = $this->getFrontendUser();
	if ($user) {
		return $user->user ?? [];
	}
	// Ohne Frontend könnten wir uns z.B. in einer Middleware befinden. Nach AUTH sind die Daten evtl im Aspect.
	$context = GeneralUtility::makeInstance(Context::class);
	$userAspect = $context->getAspect('frontend.user');
	if (!$userAspect) return [];
	$usergroupUids = array_column($this->resolveUserGroups( $userAspect->get('groupIds') ), 'uid');
	// Daten zu Standard-Darstellung normalisieren
	return [
		'uid'			=> $userAspect->get('id'),
		'username'		=> $userAspect->get('username'),
		'usergroup'		=> join(',', $usergroupUids)
	] ?? [];
}
Copied!

FrontendUser::getCurrentUserGroups() 

\nn\t3::FrontendUser()->getCurrentUserGroups($returnRowData = false); 

Benutzergruppen des aktuellen FE-Users als Array holen. Die uids der Benutzergruppen werden im zurückgegebenen Array als Key verwendet.

// Minimalversion: Per default gibt Typo3 nur title, uid und pid zurück
\nn\t3::FrontendUser()->getCurrentUserGroups();          // [1 => ['title'=>'Gruppe A', 'uid' => 1, 'pid'=>5]]

// Mit true kann der komplette Datensatz für die fe_user_group aus der DB gelesen werden
\nn\t3::FrontendUser()->getCurrentUserGroups( true );    // [1 => [... alle Felder der DB] ]
Copied!

| @return array

Source Code 

public function getCurrentUserGroups( $returnRowData = false )
{
	if (!$this->isLoggedIn()) return [];
	if (($user = $this->getFrontendUser() ?? null)) {
		// Wenn wir ein Frontend haben...
		$rawGroupData = $user->groupData ?? [];
		$groupDataByUid = [];
		foreach (($rawGroupData['uid'] ?? []) as $i=>$uid) {
			$groupDataByUid[$uid] = [];
			if ($returnRowData) {
				$groupDataByUid[$uid] = \nn\t3::Db()->findByUid('fe_groups', $uid);
			}
			foreach ($rawGroupData as $field=>$arr) {
				$groupDataByUid[$uid][$field] = $arr[$i];
			}
		}
		return $groupDataByUid;
	}
	// ... oder in einem Kontext ohne Frontend sind (z.B. einer Middleware)
	$context = GeneralUtility::makeInstance(Context::class);
	$userAspect = $context->getAspect('frontend.user');
	if (!$userAspect) return [];
	$userGroups = $this->resolveUserGroups($userAspect->get('groupIds'));
	if ($returnRowData) {
		return \nn\t3::Arrays($userGroups)->key('uid')->toArray() ?: [];
	} else {
		return \nn\t3::Arrays($userGroups)->key('uid')->pluck(['uid', 'title', 'pid'])->toArray();
	}
	return [];
}
Copied!

FrontendUser::getCurrentUserUid() 

\nn\t3::FrontendUser()->getCurrentUserUid(); 

UID des aktuellen Frontend-Users holen

$uid = \nn\t3::FrontendUser()->getCurrentUserUid();
Copied!

| @return int

Source Code 

public function getCurrentUserUid()
{
	if (!($user = $this->getCurrentUser())) return null;
	return $user['uid'];
}
Copied!

FrontendUser::getGroups() 

\nn\t3::FrontendUser()->getGroups($returnRowData = false); 

Benutzergruppen des aktuellen FE-User holen. Alias zu \nn\t3::FrontendUser()->getCurrentUserGroups();

// nur title, uid und pid der Gruppen laden
\nn\t3::FrontendUser()->getGroups();
// kompletten Datensatz der Gruppen laden
\nn\t3::FrontendUser()->getGroups( true );
Copied!

| @return array

Source Code 

public function getGroups( $returnRowData = false )
{
	return $this->getCurrentUserGroups( $returnRowData );
}
Copied!

FrontendUser::getLanguage() 

\nn\t3::FrontendUser()->getLanguage(); 

Sprach-UID des aktuellen Users holen

$languageUid = \nn\t3::FrontendUser()->getLanguage();
Copied!

| @return int

Source Code 

public function getLanguage()
{
	return \nn\t3::Environment()->getLanguage();
}
Copied!

FrontendUser::getSession() 

\nn\t3::FrontendUser()->getSession(); 

Die aktuelle User-Session holen.

\nn\t3::FrontendUser()->getSession();
Copied!

| @return \TYPO3\CMS\Core\Session\UserSession

Source Code 

public function getSession()
{
	if ($session = $this->userSession) return $session;
	$user = $this->getFrontendUser();
	if ($user) {
		return $user->getSession();
	}
	$userSessionManager = UserSessionManager::create('FE');
	$session = $userSessionManager->createFromRequestOrAnonymous($GLOBALS['TYPO3_REQUEST'], $this->getCookieName());
	return $this->userSession = $session;
}
Copied!

FrontendUser::getSessionData() 

\nn\t3::FrontendUser()->getSessionData($key = NULL); 

Session-Data für FE-User holen

\nn\t3::FrontendUser()->getSessionData('shop')
Copied!

| @return mixed

Source Code 

public function getSessionData( $key = null )
{
	$session = $this->getSession();
	if (!$session) return $key ? '' : [];
	return $session->get( $key ) ?? [];
}
Copied!

FrontendUser::getSessionId() 

\nn\t3::FrontendUser()->getSessionId(); 

Session-ID des aktuellen Frontend-Users holen

$sessionId = \nn\t3::FrontendUser()->getSessionId();
Copied!

| @return string

Source Code 

public function getSessionId()
{
	if ($session = $this->getSession()) {
		if ($sessionId = $session->getIdentifier()) {
			return $sessionId;
		}
	}
	return $_COOKIE[$this->getCookieName()] ?? null;
}
Copied!

FrontendUser::hasRole() 

\nn\t3::FrontendUser()->hasRole($roleUid); 

Prüft, ob der User eine bestimmte Rolle hat.

\nn\t3::FrontendUser()->hasRole( $roleUid );
Copied!
@param $role
@return bool

Source Code 

public function hasRole($roleUid)
{
	if (!$this->isLoggedIn()) return false;
	$userGroupsByUid = $this->getCurrentUserGroups();
	return $userGroupsByUid[$roleUid] ?? false;
}
Copied!

FrontendUser::isInUserGroup() 

\nn\t3::FrontendUser()->isInUserGroup($feGroups = NULL); 

Prüft, ob der aktuelle Frontend-User innerhalb einer bestimmte Benutzergruppe ist.

\nn\t3::FrontendUser()->isInUserGroup( 1 );
\nn\t3::FrontendUser()->isInUserGroup( ObjectStorage<FrontendUserGroup> );
\nn\t3::FrontendUser()->isInUserGroup( [FrontendUserGroup, FrontendUserGroup, ...] );
\nn\t3::FrontendUser()->isInUserGroup( [['uid'=>1, ...], ['uid'=>2, ...]] );
Copied!

| @return boolean

Source Code 

public function isInUserGroup( $feGroups = null )
{
	if (!$this->isLoggedIn()) return false;
	$groupsByUid = $this->getCurrentUserGroups();
	$feGroupUids = [];
	if (is_int( $feGroups)) {
		$feGroupUids = [$feGroups];
	} else {
		foreach ($feGroups as $obj) {
			$uid = false;
			if (is_numeric($obj)) $uid = $obj;
			if (is_array($obj) && isset($obj['uid'])) $uid = $obj['uid'];
			if (is_object($obj) && method_exists($obj, 'getUid')) $uid = $obj->getUid();
			if ($uid) $feGroupUids[] = $uid;
		}
	}
	$matches = array_intersect( array_keys($groupsByUid), $feGroupUids );
	return count($matches) > 0;
}
Copied!

FrontendUser::isLoggedIn() 

\nn\t3::FrontendUser()->isLoggedIn($request = NULL); 

Prüft, ob der User aktuell als FE-User eingeloggt ist. Früher: isset($GLOBALS['TSFE']) && $GLOBALS['TSFE']->loginUser

// Prüfen nach vollständiger Initialisierung des Front/Backends
\nn\t3::FrontendUser()->isLoggedIn();

// Prüfen anhand des JWT, z.B. in einem eID-script vor Authentifizierung
\nn\t3::FrontendUser()->isLoggedIn( $request );
Copied!
@param ServerRequest $request
@return boolean

Source Code 

public function isLoggedIn( $request = null )
{
	if ($request) {
		$cookieName = $this->getCookieName();
		$jwt = $request->getCookieParams()[$cookieName] ?? false;
		$identifier = false;
		if ($jwt) {
			try {
				$params = $request->getAttribute('normalizedParams') ?? NormalizedParams::createFromRequest($request);
				$cookieScope = $this->getCookieScope( $params );
				$identifier = \TYPO3\CMS\Core\Session\UserSession::resolveIdentifierFromJwt($jwt, $cookieScope);
			} catch( \Exception $e ) {}
		}
		if ($identifier) return true;
	}
	$user = $this->getFrontendUser();
	// Context `frontend.user.isLoggedIn` scheint in Middleware nicht zu gehen. Fallback auf TSFE.
	$loginUserFromTsfe = $user && isset($user->user['uid']);
	$context = GeneralUtility::makeInstance(Context::class);
	return $context->getPropertyFromAspect('frontend.user', 'isLoggedIn') || $loginUserFromTsfe;
}
Copied!

FrontendUser::login() 

\nn\t3::FrontendUser()->login($username, $password = NULL); 

User manuell einloggen. ab v10: Alias zu \nn\t3::FrontendUserAuthentication()->loginByUsername( $username );

\nn\t3::FrontendUser()->login('99grad');
Copied!
@param $username
@param $password @throws ReflectionException

Source Code 

public function login( $username, $password = null )
{
	if ($password !== null) {
		die('Please use \nn\t3::FrontendUserAuthentication()->login()');
	}
	$user = \nn\t3::FrontendUserAuthentication()->loginByUsername( $username );
	return $user ?: [];
}
Copied!

FrontendUser::logout() 

\nn\t3::FrontendUser()->logout(); 

Aktuellen FE-USer manuell ausloggen

\nn\t3::FrontendUser()->logout();
Copied!

| @return void

Source Code 

public function logout()
{
	if (!$this->isLoggedIn()) return false;
	// In der MiddleWare ist der FE-User evtl. noch nicht initialisiert...
	if ($TSFE = \nn\t3::Tsfe()->get()) {
		if (($TSFE->fe_user ?? null) && method_exists($TSFE->fe_user, 'logoff')) {
			$TSFE->fe_user->logoff();
		}
	}
	// Session-Daten aus Tabelle `fe_sessions` löschen
	if ($sessionManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Session\SessionManager::class)) {
		$sessionBackend = $sessionManager->getSessionBackend('FE');
		if ($sessionId = $this->getSessionId()) {
			$sessionBackend->remove( $sessionId );
		}
	}
	// ... aber Cookie löschen geht immer!
	$this->removeCookie();
	// ToDo: Replace with Signal/Slot when deprecated
	if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed'] ?? false) {
		$_params = array();
		foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed'] as $_funcRef) {
			if ($_funcRef) GeneralUtility::callUserFunction($_funcRef, $_params, $this);
		}
	}
}
Copied!

FrontendUser::removeCookie() 

\nn\t3::FrontendUser()->removeCookie(); 

Aktuellen fe_typo_user-Cookie manuell löschen

\nn\t3::FrontendUser()->removeCookie()
Copied!

| @return void

Source Code 

public function removeCookie()
{
	$cookieName = $this->getCookieName();
	\nn\t3::Cookies()->add( $cookieName, '', -1 );
}
Copied!

FrontendUser::resolveUserGroups() 

\nn\t3::FrontendUser()->resolveUserGroups($arr = [], $ignoreUids = []); 

Wandelt ein Array oder eine kommaseparierte Liste mit Benutzergrupen-UIDs in | fe_user_groups-Daten aus der Datenbank auf. Prüft auf geerbte Untergruppe.

\nn\t3::FrontendUser()->resolveUserGroups( [1,2,3] );
\nn\t3::FrontendUser()->resolveUserGroups( '1,2,3' );
Copied!

| @return array

Source Code 

public function resolveUserGroups( $arr = [], $ignoreUids = [] )
{
	$arr = \nn\t3::Arrays( $arr )->intExplode();
	if (!$arr) return [];
	return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\GroupResolver::class)->resolveGroupsForUser(['usergroup'=>join(',', $arr)], 'fe_groups');
}
Copied!

FrontendUser::setCookie() 

\nn\t3::FrontendUser()->setCookie($sessionId = NULL, $request = NULL); 

Den fe_typo_user-Cookie manuell setzen.

Wird keine sessionID übergeben, sucht Typo3 selbst nach der Session-ID des FE-Users.

Bei Aufruf dieser Methode aus einer MiddleWare sollte der Request mit übergeben werden. Dadurch kann z.B. der globale $_COOKIE-Wert und der cookieParams.fe_typo_user im Request vor Authentifizierung über typo3/cms-frontend/authentication in einer eigenen MiddleWare gesetzt werden. Hilfreich, falls eine Crossdomain-Authentifizierung erforderlich ist (z.B. per Json Web Token / JWT).

\nn\t3::FrontendUser()->setCookie();
\nn\t3::FrontendUser()->setCookie( $sessionId );
\nn\t3::FrontendUser()->setCookie( $sessionId, $request );
Copied!

| @return void

Source Code 

public function setCookie( $sessionId = null, &$request = null )
{
	if (!$sessionId) {
		$sessionId = $this->getSessionId();
	}
	$jwt = self::encodeHashSignedJwt(
		[
			'identifier' => $sessionId,
			'time' => (new \DateTimeImmutable())->format(\DateTimeImmutable::RFC3339),
		],
		self::createSigningKeyFromEncryptionKey(UserSession::class)
	);
	$cookieName = $this->getCookieName();
	$_COOKIE[$cookieName] = $jwt;
	\nn\t3::Cookies()->add( $cookieName, $jwt );
}
Copied!

FrontendUser::setPassword() 

\nn\t3::FrontendUser()->setPassword($feUserUid = NULL, $password = NULL); 

Passwort eines FE-Users ändern. Alias zu \nn\t3::FrontendUserAuthentication()->setPassword().

\nn\t3::FrontendUser()->setPassword( 12, '123passwort$#' );
\nn\t3::FrontendUser()->setPassword( $frontendUserModel, '123Passwort#$' );
Copied!

| @return boolean

Source Code 

public function setPassword( $feUserUid = null, $password = null )
{
	return \nn\t3::FrontendUserAuthentication()->setPassword( $feUserUid, $password );
}
Copied!

FrontendUser::setSessionData() 

\nn\t3::FrontendUser()->setSessionData($key = NULL, $val = NULL, $merge = true); 

Session-Data für FE-User setzen

// Session-data für `shop` mit neuen Daten mergen (bereits existierende keys in `shop` werden nicht gelöscht)
\nn\t3::FrontendUser()->setSessionData('shop', ['a'=>1]);

// Session-data für `shop` überschreiben (`a` aus dem Beispiel oben wird gelöscht)
\nn\t3::FrontendUser()->setSessionData('shop', ['b'=>1], false);
Copied!

| @return mixed

Source Code 

public function setSessionData( $key = null, $val = null, $merge = true )
{
	$session = $this->getSession();
	$sessionData = $merge ? $this->getSessionData( $key ) : [];
	if (is_array($val)) {
		ArrayUtility::mergeRecursiveWithOverrule( $sessionData, $val );
	} else {
		$sessionData = $val;
	}
	$session->set( $key, $sessionData );
	$this->getFrontendUser()->storeSessionData();
	return $sessionData;
}
Copied!

FrontendUserAuthentication 

\nn\t3::FrontendUserAuthentication() 

Frontend-User Methoden: Von Einloggen bis Passwort-Änderung

Overview of Methods 

\nn\t3::FrontendUserAuthentication()->login($username = '', $password = '', $startFeUserSession = true); 

Login eines FE-Users anhand der Usernamens und Passwortes

// Credentials überprüfen und feUser-Session starten
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password' );

// Nur überprüfen, keine feUser-Session aufbauen
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password', false );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::login()

\nn\t3::FrontendUserAuthentication()->loginBySessionId($sessionId = ''); 

Login eines FE-Users anhand einer Session-ID.

Die Session-ID entspricht dem TYPO3 Cookie fe_typo_user. In der Regel gibt es für jede Fe-User-Session einen Eintrag in der Tabelle fe_sessions. Bis zu Typo3 v10 entsprach die Spalte ses_id exakt dem Cookie-Wert.

Ab Typo3 v10 wird der Wert zusätzlich gehashed.

Siehe auch \nn\t3::Encrypt()->hashSessionId( $sessionId );

\nn\t3::FrontendUserAuthentication()->loginBySessionId( $sessionId );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginBySessionId()

\nn\t3::FrontendUserAuthentication()->loginByUsername($username = ''); 

Login eines FE-Users anhand der Usernamens

\nn\t3::FrontendUserAuthentication()->loginByUsername( '99grad' );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginByUsername()

\nn\t3::FrontendUserAuthentication()->loginField($value = NULL, $fieldName = 'uid'); 

Login eines FE-Users anhand eines beliebigen Feldes. Kein Passwort erforderlich.

\nn\t3::FrontendUserAuthentication()->loginField( $value, $fieldName );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginField()

\nn\t3::FrontendUserAuthentication()->loginUid($uid = NULL); 

Login eines FE-Users anhand einer fe_user.uid

\nn\t3::FrontendUserAuthentication()->loginUid( 1 );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginUid()

\nn\t3::FrontendUserAuthentication()->prepareSession($usernameOrUid = NULL, $unhashedSessionId = NULL); 

Eine neue FrontenUser-Session in der Tabelle fe_sessions anlegen. Es kann wahlweise die fe_users.uid oder der fe_users.username übergeben werden.

Der User wird dabei nicht automatisch eingeloggt. Stattdessen wird nur eine gültige Session in der Datenbank angelegt und vorbereitet, die Typo3 später zur Authentifizierung verwenden kann.

Gibt die Session-ID zurück.

Die Session-ID entspricht hierbei exakt dem Wert im fe_typo_user-Cookie - aber nicht zwingend dem Wert, der in fe_sessions.ses_id gespeichert wird. Der Wert in der Datenbank wird ab TYPO3 v11 gehashed.

$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 1 );
$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 'david' );

$hashInDatabase = \nn\t3::Encrypt()->hashSessionId( $sessionId );
Copied!

Falls die Session mit einer existierenden SessionId erneut aufgebaut werden soll, kann als optionaler, zweiter Parameter eine (nicht-gehashte) SessionId übergeben werden:

\nn\t3::FrontendUserAuthentication()->prepareSession( 1, 'meincookiewert' );
\nn\t3::FrontendUserAuthentication()->prepareSession( 1, $_COOKIE['fe_typo_user'] );
Copied!

| @return string

| ➜ Go to source code of FrontendUserAuthentication::prepareSession()

\nn\t3::FrontendUserAuthentication()->setPassword($feUserUid = NULL, $password = NULL); 

Passwort eines FE-Users ändern.

\nn\t3::FrontendUserAuthentication()->setPassword( 12, '123Passwort#$' );
\nn\t3::FrontendUserAuthentication()->setPassword( $frontendUserModel, '123Passwort#$' );
Copied!

| @return boolean

| ➜ Go to source code of FrontendUserAuthentication::setPassword()

Methods 

FrontendUserAuthentication::login() 

\nn\t3::FrontendUserAuthentication()->login($username = '', $password = '', $startFeUserSession = true); 

Login eines FE-Users anhand der Usernamens und Passwortes

// Credentials überprüfen und feUser-Session starten
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password' );

// Nur überprüfen, keine feUser-Session aufbauen
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password', false );
Copied!

| @return array

Source Code 

public function login( $username = '', $password = '', $startFeUserSession = true )
{
	if (!trim($password) || !trim($username)) return [];
	$user = \nn\t3::Db()->findByValues( 'fe_users', ['username'=>$username] );
	if (!$user) return [];
	if (count($user) > 1) return [];
	$user = array_pop($user);
	if (!\nn\t3::Encrypt()->checkPassword($password, $user['password'])) {
		return [];
	}
	if (!$startFeUserSession) {
		return $user;
	}
	$request = \nn\t3::Environment()->getRequest();
	$info = $this->getAuthInfoArray($request);
	$info['db_user']['username_column'] = 'username';
	$feUser = $this->setSession( $user );
	return $feUser;
}
Copied!

FrontendUserAuthentication::loginBySessionId() 

\nn\t3::FrontendUserAuthentication()->loginBySessionId($sessionId = ''); 

Login eines FE-Users anhand einer Session-ID.

Die Session-ID entspricht dem TYPO3 Cookie fe_typo_user. In der Regel gibt es für jede Fe-User-Session einen Eintrag in der Tabelle fe_sessions. Bis zu Typo3 v10 entsprach die Spalte ses_id exakt dem Cookie-Wert.

Ab Typo3 v10 wird der Wert zusätzlich gehashed.

Siehe auch \nn\t3::Encrypt()->hashSessionId( $sessionId );

\nn\t3::FrontendUserAuthentication()->loginBySessionId( $sessionId );
Copied!

| @return array

Source Code 

public function loginBySessionId( $sessionId = '' )
{
	if (!trim($sessionId)) return [];
	$sessionId = \nn\t3::Encrypt()->hashSessionId( $sessionId );
	$session = \nn\t3::Db()->findOneByValues( 'fe_sessions', ['ses_id'=>$sessionId] );
	if (!$session) return [];
	if ($feUserUid = $session['ses_userid']) {
		return $this->loginUid( $feUserUid );
	}
	return [];
}
Copied!

FrontendUserAuthentication::loginByUsername() 

\nn\t3::FrontendUserAuthentication()->loginByUsername($username = ''); 

Login eines FE-Users anhand der Usernamens

\nn\t3::FrontendUserAuthentication()->loginByUsername( '99grad' );
Copied!

| @return array

Source Code 

public function loginByUsername( $username = '' )
{
	if (!trim($username)) return [];
	$user = \nn\t3::Db()->findByValues( 'fe_users', ['username'=>$username] );
	if (!$user) return [];
	if (count($user) > 1) return [];
	$user = $user[0];
	$request = \nn\t3::Environment()->getRequest();
	$info = $this->getAuthInfoArray($request);
	$info['db_user']['username_column'] = 'username';
	$feUser = $this->setSession( $user );
	return $feUser;
}
Copied!

FrontendUserAuthentication::loginField() 

\nn\t3::FrontendUserAuthentication()->loginField($value = NULL, $fieldName = 'uid'); 

Login eines FE-Users anhand eines beliebigen Feldes. Kein Passwort erforderlich.

\nn\t3::FrontendUserAuthentication()->loginField( $value, $fieldName );
Copied!

| @return array

Source Code 

public function loginField( $value = null, $fieldName = 'uid')
{
	if (!$value) return [];
	$user = \nn\t3::Db()->findByValues( 'fe_users', [$fieldName => $value] );
	if (!$user) return [];
	if (!count($user) > 1) return [];
	$user = array_pop($user);
	$request = \nn\t3::Environment()->getRequest();
	$info = $this->getAuthInfoArray($request);
	$info['db_user']['username_column'] = 'username';
	$feUser = $this->setSession( $user );
	return $feUser;
}
Copied!

FrontendUserAuthentication::loginUid() 

\nn\t3::FrontendUserAuthentication()->loginUid($uid = NULL); 

Login eines FE-Users anhand einer fe_user.uid

\nn\t3::FrontendUserAuthentication()->loginUid( 1 );
Copied!

| @return array

Source Code 

public function loginUid( $uid = null )
{
	$uid = intval($uid);
	if (!$uid) return [];
	$user = \nn\t3::Db()->findByUid( 'fe_users', $uid );
	if (!$user) return [];
	$request = \nn\t3::Environment()->getRequest();
	$info = $this->getAuthInfoArray($request);
	$info['db_user']['username_column'] = 'username';
	$feUser = $this->setSession( $user );
	return $feUser;
}
Copied!

FrontendUserAuthentication::prepareSession() 

\nn\t3::FrontendUserAuthentication()->prepareSession($usernameOrUid = NULL, $unhashedSessionId = NULL); 

Eine neue FrontenUser-Session in der Tabelle fe_sessions anlegen. Es kann wahlweise die fe_users.uid oder der fe_users.username übergeben werden.

Der User wird dabei nicht automatisch eingeloggt. Stattdessen wird nur eine gültige Session in der Datenbank angelegt und vorbereitet, die Typo3 später zur Authentifizierung verwenden kann.

Gibt die Session-ID zurück.

Die Session-ID entspricht hierbei exakt dem Wert im fe_typo_user-Cookie - aber nicht zwingend dem Wert, der in fe_sessions.ses_id gespeichert wird. Der Wert in der Datenbank wird ab TYPO3 v11 gehashed.

$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 1 );
$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 'david' );

$hashInDatabase = \nn\t3::Encrypt()->hashSessionId( $sessionId );
Copied!

Falls die Session mit einer existierenden SessionId erneut aufgebaut werden soll, kann als optionaler, zweiter Parameter eine (nicht-gehashte) SessionId übergeben werden:

\nn\t3::FrontendUserAuthentication()->prepareSession( 1, 'meincookiewert' );
\nn\t3::FrontendUserAuthentication()->prepareSession( 1, $_COOKIE['fe_typo_user'] );
Copied!

| @return string

Source Code 

public function prepareSession( $usernameOrUid = null, $unhashedSessionId = null )
{
	if (!$usernameOrUid) return null;
	if ($uid = intval($usernameOrUid)) {
		$user = \nn\t3::Db()->findByUid('fe_users', $uid);
	} else {
		$user = \nn\t3::Db()->findOneByValues('fe_users', ['username'=>$usernameOrUid]);
	}
	if (!$user) return null;
	if (!$unhashedSessionId) {
		$unhashedSessionId = $this->createSessionId();
	}
	$hashedSessionId = \nn\t3::Encrypt()->hashSessionId( $unhashedSessionId );
	$existingSession = \nn\t3::Db()->findOneByValues('fe_sessions', ['ses_id'=>$hashedSessionId]);
	if (!$existingSession) {
		$this->id = $hashedSessionId;
		$record = $this->elevateToFixatedUserSession($unhashedSessionId, $user['uid']);
		\nn\t3::Db()->insert('fe_sessions', $record);
	} else {
		\nn\t3::Db()->update('fe_sessions', ['ses_tstamp'=>$GLOBALS['EXEC_TIME']], ['ses_id'=>$hashedSessionId]);
	}
	$request = \nn\t3::Environment()->getRequest();
	$this->start( $request );
	return $unhashedSessionId;
}
Copied!

FrontendUserAuthentication::setPassword() 

\nn\t3::FrontendUserAuthentication()->setPassword($feUserUid = NULL, $password = NULL); 

Passwort eines FE-Users ändern.

\nn\t3::FrontendUserAuthentication()->setPassword( 12, '123Passwort#$' );
\nn\t3::FrontendUserAuthentication()->setPassword( $frontendUserModel, '123Passwort#$' );
Copied!

| @return boolean

Source Code 

public function setPassword( $feUserUid = null, $password = null )
{
	if (!$password || !$feUserUid) return false;
	if (!is_numeric($feUserUid)) $feUserUid = \nn\t3::Obj()->get( $feUserUid, 'uid' );
	$saltedPassword = \nn\t3::Encrypt()->password( $password );
	\nn\t3::Db()->update( 'fe_users', [
		'password' => $saltedPassword,
		'pwchanged' => time(),
	], $feUserUid);
	return true;
}
Copied!

Geo 

\nn\t3::Geo() 

Berechnungen und Konvertieren von Geopositionen und Daten.

Zum Umwandeln von Geo-Koordinaten in Adressdaten und umgekehrt, muss ein Google Maps ApiKey erstellt werden und im Extension Manager für nnhelpers hinterlegt werden. Alternativ kann beim Initialisieren ein eigener Api-Key angegeben werden:

nn\t3::Geo( $myApiKey )->getCoordinates('...');
Copied!

Overview of Methods 

\nn\t3::Geo()->autoComplete($params = []); 

Autocomplete Suche: Findet Adressen (Namen) anhand eines Suchwortes

$results = \nn\t3::Geo()->autoComplete('99grad Wiesbaden');
$results = \nn\t3::Geo()->autoComplete(['keyword'=>'99grad', 'lat'=>'50.08', 'lng'=>'8.25', 'radius'=>2, 'type'=>['university']]);
Copied!
@param array|string $params
@return array

| ➜ Go to source code of Geo::autoComplete()

\nn\t3::Geo()->getAddress($lng = 8.2506933201813, $lat = 50.08060702093, $returnAll = false, $language = 'de'); 

Geo-Koordinaten in Adress-Daten umwandeln (Reverse Geo Coding) Falls die Extension nnaddress installiert ist, wird diese für die Auflösung verwenden.

// Erstes Ergebnis zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021 );

// ALLE Ergebnisse zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true );

// ALLE Ergebnisse in Englisch zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true, 'en' );

// $lng und $lat kann auch als Array übergeben werden
\nn\t3::Geo()->getAddress( ['lat'=>50.08060702093021, 'lng'=>8.250693320181336] );

// Eigenen API-Key verwenden?
\nn\t3::Geo( $apiKey )->getAddress( 8.250693320181336, 50.08060702093021 );
Copied!

Beispiel für Rückgabe:

[
    'lat' => 50.0805069,
    'lng' => 8.2508677,
    'street' => 'Blumenstrass 2',
    'zip' => '65189',
    'city' => 'Wiesbaden',
    ...
]
Copied!
@param array|float $lng
@param float|bool $lat
@param bool $returnAll
@return array

| ➜ Go to source code of Geo::getAddress()

\nn\t3::Geo()->getApiKey(); 

Api-Key für Methoden in dieser Klasse holen. Der Api-Key kann entweder beim Initialisieren von \nn\t3::Geo() angegeben werden oder im Extension Manager für nnhelpers.

\nn\t3::Geo( $myApiKey )->getCoordinates('Blumenstrasse 2, 65189 Wiesbaden');
\nn\t3::Geo(['apiKey'=>$myApiKey])->getCoordinates('Blumenstrasse 2, 65189 Wiesbaden');
Copied!

| @return string

| ➜ Go to source code of Geo::getApiKey()

\nn\t3::Geo()->getCoordinates($address = '', $returnAll = false, $language = 'de'); 

Adressdaten in Geo-Koordinaten umwandeln (Geo Coding) Falls die Extension nnaddress installiert ist, wird diese für die Auflösung verwenden.

// Abfrage per String, erstes Ergebnis zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );

// Abfrage per Array
\nn\t3::Geo()->getCoordinates( ['street'=>'Blumenstrasse 2', 'zip'=>'65189', 'city'=>'Wiesbaden', 'country'=>'DE'] );

// Alle Ergebnisse zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true );

// Alle Ergebnisse in English zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true, 'en' );

// Eingenen Api-Key verwenden
\nn\t3::Geo( $apiKey )->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );
Copied!

Beispiel für Rückgabe:

[
    'lat' => 50.0805069,
    'lng' => 8.2508677,
    'street' => 'Blumenstrass 2',
    'zip' => '65189',
    'city' => 'Wiesbaden',
    ...
]
Copied!
@param array|string $address
@return array

| ➜ Go to source code of Geo::getCoordinates()

\nn\t3::Geo()->getNearby($params = []); 

Nearby Suche: Findet POIs in der Nähe eines Punktes Siehe https://bit.ly/43CXxjX für mögliche type-Angaben.

$results = \nn\t3::Geo()->getNearby(['lat'=>'50.08', 'lng'=>'8.25', 'radius'=>2, 'type'=>['university']])
Copied!
@param array $params
@return array

| ➜ Go to source code of Geo::getNearby()

\nn\t3::Geo()->parseAddressCompontent($row = []); 

Normalisiert ein Ergebnis aus dem GeoCoding

@param array $row
@return array

| ➜ Go to source code of Geo::parseAddressCompontent()

\nn\t3::Geo()->toGps($coordinate, $hemisphere); 

GPS-Koordinaten in lesbare Latitude/Longitude-Koordinaten umrechnen

\nn\t3::Geo()->toGps( ['50/1', '4/1', '172932/3125'], 'W' );
Copied!

| @return array

| ➜ Go to source code of Geo::toGps()

Methods 

Geo::autoComplete() 

\nn\t3::Geo()->autoComplete($params = []); 

Autocomplete Suche: Findet Adressen (Namen) anhand eines Suchwortes

$results = \nn\t3::Geo()->autoComplete('99grad Wiesbaden');
$results = \nn\t3::Geo()->autoComplete(['keyword'=>'99grad', 'lat'=>'50.08', 'lng'=>'8.25', 'radius'=>2, 'type'=>['university']]);
Copied!
@param array|string $params
@return array

Source Code 

public function autoComplete( $params = [] )
{
	if (is_string($params)) {
		$params = ['keyword'=>$params];
	}
	$params = array_merge([
		'language' 	=> 'de',
		'types'		=> [],
	], $params);
	if (is_string($params['types'])) {
		$params['types'] = \nn\t3::Arrays( $params['types'] )->trimExplode();
	}
	$reqVars = [
		'input'			=> $params['keyword'],
		'language'		=> $params['language'],
		'key'			=> $this->getApiKey(),
	];
	if ($params['lat'] ?? false) {
		$reqVars['location'] = "{$params['lat']},{$params['lng']}";
	}
	if ($params['radius'] ?? false) {
		$reqVars['radius'] = $params['radius'] * 1000;
	}
	if ($params['type'] ?? false) {
		$reqVars['type'] = join('|', $params['types']);
	}
	$result = \nn\t3::Request()->GET( 'https://maps.googleapis.com/maps/api/place/autocomplete/json', $reqVars );
	$data = json_decode( $result['content'] ?? '', true );
	if ($error = $data['error_message'] ?? false) {
		\nn\t3::Exception( '\nn\t3::Geo()->getCoordinates() : ' . $error );
	}
	foreach ($data['predictions'] as &$result) {
		$result = [
			'name' 				=> $result['structured_formatting']['main_text'] ?? '',
			'address' 			=> $result['structured_formatting']['secondary_text'] ?? '',
			'google_place_id' 	=> $result['place_id'],
		];
	}
	return $data['predictions'];
}
Copied!

Geo::getAddress() 

\nn\t3::Geo()->getAddress($lng = 8.2506933201813, $lat = 50.08060702093, $returnAll = false, $language = 'de'); 

Geo-Koordinaten in Adress-Daten umwandeln (Reverse Geo Coding) Falls die Extension nnaddress installiert ist, wird diese für die Auflösung verwenden.

// Erstes Ergebnis zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021 );

// ALLE Ergebnisse zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true );

// ALLE Ergebnisse in Englisch zurückgeben
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true, 'en' );

// $lng und $lat kann auch als Array übergeben werden
\nn\t3::Geo()->getAddress( ['lat'=>50.08060702093021, 'lng'=>8.250693320181336] );

// Eigenen API-Key verwenden?
\nn\t3::Geo( $apiKey )->getAddress( 8.250693320181336, 50.08060702093021 );
Copied!

Beispiel für Rückgabe:

[
    'lat' => 50.0805069,
    'lng' => 8.2508677,
    'street' => 'Blumenstrass 2',
    'zip' => '65189',
    'city' => 'Wiesbaden',
    ...
]
Copied!
@param array|float $lng
@param float|bool $lat
@param bool $returnAll
@return array

Source Code 

public function getAddress ( $lng = 8.250693320181336, $lat = 50.08060702093021, $returnAll = false, $language = 'de' ) {
	$results = [];
	if (is_array($lng)) {
		$returnAll = $lat;
		$lat = $lng['lat'] ?? 0;
		$lng = $lng['lng'] ?? 0;
	}
	// EXT:nnaddress verwenden, falls vorhanden
	if (\nn\t3::Environment()->extLoaded('nnaddress')) {
		$addressService = GeneralUtility::makeInstance( \Nng\Nnaddress\Services\AddressService::class );
		if ($addresses = $addressService->getAddressForGeoCoordinates( ['lng'=>$lng, 'lat'=>$lat] )) {
			foreach ($addresses as $address) {
				$results[] = [
					'street' 	=> $address['street'],
					'zip' 		=> $address['postal_code'],
					'city' 		=> $address['locality'],
					'country' 	=> $address['political'],
				];
			}
		}
	} else {
		$apiKey = $this->getApiKey();
		if (!$apiKey) return [];
		$result = \nn\t3::Request()->GET(
			'https://maps.googleapis.com/maps/api/geocode/json', [
				'latlng' 	=> $lat . ',' . $lng,
				'key'		=> $apiKey,
				'language'	=> $language,
			]);
		$data = json_decode( $result['content'], true );
		foreach ($data['results'] as &$result) {
			$result = $this->parseAddressCompontent( $result );
		}
		$results = $data['results'];
	}
	if (!$results) return [];
	return $returnAll ? $results : array_shift($results);
}
Copied!

Geo::getApiKey() 

\nn\t3::Geo()->getApiKey(); 

Api-Key für Methoden in dieser Klasse holen. Der Api-Key kann entweder beim Initialisieren von \nn\t3::Geo() angegeben werden oder im Extension Manager für nnhelpers.

\nn\t3::Geo( $myApiKey )->getCoordinates('Blumenstrasse 2, 65189 Wiesbaden');
\nn\t3::Geo(['apiKey'=>$myApiKey])->getCoordinates('Blumenstrasse 2, 65189 Wiesbaden');
Copied!

| @return string

Source Code 

public function getApiKey() {
	$apiKey = $this->config['apiKey'] ?? \nn\t3::Environment()->getExtConf('nnhelpers')['googleGeoApiKey'] ?? false;
	return $apiKey;
}
Copied!

Geo::getCoordinates() 

\nn\t3::Geo()->getCoordinates($address = '', $returnAll = false, $language = 'de'); 

Adressdaten in Geo-Koordinaten umwandeln (Geo Coding) Falls die Extension nnaddress installiert ist, wird diese für die Auflösung verwenden.

// Abfrage per String, erstes Ergebnis zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );

// Abfrage per Array
\nn\t3::Geo()->getCoordinates( ['street'=>'Blumenstrasse 2', 'zip'=>'65189', 'city'=>'Wiesbaden', 'country'=>'DE'] );

// Alle Ergebnisse zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true );

// Alle Ergebnisse in English zurückgeben
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true, 'en' );

// Eingenen Api-Key verwenden
\nn\t3::Geo( $apiKey )->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );
Copied!

Beispiel für Rückgabe:

[
    'lat' => 50.0805069,
    'lng' => 8.2508677,
    'street' => 'Blumenstrass 2',
    'zip' => '65189',
    'city' => 'Wiesbaden',
    ...
]
Copied!
@param array|string $address
@return array

Source Code 

public function getCoordinates ( $address = '', $returnAll = false, $language = 'de' ) {
	// EXT:nnaddress verwenden, falls vorhanden
	if (\nn\t3::Environment()->extLoaded('nnaddress')) {
		$addressService = \nn\t3::injectClass( \Nng\Nnaddress\Services\AddressService::class );
		if ($coordinates = $addressService->getGeoCoordinatesForAddress( $address )) {
			return $coordinates;
		}
	}
	if (is_array($address)) {
		$address = [
			'street' 	=> $address['street'] ?? '',
			'zip' 		=> $address['zip'] ?? '',
			'city' 		=> $address['city'] ?? '',
			'country' 	=> $address['country'] ?? '',
		];
		$address = "{$address['street']}, {$address['zip']} {$address['city']}, {$address['country']}";
	}
	$address = trim($address, ', ');
	$apiKey = $this->getApiKey();
	if (!$apiKey) return [];
	$result = \nn\t3::Request()->GET(
		'https://maps.googleapis.com/maps/api/geocode/json', [
			'address' 	=> $address,
			'key'		=> $apiKey,
			'language'	=> $language,
		]);
	$data = json_decode( $result['content'], true );
	if ($error = $data['error_message'] ?? false) {
		\nn\t3::Exception( '\nn\t3::Geo()->getCoordinates() : ' . $error );
	}
	foreach ($data['results'] as &$result) {
		$result = $this->parseAddressCompontent( $result );
	}
	return $returnAll ? $data['results'] : array_shift( $data['results'] );
}
Copied!

Geo::getNearby() 

\nn\t3::Geo()->getNearby($params = []); 

Nearby Suche: Findet POIs in der Nähe eines Punktes Siehe https://bit.ly/43CXxjX für mögliche type-Angaben.

$results = \nn\t3::Geo()->getNearby(['lat'=>'50.08', 'lng'=>'8.25', 'radius'=>2, 'type'=>['university']])
Copied!
@param array $params
@return array

Source Code 

public function getNearby( $params = [] )
{
	$params = array_merge([
		'lat' 		=> 50.08060702093021,
		'lng'		=> 8.250693320181336,
		'radius' 	=> 5,
		'language' 	=> 'de',
		'types'		=> [],
	], $params);
	if (is_string($params['types'])) {
		$params['types'] = \nn\t3::Arrays( $params['types'] )->trimExplode();
	}
	$reqVars = [
		'location' 		=> "{$params['lat']},{$params['lng']}",
		'radius' 		=> $params['radius'] * 1000,
		'type'			=> join('|', $params['types']),
		'language'		=> $params['language'],
		'key'			=> $this->getApiKey(),
	];
	$result = \nn\t3::Request()->GET( 'https://maps.googleapis.com/maps/api/place/nearbysearch/json', $reqVars );
	$data = json_decode( $result['content'] ?? '', true );
	if ($error = $data['error_message'] ?? false) {
		\nn\t3::Exception( '\nn\t3::Geo()->getCoordinates() : ' . $error );
	}
	foreach ($data['results'] as &$result) {
		$result = $this->parseAddressCompontent( $result );
	}
	return $data['results'];
}
Copied!

Geo::parseAddressCompontent() 

\nn\t3::Geo()->parseAddressCompontent($row = []); 

Normalisiert ein Ergebnis aus dem GeoCoding

@param array $row
@return array

Source Code 

public function parseAddressCompontent( $row = [] )
{
	if (!$row) $row = [];
	$address = [];
	$addressShort = [];
	foreach ($row['address_components'] as $r) {
		foreach ($r['types'] as $n) {
			$address[$n] = $r['long_name'];
			$addressShort[$n] = $r['short_name'];
		}
	}
	$address['name'] = $row['name'] ?? '';
	$address['country_short'] = $addressShort['country'] ?? '';
	$address['street'] = trim(($address['route'] ?? '') . ' ' . ($address['street_number'] ?? '') );
	$address['zip'] = $address['postal_code'] ?? '';
	$address['city'] = $address['locality'] ?? '';
	$address['formatted_phone_number'] = $address['phone'] = $row['formatted_phone_number'] ?? '';
	$address['international_phone_number'] = $row['international_phone_number'] ?? '';
	$address['lat'] = $row['geometry']['location']['lat'] ?? null;
	$address['lng'] = $row['geometry']['location']['lng'] ?? null;
	$address['google_id'] = $row['id'] ?? '';
	$address['google_place_id'] = $row['place_id'] ?? '';
	$address['types'] = $row['types'] ?? [];
	if (!$address['street'] && ($row['vicinity'] ?? false)) {
		$parts = explode( ',', $row['vicinity'] );
		$address['street'] = trim($parts[0]);
		$address['city'] = trim($parts[1]);
	}
	return $address;
}
Copied!

Geo::toGps() 

\nn\t3::Geo()->toGps($coordinate, $hemisphere); 

GPS-Koordinaten in lesbare Latitude/Longitude-Koordinaten umrechnen

\nn\t3::Geo()->toGps( ['50/1', '4/1', '172932/3125'], 'W' );
Copied!

| @return array

Source Code 

public function toGps( $coordinate, $hemisphere )
{
	if (!$coordinate || !$hemisphere) return 0;
	for ($i = 0; $i < 3; $i++) {
		$part = explode('/', $coordinate[$i]);
		if (count($part) == 1) {
			$coordinate[$i] = $part[0];
		} else if (count($part) == 2) {
			$coordinate[$i] = floatval($part[0])/floatval($part[1]);
		} else {
			$coordinate[$i] = 0;
		}
	}
	list($degrees, $minutes, $seconds) = $coordinate;
	$sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1;
	return $sign * ($degrees + $minutes/60 + $seconds/3600);
}
Copied!

Http 

\nn\t3::Http() 

Einfache Weiterleitungen machen, URLs bauen

Overview of Methods 

\nn\t3::Http()->buildUri($pageUid, $vars = [], $absolute = false); 

URI bauen, funktioniert im Frontend und Backend-Context. Berücksichtigt realURL

\nn\t3::Http()->buildUri( 123 );
\nn\t3::Http()->buildUri( 123, ['test'=>1], true );
Copied!

| @return string

| ➜ Go to source code of Http::buildUri()

\nn\t3::Http()->followRedirect($url); 

Weiterleitungs-Ziel ermitteln

\nn\t3::Http()->followRedirect( 'https://www.99grad.de/some/redirect' );
Copied!
@param string $url
@return void

| ➜ Go to source code of Http::followRedirect()

\nn\t3::Http()->redirect($pidOrUrl = NULL, $vars = [], $varsPrefix = ''); 

Zu einer Seite weiterleiten

\nn\t3::Http()->redirect( 'https://www.99grad.de' );
\nn\t3::Http()->redirect( 10 );                                      // => path/to/pageId10
\nn\t3::Http()->redirect( 10, ['test'=>'123'] );                      // => path/to/pageId10&test=123
\nn\t3::Http()->redirect( 10, ['test'=>'123'], 'tx_myext_plugin' );
Copied!

| @return void

| ➜ Go to source code of Http::redirect()

Methods 

Http::buildUri() 

\nn\t3::Http()->buildUri($pageUid, $vars = [], $absolute = false); 

URI bauen, funktioniert im Frontend und Backend-Context. Berücksichtigt realURL

\nn\t3::Http()->buildUri( 123 );
\nn\t3::Http()->buildUri( 123, ['test'=>1], true );
Copied!

| @return string

Source Code 

public function buildUri ( $pageUid, $vars = [], $absolute = false )
{
	// Keine pid übergeben? Dann selbst ermitteln zu aktueller Seite
	if (!$pageUid) $pageUid = \nn\t3::Page()->getPid();
	// String statt pid übergeben? Dann Request per PHP bauen
	if (!is_numeric($pageUid)) {
		// relativer Pfad übergeben z.B. `/link/zu/seite`
		if (strpos($pageUid, 'http') === false) {
			$pageUid = \nn\t3::Environment()->getBaseURL() . ltrim( $pageUid, '/' );
		}
		$parsedUrl = parse_url($pageUid);
		parse_str($parsedUrl['query'] ?? '', $parsedParams);
		if (!$parsedParams) $parsedParams = [];
		ArrayUtility::mergeRecursiveWithOverrule( $parsedParams, $vars );
		$reqStr = $parsedParams ? http_build_query( $parsedParams ) : false;
		$path = $parsedUrl['path'] ?: '/';
		$port = $parsedUrl['port'] ?? false;
		if ($port) $port = ":{$port}";
		return "{$parsedUrl['scheme']}://{$parsedUrl['host']}{$port}{$path}" . ($reqStr ? '?'.$reqStr : '');
	}
	// Frontend initialisieren, falls nicht vorhanden
	if (!\nn\t3::Environment()->isFrontend()) {
		\nn\t3::Tsfe()->get();
	}
	$request = $GLOBALS['TYPO3_REQUEST'] ?? new \TYPO3\CMS\Core\Http\ServerRequest();
	$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
	$cObj->setRequest( $request );
	$uri = $cObj->typolink_URL([
		'parameter' => $pageUid,
		'linkAccessRestrictedPages' => 1,
		'additionalParams' => GeneralUtility::implodeArrayForUrl('', $vars),
	]);
	// setAbsoluteUri( TRUE ) geht nicht immer...
	if ($absolute) {
		$uri = GeneralUtility::locationHeaderUrl($uri);
	}
	return $uri;
}
Copied!

Http::followRedirect() 

\nn\t3::Http()->followRedirect($url); 

Weiterleitungs-Ziel ermitteln

\nn\t3::Http()->followRedirect( 'https://www.99grad.de/some/redirect' );
Copied!
@param string $url
@return void

Source Code 

public function followRedirect( string $url )
{
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_HEADER, true);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	$response = curl_exec($ch);
	$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
	curl_close($ch);
	return $url;
}
Copied!

Http::redirect() 

\nn\t3::Http()->redirect($pidOrUrl = NULL, $vars = [], $varsPrefix = ''); 

Zu einer Seite weiterleiten

\nn\t3::Http()->redirect( 'https://www.99grad.de' );
\nn\t3::Http()->redirect( 10 );                                      // => path/to/pageId10
\nn\t3::Http()->redirect( 10, ['test'=>'123'] );                      // => path/to/pageId10&test=123
\nn\t3::Http()->redirect( 10, ['test'=>'123'], 'tx_myext_plugin' );
Copied!

| @return void

Source Code 

public function redirect ( $pidOrUrl = null, $vars = [], $varsPrefix = '' ) {
	if (!$varsPrefix) unset($vars['id']);
	if ($varsPrefix) {
		$tmp = [$varsPrefix=>[]];
		foreach ($vars as $k=>$v) $tmp[$varsPrefix][$k] = $v;
		$vars = $tmp;
	}
	$link = $this->buildUri( $pidOrUrl, $vars, true );
	header('Location: '.$link);
	exit();
}
Copied!

LL 

\nn\t3::LL() 

Wrapper für Methoden rund um die Localization von Typo3

Overview of Methods 

\nn\t3::LL()->get($id = '', $extensionName = '', $args = [], $explode = '', $langKey = NULL, $altLangKey = NULL); 

Localization für einen bestimmten Key holen.

Verwendet die Übersetzungen, die im xlf einer Extension angegeben sind. Diese Dateien liegen standardmäßig unter EXT:extname/Resources/Private/Language/locallang.xlf bzw. EXT:extname/Resources/Private/Language/de.locallang.xlf für die jeweilige Übersetzung.

// Einfaches Beispiel:
\nn\t3::LL()->get(''LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:my.identifier');
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress');

// Argumente im String ersetzen: 'Nach der %s kommt die %s' oder `Vor der %2$s kommt die %1$s'
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', ['eins', 'zwei']);

// explode() des Ergebnisses an einem Trennzeichen
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, ',');

// In andere Sprache als aktuelle Frontend-Sprache übersetzen
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, null, 'en');
\nn\t3::LL()->get('LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:my.identifier', null, null, null, 'en');
Copied!
@param string $id
@param string $extensionName
@param array $args
@param string $explode
@param string $langKey
@param string $altLangKey
@return mixed

| ➜ Go to source code of LL::get()

\nn\t3::LL()->translate($srcText = '', $targetLanguageKey = 'EN', $sourceLanguageKey = 'DE', $apiKey = NULL); 

Übersetzt einen Text per DeepL. Ein API-Key muss im Extension Manager eingetragen werden. DeepL erlaubt die Übersetzung von bis zu 500.000 Zeichen / Monat kostenfrei.

\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 1 );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN', 'DE' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 1, 0 );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN', 'DE', $apiKey );
Copied!
@param string $srcText Text der übersetzt werden soll
@param string|int $targetLanguageKey Zielsprache (z.B. 'EN' oder '1')
@param string|int $sourceLanguageKey Quellsprache (z.B. 'DE' oder '0')
@param string $apiKey DeepL Api-Key (falls nicht im ExtensionManager definiert)
@return string

| ➜ Go to source code of LL::translate()

Methods 

LL::get() 

\nn\t3::LL()->get($id = '', $extensionName = '', $args = [], $explode = '', $langKey = NULL, $altLangKey = NULL); 

Localization für einen bestimmten Key holen.

Verwendet die Übersetzungen, die im xlf einer Extension angegeben sind. Diese Dateien liegen standardmäßig unter EXT:extname/Resources/Private/Language/locallang.xlf bzw. EXT:extname/Resources/Private/Language/de.locallang.xlf für die jeweilige Übersetzung.

// Einfaches Beispiel:
\nn\t3::LL()->get(''LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:my.identifier');
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress');

// Argumente im String ersetzen: 'Nach der %s kommt die %s' oder `Vor der %2$s kommt die %1$s'
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', ['eins', 'zwei']);

// explode() des Ergebnisses an einem Trennzeichen
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, ',');

// In andere Sprache als aktuelle Frontend-Sprache übersetzen
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, null, 'en');
\nn\t3::LL()->get('LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:my.identifier', null, null, null, 'en');
Copied!
@param string $id
@param string $extensionName
@param array $args
@param string $explode
@param string $langKey
@param string $altLangKey
@return mixed

Source Code 

public function get( $id = '',  $extensionName = '', $args = [], $explode = '', $langKey = null, $altLangKey = null ) {
	$value = LocalizationUtility::translate($id, $extensionName, $args, $langKey, $altLangKey);
	if (!$explode) return $value;
	return GeneralUtility::trimExplode(($explode === true ? ',' : $explode), $value);
}
Copied!

LL::translate() 

\nn\t3::LL()->translate($srcText = '', $targetLanguageKey = 'EN', $sourceLanguageKey = 'DE', $apiKey = NULL); 

Übersetzt einen Text per DeepL. Ein API-Key muss im Extension Manager eingetragen werden. DeepL erlaubt die Übersetzung von bis zu 500.000 Zeichen / Monat kostenfrei.

\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 1 );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN', 'DE' );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 1, 0 );
\nn\t3::LL()->translate( 'Das Pferd isst keinen Gurkensalat', 'EN', 'DE', $apiKey );
Copied!
@param string $srcText Text der übersetzt werden soll
@param string|int $targetLanguageKey Zielsprache (z.B. 'EN' oder '1')
@param string|int $sourceLanguageKey Quellsprache (z.B. 'DE' oder '0')
@param string $apiKey DeepL Api-Key (falls nicht im ExtensionManager definiert)
@return string

Source Code 

public function translate( $srcText = '', $targetLanguageKey = 'EN', $sourceLanguageKey = 'DE', $apiKey = null )
{
	$deeplConfig = \nn\t3::Environment()->getExtConf('nnhelpers');
	if (!$apiKey) {
		$apiKey = $deeplConfig['deeplApiKey'] ?? false;
	}
	if (!$this->sysLanguages) {
		$this->sysLanguages = \nn\t3::Environment()->getLanguages('languageId', 'iso-639-1');
	}
	// convert numeric language_uid to language string
	if (is_numeric($targetLanguageKey)) {
		$targetLanguageKey = $this->sysLanguages[$targetLanguageKey];
	}
	if (is_numeric($sourceLanguageKey)) {
		$sourceLanguageKey = $this->sysLanguages[$sourceLanguageKey];
	}
	if (!$apiKey || !$deeplConfig['deeplApiUrl']) {
		return 'Bitte API Key und URL für DeepL im Extension-Manager angeben';
	}
	$srcText = \nn\t3::Convert($srcText)->toUTF8();
	$params = [
		'text'			=> '<LL>' . $srcText . '</LL>',
		'source_lang'	=> strtoupper($sourceLanguageKey),
		'target_lang'	=> strtoupper($targetLanguageKey),
		'tag_handling'	=> 'xml',
	];
	$headers = [
		'Authorization' => 'DeepL-Auth-Key ' . $apiKey,
	];
	$result = \nn\t3::Request()->POST( $deeplConfig['deeplApiUrl'], $params, $headers );
	if ($result['status'] != 200) {
		die('[ERROR] Fehler bei POST-Query an ' . $deeplConfig['deeplApiUrl'] . ' [' . $result['status'] . '] ' . $result['content']);
		return "[ERROR] Fehler bei POST-Query an {$deeplConfig['deeplApiUrl']} [{$result['status']}, {$result['error']}]";
	}
	$json = json_decode( $result['content'], true ) ?: ['error' => 'JSON leer'];
	if (!$json || !isset($json['translations'][0]['text'])) {
		return "[ERROR] Fehler bei Übersetzung. Kein Text von DeepL zurückgegeben oder JSON konnte nicht geparsed werden.";
	}
	$text = $json['translations'][0]['text'] ?? '';
	$text = trim(str_replace(['<LL>', '</LL>'], '', $text));
	$text = str_replace( ">.\n", ">\n", $text);
	return $text;
}
Copied!

Log 

\nn\t3::Log() 

Log in die Tabelle sys_log

Overview of Methods 

\nn\t3::Log()->error($extName = '', $message = '', $data = []); 

Eine Warnung in die Tabelle sys_log schreiben. Kurzschreibweise für nnt3::Log()->log(..., 'error');

\nn\t3::Log()->error( 'extname', 'Text', ['die'=>'daten'] );
Copied!

return void

| ➜ Go to source code of Log::error()

\nn\t3::Log()->info($extName = '', $message = '', $data = []); 

Eine Info in die Tabelle sys_log schreiben. Kurzschreibweise für nnt3::Log()->log(..., 'info');

\nn\t3::Log()->error( 'extname', 'Text', ['die'=>'daten'] );
Copied!

return void

| ➜ Go to source code of Log::info()

\nn\t3::Log()->log($extName = 'nnhelpers', $message = NULL, $data = [], $severity = 'info'); 

Schreibt einen Eintrag in die Tabelle sys_log. Der severity-Level kann angegeben werden, z.B. info, warning oder error

\nn\t3::Log()->log( 'extname', 'Alles übel.', ['nix'=>'gut'], 'error' );
\nn\t3::Log()->log( 'extname', 'Alles schön.' );
Copied!

| @return mixed

| ➜ Go to source code of Log::log()

Methods 

Log::error() 

\nn\t3::Log()->error($extName = '', $message = '', $data = []); 

Eine Warnung in die Tabelle sys_log schreiben. Kurzschreibweise für nnt3::Log()->log(..., 'error');

\nn\t3::Log()->error( 'extname', 'Text', ['die'=>'daten'] );
Copied!

return void

Source Code 

public function error( $extName = '', $message = '', $data = []) {
	$this->log( $extName, $message, $data, 'error' );
}
Copied!

Log::info() 

\nn\t3::Log()->info($extName = '', $message = '', $data = []); 

Eine Info in die Tabelle sys_log schreiben. Kurzschreibweise für nnt3::Log()->log(..., 'info');

\nn\t3::Log()->error( 'extname', 'Text', ['die'=>'daten'] );
Copied!

return void

Source Code 

public function info( $extName = '', $message = '', $data = []) {
	$this->log( $extName, $message, $data, 'info' );
}
Copied!

Log::log() 

\nn\t3::Log()->log($extName = 'nnhelpers', $message = NULL, $data = [], $severity = 'info'); 

Schreibt einen Eintrag in die Tabelle sys_log. Der severity-Level kann angegeben werden, z.B. info, warning oder error

\nn\t3::Log()->log( 'extname', 'Alles übel.', ['nix'=>'gut'], 'error' );
\nn\t3::Log()->log( 'extname', 'Alles schön.' );
Copied!

| @return mixed

Source Code 

public function log( $extName = 'nnhelpers', $message = null, $data = [], $severity = 'info' ) {
	if (is_array($message)) $message = join(" · ", $message);
	$severity = strtoupper( $severity );
	$logLevel = constant( "\TYPO3\CMS\Core\Log\LogLevel::$severity" );
	$type = $severity == 'ERROR' ? 5 : 4;	// 4 = type: EXTENSION
	// Die Core-Methode ist schön, allerdings nur, wenn man wirklich diese Flexibiltät braucht.
	// Leider sind die Log-Einträge mit dem Core DatabaseWriter nicht im Backend sichtbar.
	// Wir wollen nur einen einfach Eintrag in sys_log haben und nutzen einen simplen INSERT
	/*
	$logger = GeneralUtility::makeInstance( LogManager::class )->getLogger( __CLASS__ );
	$logger->log( $logLevel, $message, $params );
	*/
	\nn\t3::Db()->insert('sys_log', [
		'details' 		=> "[{$extName}] {$message} " . ($data ? print_r( $data, true ) : ''),
		'action' 		=> $data['action'] ?? 0,
		'level'			=> $logLevel,
		'type'			=> $type,
		'log_data'		=> serialize($data),
		'error'			=> $severity == 'ERROR' ? 1 : 0,
		'tstamp'		=> time(),
		'IP'			=> $_SERVER['REMOTE_ADDR'] ?? '',
	]);
}
Copied!

Mail 

\nn\t3::Mail() 

Helferlein für den Mailversand

Overview of Methods 

\nn\t3::Mail()->send($paramOverrides = []); 

Eine E-Mail senden.

$html = \nn\t3::Template()->render('MailTemplate', ['varKey'=>'varValue'], 'tx_extname_plugin');

\nn\t3::Mail()->send([
    'html'            => $html,
    'plaintext'       => Optional: Text-Version
    'fromEmail'       => Absender-Email
    'fromName'        => Absender-Name
    'toEmail'     => Empfänger-Email(s)
    'ccToEmail'       => CC Empfänger-Email(s)
    'bccToEmail'  => BCC Empfänger-Email(s)
    'replyToEmail'    => Antwort an Empfänger-Email
    'replyToName' => Antwort an Name
    'subject'     => Betreff
    'attachments' => [...],
    'emogrify'        => CSS-Stile in Inline-Styles umwandeln (default: `true`)
    'absPrefix'       => Relative Pfade in absolute umwandeln (default: `true`)
    'headers'     => ['List-Unsubscribe' => '<mailto:unsubscribe@99grad.de>, <https://www.unsubscribe.com>'],
]);
Copied!

Bilder einbetten mit <img data-embed="1" src="..." /> Dateianhänge mit <a data-embed="1" href="..." /> | @return void

| ➜ Go to source code of Mail::send()

Methods 

Mail::send() 

\nn\t3::Mail()->send($paramOverrides = []); 

Eine E-Mail senden.

$html = \nn\t3::Template()->render('MailTemplate', ['varKey'=>'varValue'], 'tx_extname_plugin');

\nn\t3::Mail()->send([
    'html'            => $html,
    'plaintext'       => Optional: Text-Version
    'fromEmail'       => Absender-Email
    'fromName'        => Absender-Name
    'toEmail'     => Empfänger-Email(s)
    'ccToEmail'       => CC Empfänger-Email(s)
    'bccToEmail'  => BCC Empfänger-Email(s)
    'replyToEmail'    => Antwort an Empfänger-Email
    'replyToName' => Antwort an Name
    'subject'     => Betreff
    'attachments' => [...],
    'emogrify'        => CSS-Stile in Inline-Styles umwandeln (default: `true`)
    'absPrefix'       => Relative Pfade in absolute umwandeln (default: `true`)
    'headers'     => ['List-Unsubscribe' => '<mailto:unsubscribe@99grad.de>, <https://www.unsubscribe.com>'],
]);
Copied!

Bilder einbetten mit <img data-embed="1" src="..." /> Dateianhänge mit <a data-embed="1" href="..." /> | @return void

Source Code 

public function send ( $paramOverrides = [] ) {
	\nn\t3::autoload();
	// Defaults mergen mit Parametern
	$params = [
		'emogrify'	=> true,
		'absPrefix'	=> true,
	];
	ArrayUtility::mergeRecursiveWithOverrule( $params, $paramOverrides);
	$mail = GeneralUtility::makeInstance(MailMessage::class);
	$html = $params['html'] ?? '';
	$pathSite = \nn\t3::Environment()->getPathSite();
	$recipients = \nn\t3::Arrays($params['toEmail'] ?? '')->trimExplode();
	$fromEmail = array_shift(\nn\t3::Arrays($params['fromEmail'] ?? '')->trimExplode());
	if ($replyToEmail = $params['replyToEmail'] ?? false) {
		$mail->replyTo( new \Symfony\Component\Mime\Address($replyToEmail, $params['replyToName'] ?? '') );
	}
	if ($ccToEmail = $params['ccToEmail'] ?? false) {
		$ccToEmail = \nn\t3::Arrays($ccToEmail)->trimExplode();
		$mail->setCc( $ccToEmail );
	}
	if ($bccToEmail = $params['bccToEmail'] ?? false) {
		$bccToEmail = \nn\t3::Arrays($bccToEmail)->trimExplode();
		$mail->setBcc( $bccToEmail );
	}
	$mail->from( new \Symfony\Component\Mime\Address($fromEmail, $params['fromName'] ?? '') );
	$mail->to(...$recipients);
	$mail->subject($params['subject'] ?? '');
	// Inline-Media im HTML-Code finden (<img data-embed="1" src="..." />)
	$dom = new \DOMDocument();
	@$dom->loadHTML($html);
	// XPATH Cheat-Sheet: https://devhints.io/xpath
	$xpath = new \DOMXPath($dom);
	$nodes = $xpath->query('//*[@data-embed]');
	$attachedFiles = [];
	foreach ($nodes as $node) {
		if ($img = $node->getAttribute('src')) {
			$node->removeAttribute('data-embed');
			$cid = 'img-' . md5($pathSite . $img);
			$node->setAttribute('src', 'cid:'.$cid);
			$mail->embedFromPath( $pathSite . $img, $cid );
		}
		if ($file = $node->getAttribute('href')) {
			if (!isset($attachedFiles[$pathSite . $file])) {
				$absPath = \nn\t3::File()->absPath( $file );
				$mail->attachFromPath( $absPath );
				$attachedFiles[$absPath] = true;
			}
		}
	}
	// Zusätzlich Anhänge?
	$attachments = \nn\t3::Arrays($params['attachments'] ?? '')->trimExplode();
	foreach ($attachments as $path) {
		if (!isset($attachedFiles[$pathSite . $path])) {
			$absPath = \nn\t3::File()->absPath( $path );
			$mail->attachFromPath( $absPath );
			$attachedFiles[ $absPath ] = true;
		}
	}
	$html = $dom->saveHTML();
	// Relative Pfade im Quelltext mit absoluten Pfaden ersetzen
	if ($params['absPrefix'] ?? false) {
		$html = \nn\t3::Dom()->absPrefix( $html );
	}
	// CSS in Inline-Styles umwandeln
	if ($params['emogrify'] ?? false) {
		$html = CssInliner::fromHtml($html)->inlineCss()->render();
	}
	$plaintext = $params['plaintext'] ?? strip_tags($html);
	if ($html) {
		$mail->html($html);
		$mail->text($plaintext);
	} else {
		$mail->text($plaintext);
	}
	$returnPath = $params['returnPath_email'] ?? \TYPO3\CMS\Core\Utility\MailUtility::getSystemFromAddress();
	if (strpos($returnPath, 'no-reply') === false) {
		$mail->setReturnPath( $returnPath );
	}
	// zsätzliche Header?
	if ($headers = $params['headers'] ?? false) {
		$mailHeaders = $mail->getHeaders();
		foreach ($headers as $k=>$v) {
			$mailHeaders->addTextHeader($k, $v);
		}
	}
	$sent = $mail->send();
	if (!$sent) {
/*
		\nn\t3::Log()->error('nnhelpers', 'Mail not sent', $recipients);
		$fp = fopen('mail_error.log', 'a');
		$to = join(',', $recipients);
		fputs($fp, date('d.m.Y H:i:s')." {$to}\n\n\n");
		fclose($fp);
		$helpMail = $this->params['errorMail_email'];
		$mail->setReturnPath( $helpMail );
		$mail->setTo( $helpMail );
		$mail->setSubject('Mailversand: FEHLER!');
		$mail->send();
//*/
	}
	return $sent;
}
Copied!

Message 

\nn\t3::Message() 

Vereinfacht die Verwendung der FlashMessages.

Im Backend: FlashMessages werden automatisch ganz oben ausgegeben

\nn\t3::Message()->OK('Titel', 'Infotext');
\nn\t3::Message()->ERROR('Titel', 'Infotext');
Copied!

Im Frontend: FlashMessages können über ViewHelper ausgegeben werden

\nn\t3::Message()->OK('Titel', 'Infotext');
<nnt3:flashMessages />
<f:flashMessages queueIdentifier='core.template.flashMessages' />

\nn\t3::Message()->setId('oben')->OK('Titel', 'Infotext');
<nnt3:flashMessages id='oben' />
<f:flashMessages queueIdentifier='oben' />
Copied!

... oder als HTML gerendert und zurückgegeben werden:

echo \nn\t3::Message()->render('oben');
echo \nn\t3::Message()->render();
Copied!

Overview of Methods 

\nn\t3::Message()->ERROR($title = '', $text = ''); 

Gibt eine "ERROR" Flash-Message aus

\nn\t3::Message()->ERROR('Titel', 'Infotext');
Copied!

| @return void

| ➜ Go to source code of Message::ERROR()

\nn\t3::Message()->OK($title = '', $text = ''); 

Gibt eine "OK" Flash-Message aus

\nn\t3::Message()->OK('Titel', 'Infotext');
Copied!

| @return void

| ➜ Go to source code of Message::OK()

\nn\t3::Message()->WARNING($title = '', $text = ''); 

Gibt eine "WARNING" Flash-Message aus

\nn\t3::Message()->WARNING('Titel', 'Infotext');
Copied!

| @return void

| ➜ Go to source code of Message::WARNING()

\nn\t3::Message()->flash($title = '', $text = '', $type = 'OK', $queueID = NULL); 

Speichert eine Flash-Message in den Message-Queue für Frontend oder Backend. | @return void

| ➜ Go to source code of Message::flash()

\nn\t3::Message()->flush($queueID = NULL); 

Löscht alle Flash-Messages Optional kann eine Queue-ID angegeben werden.

\nn\t3::Message()->flush('oben');
\nn\t3::Message()->flush();
Copied!

| @return array

| ➜ Go to source code of Message::flush()

\nn\t3::Message()->render($queueID = NULL); 

Rendert die Flash-Messages in der Queue Simples Beispiel:

\nn\t3::Message()->OK('Ja', 'Nein');
echo \nn\t3::Message()->render();
Copied!

Beispiel mit einer Queue-ID:

\nn\t3::Message()->setId('oben')->OK('Ja', 'Nein');
echo \nn\t3::Message()->render('oben');
Copied!

Ausgabe im Fluid über den ViewHelper:

<nnt3:flashMessages id="oben" />
{nnt3:flashMessages()}
Copied!

| @return string

| ➜ Go to source code of Message::render()

\nn\t3::Message()->setId($name = NULL); 

Legt fest, welcher MessageQueue verwendet werden soll

\nn\t3::Message()->setId('oben')->OK('Titel', 'Infotext');
Copied!

Ausgabe in Fluid per ViewHelper:

<nnt3:flashMessages id="oben" />
{nnt3:flashMessages(id:'oben')}
Copied!

| @return void

| ➜ Go to source code of Message::setId()

Methods 

Message::ERROR() 

\nn\t3::Message()->ERROR($title = '', $text = ''); 

Gibt eine "ERROR" Flash-Message aus

\nn\t3::Message()->ERROR('Titel', 'Infotext');
Copied!

| @return void

Source Code 

public function ERROR( $title = '', $text = '' ) {
	$this->flash( $title, $text, 'ERROR' );
}
Copied!

Message::flash() 

\nn\t3::Message()->flash($title = '', $text = '', $type = 'OK', $queueID = NULL); 

Speichert eine Flash-Message in den Message-Queue für Frontend oder Backend. | @return void

Source Code 

public function flash( $title = '', $text = '', $type = 'OK', $queueID = null )
{
	$message = GeneralUtility::makeInstance(FlashMessage::class,
		$text,
		$title,
		constant("TYPO3\CMS\Core\Type\ContextualFeedbackSeverity::{$type}"),
		true
	);
	$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
	$queueID = $queueID ?: $this->queueId ?: 'core.template.flashMessages';
	$messageQueue = $flashMessageService->getMessageQueueByIdentifier( $queueID );
	$messageQueue->addMessage($message);
}
Copied!

Message::flush() 

\nn\t3::Message()->flush($queueID = NULL); 

Löscht alle Flash-Messages Optional kann eine Queue-ID angegeben werden.

\nn\t3::Message()->flush('oben');
\nn\t3::Message()->flush();
Copied!

| @return array

Source Code 

public function flush( $queueID = null ) {
	$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
	$queueID = $queueID ?: $this->queueId ?: 'core.template.flashMessages';
	$messageQueue = $flashMessageService->getMessageQueueByIdentifier( $queueID );
	return $messageQueue->getAllMessagesAndFlush() ?: [];
}
Copied!

Message::OK() 

\nn\t3::Message()->OK($title = '', $text = ''); 

Gibt eine "OK" Flash-Message aus

\nn\t3::Message()->OK('Titel', 'Infotext');
Copied!

| @return void

Source Code 

public function OK( $title = '', $text = '' ) {
	$this->flash( $title, $text );
}
Copied!

Message::render() 

\nn\t3::Message()->render($queueID = NULL); 

Rendert die Flash-Messages in der Queue Simples Beispiel:

\nn\t3::Message()->OK('Ja', 'Nein');
echo \nn\t3::Message()->render();
Copied!

Beispiel mit einer Queue-ID:

\nn\t3::Message()->setId('oben')->OK('Ja', 'Nein');
echo \nn\t3::Message()->render('oben');
Copied!

Ausgabe im Fluid über den ViewHelper:

<nnt3:flashMessages id="oben" />
{nnt3:flashMessages()}
Copied!

| @return string

Source Code 

public function render( $queueID = null ) {
	if (!($messages = $this->flush($queueID))) return '';
	$html = GeneralUtility::makeInstance(FlashMessageRendererResolver::class)->resolve()->render($messages);
	return $html;
}
Copied!

Message::setId() 

\nn\t3::Message()->setId($name = NULL); 

Legt fest, welcher MessageQueue verwendet werden soll

\nn\t3::Message()->setId('oben')->OK('Titel', 'Infotext');
Copied!

Ausgabe in Fluid per ViewHelper:

<nnt3:flashMessages id="oben" />
{nnt3:flashMessages(id:'oben')}
Copied!

| @return void

Source Code 

public function setId( $name = null ) {
	$this->queueId = $name;
	return $this;
}
Copied!

Message::WARNING() 

\nn\t3::Message()->WARNING($title = '', $text = ''); 

Gibt eine "WARNING" Flash-Message aus

\nn\t3::Message()->WARNING('Titel', 'Infotext');
Copied!

| @return void

Source Code 

public function WARNING( $title = '', $text = '' ) {
	$this->flash( $title, $text, 'WARNING' );
}
Copied!

Obj 

\nn\t3::Obj() 

Alles, was man für Objects und Models braucht.

Overview of Methods 

\nn\t3::Obj()->accessSingleProperty($obj, $key); 

Zugriff auf einen Key in einem Object oder Array key muss einzelner String sein, kein Pfad

nnt3::Obj()->accessSingleProperty( $obj, 'uid' ); nnt3::Obj()->accessSingleProperty( $obj, 'fal_media' ); nnt3::Obj()->accessSingleProperty( $obj, 'falMedia' );

@param mixed $obj Model oder Array
@param string $key der Key, der geholt werden soll

| @return mixed

| ➜ Go to source code of Obj::accessSingleProperty()

\nn\t3::Obj()->diff($objA, $objB, $fieldsToIgnore = [], $fieldsToCompare = [], $options = [], $path = '', $diff = []); 

Vergleicht zwei Objekte, gibt Array mit Unterschieden zurück. Existiert eine Property von objA nicht in objB, wird diese ignoriert.

// gibt Array mit Unterschieden zurück
\nn\t3::Obj()->diff( $objA, $objB );

// ignoriert die Felder uid und title
\nn\t3::Obj()->diff( $objA, $objB, ['uid', 'title'] );

// Vergleicht NUR die Felder title und bodytext
\nn\t3::Obj()->diff( $objA, $objB, [], ['title', 'bodytext'] );

// Optionen
\nn\t3::Obj()->diff( $objA, $objB, [], [], ['ignoreWhitespaces'=>true, 'ignoreTags'=>true, 'ignoreEncoding'=>true] );
Copied!
@param mixed $objA Ein Object, Array oder Model
@param mixed $objB Das zu vergleichende Object oder Model
@param array $fieldsToIgnore Liste der Properties, die ignoriert werden können. Leer = keine
@param array $fieldsToCompare Liste der Properties, die verglichen werden sollen. Leer = alle
@param boolean $options Optionen / Toleranzen beim Vergleichen
includeMissing => auch fehlende Properties in $objB hinzufügen
ignoreWhitespaces => Leerzeichen ignorieren
ignoreEncoding => UTF8 / ISO-Encoding ignorieren
ignoreTags => HTML-Tags ignorieren
depth => Tiefe, die verglichen werden soll

| @return array

| ➜ Go to source code of Obj::diff()

\nn\t3::Obj()->forceArray($obj); 

Konvertiert zu Array

| @param mixed $obj

| @return array

| ➜ Go to source code of Obj::forceArray()

\nn\t3::Obj()->get($obj, $key = ''); 

Zugriff auf einen Wert in dem Object anhand des Keys Alias zu \nn\t3::Obj()->accessSingleProperty()

\nn\t3::Obj()->get( $obj, 'title' );
\nn\t3::Obj()->get( $obj, 'falMedia' );
\nn\t3::Obj()->get( $obj, 'fal_media' );
Copied!
@param mixed $obj Model oder Array
@param string $key der Key / Property

| @return mixed

| ➜ Go to source code of Obj::get()

\nn\t3::Obj()->getClassSchema($modelClassName = NULL); 

Infos zum classSchema eines Models holen

\nn\t3::Obj()->getClassSchema( \My\Model\Name::class );
\nn\t3::Obj()->getClassSchema( $myModel );
Copied!

return DataMap

| ➜ Go to source code of Obj::getClassSchema()

\nn\t3::Obj()->getKeys($obj); 

Zugriff auf ALLE Keys, die in einem Object zu holen sind

\nn\t3::Obj()->getKeys( $model );                                    // ['uid', 'title', 'text', ...]
\nn\t3::Obj()->getKeys( $model );                                    // ['uid', 'title', 'text', ...]
\nn\t3::Obj()->getKeys( \Nng\MyExt\Domain\Model\Demo::class );       // ['uid', 'title', 'text', ...]
Copied!
@param mixed $obj Model, Array oder Klassen-Name
@return array

| ➜ Go to source code of Obj::getKeys()

\nn\t3::Obj()->getMethodArguments($className = NULL, $methodName = NULL); 

Infos zu den Argumenten einer Methode holen. | Berücksichtigt auch das per@paramangegebene Typehinting, z.B. zuObjectStorage<ModelName>.

\nn\t3::Obj()->getMethodArguments( \My\Model\Name::class, 'myMethodName' );
\nn\t3::Obj()->getMethodArguments( $myClassInstance, 'myMethodName' );
Copied!

Gibt als Beispiel zurück:

'varName' => [
    'type' => 'Storage<Model>',
    'storageType' => 'Storage',
    'elementType' => 'Model',
 'optional' => true,
 'defaultValue' => '123'
]
Copied!

return array

| ➜ Go to source code of Obj::getMethodArguments()

\nn\t3::Obj()->getProps($obj, $key = 'type', $onlySettable = true); 

Liste der Properties eines Objects oder Models mit Typ zurückgeben.

\nn\t3::Obj()->getProps( $obj );         // ['uid'=>'integer', 'title'=>'string' ...]
\nn\t3::Obj()->getProps( $obj, true );       // ['uid'=>[type=>'integer', 'private'=>TRUE]]
\nn\t3::Obj()->getProps( $obj, 'default' );    // ['uid'=>TRUE]
\nn\t3::Obj()->getProps( \Nng\MyExt\Domain\Model\Demo::class );
Copied!
@param mixed $obj Model oder Klassen-Name
@param mixed $key Wenn TRUE wird Array mit allen Infos geholt, z.B. auch default-Wert etc.
@param boolean $onlySettable Nur properties holen, die auch per setName() gesetzt werden können
@return array

| ➜ Go to source code of Obj::getProps()

\nn\t3::Obj()->getSetableKeys($obj); 

Alle keys eines Objektes holen, die einen SETTER haben. Im Gegensatz zu \nn\t3::Obj()->getKeys() werden nur die Property-Keys zurückgegeben, die sich auch setzen lassen, z.B. über setNameDerProp()

| @return array

| ➜ Go to source code of Obj::getSetableKeys()

\nn\t3::Obj()->getTableName($modelClassName = NULL); 

Gibt den DB-Tabellen-Namen für ein Model zurück

$model = new \Nng\MyExt\Domain\Model\Test;
\nn\t3::Obj()->getTableName( $model );   // 'tx_myext_domain_model_test'
\nn\t3::Obj()->getTableName( Test::class );  // 'tx_myext_domain_model_test'
Copied!

| @return string

| ➜ Go to source code of Obj::getTableName()

\nn\t3::Obj()->isFalFile($obj); 

Prüft, ob es sich bei dem Object um eine \TYPO3\CMS\Core\Resource\FileReference handelt.

\nn\t3::Obj()->isFalFile( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFalFile()

\nn\t3::Obj()->isFile($obj); 

Prüft, ob es sich bei dem Object um ein \TYPO3\CMS\Core\Resource\File handelt.

\nn\t3::Obj()->isFile( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFile()

\nn\t3::Obj()->isFileReference($obj); 

Prüft, ob es sich bei dem Object um eine \TYPO3\CMS\Extbase\Domain\Model\FileReference handelt.

\nn\t3::Obj()->isFileReference( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFileReference()

\nn\t3::Obj()->isModel($obj); 

Prüft, ob es sich bei dem Object um ein Domain-Model handelt.

\nn\t3::Obj()->isModel( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isModel()

\nn\t3::Obj()->isSimpleType($type = ''); 

Prüft, ob es sich bei einem Typ (string) um einen "einfachen" Typ handelt. Einfache Typen sind alle Typen außer Models, Klassen etc. - also z.B. array, string, boolean etc.

$isSimple = \nn\t3::Obj()->isSimpleType( 'string' );                           // true
$isSimple = \nn\t3::Obj()->isSimpleType( \My\Extname\ClassName::class );     // false
Copied!

| @return boolean

| ➜ Go to source code of Obj::isSimpleType()

\nn\t3::Obj()->isStorage($obj); 

Prüft, ob es sich bei dem Object um eine Storage handelt.

\nn\t3::Obj()->isStorage( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isStorage()

\nn\t3::Obj()->isSysCategory($obj); 

Prüft, ob es sich bei dem Object um eine SysCategory handelt. Berücksichtigt alle Modelle, die in sys_category gespeichert werden.

\nn\t3::Obj()->isSysCategory( $obj );

$cat = new \GeorgRinger\News\Domain\Model\Category();
\nn\t3::Obj()->isSysCategory( $cat );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isSysCategory()

\nn\t3::Obj()->merge($model = NULL, $overlay = NULL); 

Merge eines Arrays in ein Object

\nn\t3::Obj( \My\Doman\Model )->merge(['title'=>'Neuer Titel']);
Copied!

Damit können sogar FileReferences geschrieben / überschrieben werden. In diesem Beispiel wird $data mit einem existierende Model gemerged. | falMedia ist im Beispiel eine ObjectStorage. Das erste Element in falMedia exisitert bereits in der Datenbank (uid = 12). Hier wird nur der Titel aktualisiert. Das zweite Element im Array (ohne uid) ist neu. Dafür wird automatisch eine neue | sys_file_reference in der Datenbank erzeugt.

$data = [
    'uid' => 10,
    'title' => 'Der Titel',
    'falMedia' => [
        ['uid'=>12, 'title'=>'1. Bildtitel'],
        ['title'=>'NEU Bildtitel', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
    ]
];
$oldModel = $repository->findByUid( $data['uid'] );
$mergedModel = \nn\t3::Obj($oldModel)->merge($data);
Copied!

Hinweis Um ein neues Model mit Daten aus einem Array zu erzeugen gibt es die Methode $newModel = \nn\t3::Convert($data)->toModel( \My\Model\Name::class );

| @return Object

| ➜ Go to source code of Obj::merge()

\nn\t3::Obj()->parseType($paramType = ''); 

Einen String mit Infos zu ObjectStorage<Model> parsen.

\nn\t3::Obj()->parseType( 'string' );
\nn\t3::Obj()->parseType( 'Nng\Nnrestapi\Domain\Model\ApiTest' );
\nn\t3::Obj()->parseType( '\TYPO3\CMS\Extbase\Persistence\ObjectStorage<Nng\Nnrestapi\Domain\Model\ApiTest>' );
Copied!

Git ein Array mit Infos zurück: | type ist dabei nur gesetzt, falls es ein Array oder eine ObjectStorage ist. | elementType ist immer der Typ des Models oder das TypeHinting der Variable

[
    'elementType' => 'Nng\Nnrestapi\Domain\Model\ApiTest',
    'type' => 'TYPO3\CMS\Extbase\Persistence\ObjectStorage',
    'simple' => FALSE
]
Copied!

| @return array

| ➜ Go to source code of Obj::parseType()

\nn\t3::Obj()->prop($obj, $key); 

Zugriff auf einen Key in einem Object oder Array. Der Key kann auch ein Pfad sein, z.B. "img.0.uid"

nnt3::Obj()->prop( $obj, 'img.0.uid' );

@param mixed $obj Model oder Array
@param string $key der Key, der geholt werden soll

| @return mixed

| ➜ Go to source code of Obj::prop()

\nn\t3::Obj()->props($obj, $keys = []); 

Einzelne Properties eines Objects oder Arrays holen

\nn\t3::Obj()->props( $obj, ['uid', 'pid'] );
\nn\t3::Obj()->props( $obj, 'uid' );
Copied!

| @return array

| ➜ Go to source code of Obj::props()

\nn\t3::Obj()->set($obj, $key = '', $val = '', $useSetter = true); 

Setzt einen Wert in einem Object oder Array.

\nn\t3::Obj()->set( $obj, 'title', $val );
Copied!
@param mixed $obj Model oder Array
@param string $key der Key / Property
@param mixed $val der Wert, der gesetzt werden soll
@param boolean $useSetter setKey()-Methode zum Setzen verwenden

| @return mixed

| ➜ Go to source code of Obj::set()

\nn\t3::Obj()->toArray($obj, $depth = 3, $fields = [], $addClass = false); 

Konvertiert ein Object in ein Array Bei Memory-Problemen wegen Rekursionen: Max-Tiefe angebenen!

\nn\t3::Obj()->toArray($obj, 2, ['uid', 'title']);
\nn\t3::Obj()->toArray($obj, 1, ['uid', 'title', 'parent.uid']);
Copied!
@param mixed $obj ObjectStorage, Model oder Array das Konvertiert werden soll
@param integer $depth Tiefe, die konvertiert werden soll. Bei rekursivem Konvertieren unbedingt nutzen
@param array $fields nur diese Felder aus dem Object / Array zurückgeben
@param boolean $addClass '__class' mit Infos zur Klasse ergänzen?

| @return array

| ➜ Go to source code of Obj::toArray()

Methods 

Obj::accessSingleProperty() 

\nn\t3::Obj()->accessSingleProperty($obj, $key); 

Zugriff auf einen Key in einem Object oder Array key muss einzelner String sein, kein Pfad

nnt3::Obj()->accessSingleProperty( $obj, 'uid' ); nnt3::Obj()->accessSingleProperty( $obj, 'fal_media' ); nnt3::Obj()->accessSingleProperty( $obj, 'falMedia' );

@param mixed $obj Model oder Array
@param string $key der Key, der geholt werden soll

| @return mixed

Source Code 

public function accessSingleProperty ( $obj, $key )
{
	if ($key == '') return '';
	if (is_object($obj)) {
		if (is_numeric($key)) {
			$obj = $this->forceArray($obj);
			return $obj[intval($key)];
		}
		$gettable = ObjectAccess::isPropertyGettable($obj, $key);
		if ($gettable) return ObjectAccess::getProperty($obj, $key);
		$camelCaseKey = GeneralUtility::underscoredToLowerCamelCase( $key );
		$gettable = ObjectAccess::isPropertyGettable($obj, $camelCaseKey);
		if ($gettable) return ObjectAccess::getProperty($obj, $camelCaseKey);
			if ($key == 'elementType' && $obj instanceof Property) {
				$valueTypes = $obj->getPrimaryType()->getCollectionValueTypes();
				if (!empty($valueTypes)) {
					return $valueTypes[0]->getClassName();
				}
			}
			if ($obj instanceof Property) {
				return $obj->getPrimaryType()->getClassName() ?? $obj->getPrimaryType()->getBuiltinType() ?? null;
			}
		return $obj->$key ?? null;
	} else {
		if (is_array($obj)) return $obj[$key] ?? null;
	}
	return [];
}
Copied!

Obj::diff() 

\nn\t3::Obj()->diff($objA, $objB, $fieldsToIgnore = [], $fieldsToCompare = [], $options = [], $path = '', $diff = []); 

Vergleicht zwei Objekte, gibt Array mit Unterschieden zurück. Existiert eine Property von objA nicht in objB, wird diese ignoriert.

// gibt Array mit Unterschieden zurück
\nn\t3::Obj()->diff( $objA, $objB );

// ignoriert die Felder uid und title
\nn\t3::Obj()->diff( $objA, $objB, ['uid', 'title'] );

// Vergleicht NUR die Felder title und bodytext
\nn\t3::Obj()->diff( $objA, $objB, [], ['title', 'bodytext'] );

// Optionen
\nn\t3::Obj()->diff( $objA, $objB, [], [], ['ignoreWhitespaces'=>true, 'ignoreTags'=>true, 'ignoreEncoding'=>true] );
Copied!
@param mixed $objA Ein Object, Array oder Model
@param mixed $objB Das zu vergleichende Object oder Model
@param array $fieldsToIgnore Liste der Properties, die ignoriert werden können. Leer = keine
@param array $fieldsToCompare Liste der Properties, die verglichen werden sollen. Leer = alle
@param boolean $options Optionen / Toleranzen beim Vergleichen
includeMissing => auch fehlende Properties in $objB hinzufügen
ignoreWhitespaces => Leerzeichen ignorieren
ignoreEncoding => UTF8 / ISO-Encoding ignorieren
ignoreTags => HTML-Tags ignorieren
depth => Tiefe, die verglichen werden soll

| @return array

Source Code 

public function diff( $objA, $objB, $fieldsToIgnore = [], $fieldsToCompare = [], $options = [], $path = '', &$diff = [] )
{
	$arrA = $this->toArray( $objA, $options['depth'] ?? 3 );
	$arrB = $this->toArray( $objB, $options['depth'] ?? 3 );
	$includeMissing = $options['includeMissing'] ?? false;
	// Keine Felder zum Vergleich angegeben? Dann alle nehmen
	if (!$fieldsToCompare) {
		$fieldsToCompare = array_keys( $arrA );
	}
	// Felder, die ignoriert werden sollen abziehen.
	$fieldsToCheck = array_diff( $fieldsToCompare, $fieldsToIgnore );
	foreach ($fieldsToCheck as $k=>$fieldName) {
		$deep = $path . ($path === '' ? '' : '.') . "{$fieldName}";
		$hasDiff = false;
		$valA = $arrA[$fieldName];
		$valB = $arrB[$fieldName] ?? null;
		// Property existiert nur in objA? Dann ignorieren
		if (!$includeMissing && !isset($arrB[$fieldName])) continue;
		if (is_array($valA)) {
			$this->diff($valA, $valB, [], [], $options, $deep, $diff);
		} else {
			// Einfacher String-Vergleich
			$cmpA = $valA;
			$cmpB = $valB;
			if (is_string($cmpA) && is_string($cmpB)) {
				if ($options['ignoreWhitespaces'] ?? false) {
					$cmpA = preg_replace('/[\s\t]/', '', $cmpA);
					$cmpB = preg_replace('/[\s\t]/', '', $cmpB);
				}
				if ($options['ignoreTags'] ?? false) {
					$cmpA = strip_tags($cmpA);
					$cmpB = strip_tags($cmpB);
				}
				if ($options['ignoreEncoding'] ?? false) {
					$cmpA = \nn\t3::Convert($cmpA)->toUTF8();
					$cmpB = \nn\t3::Convert($cmpB)->toUTF8();
				}
			}
			$hasDiff = $cmpA != $cmpB;
		}
		// Gab es einen Unterschied? Dann diff-Array befüllen
		if ($hasDiff) {
			$diff[$deep] = [
				'from'	=> $valA,
				'to'	=> $valB,
			];
		}
	}
	return $diff;
}
Copied!

Obj::forceArray() 

\nn\t3::Obj()->forceArray($obj); 

Konvertiert zu Array

| @param mixed $obj

| @return array

Source Code 

public function forceArray($obj)
{
	if (!$obj) return [];
	if ($this->isStorage($obj)) {
		$tmp = [];
		foreach ($obj as $k=>$v) {
			$tmp[] = $v;
		}
		return $tmp;
	}
	return is_array($obj) ? $obj : [$obj];
}
Copied!

Obj::get() 

\nn\t3::Obj()->get($obj, $key = ''); 

Zugriff auf einen Wert in dem Object anhand des Keys Alias zu \nn\t3::Obj()->accessSingleProperty()

\nn\t3::Obj()->get( $obj, 'title' );
\nn\t3::Obj()->get( $obj, 'falMedia' );
\nn\t3::Obj()->get( $obj, 'fal_media' );
Copied!
@param mixed $obj Model oder Array
@param string $key der Key / Property

| @return mixed

Source Code 

public function get( $obj, $key = '' )
{
	return $this->accessSingleProperty($obj, $key);
}
Copied!

Obj::getClassSchema() 

\nn\t3::Obj()->getClassSchema($modelClassName = NULL); 

Infos zum classSchema eines Models holen

\nn\t3::Obj()->getClassSchema( \My\Model\Name::class );
\nn\t3::Obj()->getClassSchema( $myModel );
Copied!

return DataMap

Source Code 

public function getClassSchema( $modelClassName = null )
{
	if (is_object($modelClassName)) {
		$modelClassName = get_class( $modelClassName );
	}
	if ($cache = \nn\t3::Cache()->get($modelClassName, true)) {
		return $cache;
	}
	$reflectionService = GeneralUtility::makeInstance( ReflectionService::class);
	$schema = $reflectionService->getClassSchema($modelClassName);
	return \nn\t3::Cache()->set( $modelClassName, $schema, true );
}
Copied!

Obj::getKeys() 

\nn\t3::Obj()->getKeys($obj); 

Zugriff auf ALLE Keys, die in einem Object zu holen sind

\nn\t3::Obj()->getKeys( $model );                                    // ['uid', 'title', 'text', ...]
\nn\t3::Obj()->getKeys( $model );                                    // ['uid', 'title', 'text', ...]
\nn\t3::Obj()->getKeys( \Nng\MyExt\Domain\Model\Demo::class );       // ['uid', 'title', 'text', ...]
Copied!
@param mixed $obj Model, Array oder Klassen-Name
@return array

Source Code 

public function getKeys ( $obj )
{
	if (is_string($obj) && class_exists($obj)) {
		$obj = new $obj();
	}
	$keys = [];
	if (is_object($obj)) {
		return ObjectAccess::getGettablePropertyNames($obj);
	} else if (is_array($obj)) {
		return array_keys($obj);
	}
	return [];
}
Copied!

Obj::getMethodArguments() 

\nn\t3::Obj()->getMethodArguments($className = NULL, $methodName = NULL); 

Infos zu den Argumenten einer Methode holen. | Berücksichtigt auch das per@paramangegebene Typehinting, z.B. zuObjectStorage<ModelName>.

\nn\t3::Obj()->getMethodArguments( \My\Model\Name::class, 'myMethodName' );
\nn\t3::Obj()->getMethodArguments( $myClassInstance, 'myMethodName' );
Copied!

Gibt als Beispiel zurück:

'varName' => [
    'type' => 'Storage<Model>',
    'storageType' => 'Storage',
    'elementType' => 'Model',
 'optional' => true,
 'defaultValue' => '123'
]
Copied!

return array

Source Code 

public function getMethodArguments( $className = null, $methodName = null )
{
	$result = [];
	$method = $this->getClassSchema( $className )->getMethod( $methodName );
	$parameters = $method->getParameters();
	if (!$parameters) return [];
	foreach ($parameters as $param) {
		$paramType = $param->getType();
		$typeInfo = $this->parseType( $paramType );
		$result[$param->getName()] = [
			'type' 			=> $paramType,
			'simple' 		=> $typeInfo['simple'],
			'storageType' 	=> $typeInfo['type'],
			'elementType' 	=> $typeInfo['elementType'],
			'optional' 		=> $param->isOptional(),
			'defaultValue'	=> $param->getDefaultValue()
		];
	}
	return $result;
}
Copied!

Obj::getProps() 

\nn\t3::Obj()->getProps($obj, $key = 'type', $onlySettable = true); 

Liste der Properties eines Objects oder Models mit Typ zurückgeben.

\nn\t3::Obj()->getProps( $obj );         // ['uid'=>'integer', 'title'=>'string' ...]
\nn\t3::Obj()->getProps( $obj, true );       // ['uid'=>[type=>'integer', 'private'=>TRUE]]
\nn\t3::Obj()->getProps( $obj, 'default' );    // ['uid'=>TRUE]
\nn\t3::Obj()->getProps( \Nng\MyExt\Domain\Model\Demo::class );
Copied!
@param mixed $obj Model oder Klassen-Name
@param mixed $key Wenn TRUE wird Array mit allen Infos geholt, z.B. auch default-Wert etc.
@param boolean $onlySettable Nur properties holen, die auch per setName() gesetzt werden können
@return array

Source Code 

public function getProps ( $obj, $key = 'type', $onlySettable = true )
{
	if (is_string($obj) && class_exists($obj)) {
		$obj = new $obj();
	}
	$schema = $this->getClassSchema( $obj );
	$properties = $schema->getProperties();
	if ($onlySettable) {
		$settables = array_flip(ObjectAccess::getSettablePropertyNames($obj));
		foreach ($properties as $k=>$p) {
			if (isset($settables[$k]) && !$settables[$k]) unset( $properties[$k] );
		}
	}
	$flatProps = [];
	foreach ($properties as $name=>$property) {
		$flatProps[$name] = $this->accessSingleProperty( $property, $key );
	}
	return $flatProps;
}
Copied!

Obj::getSetableKeys() 

\nn\t3::Obj()->getSetableKeys($obj); 

Alle keys eines Objektes holen, die einen SETTER haben. Im Gegensatz zu \nn\t3::Obj()->getKeys() werden nur die Property-Keys zurückgegeben, die sich auch setzen lassen, z.B. über setNameDerProp()

| @return array

Source Code 

public function getSetableKeys( $obj )
{
	$props = $this->getProps( $obj, null, true );
	return array_keys( $props );
}
Copied!

Obj::getTableName() 

\nn\t3::Obj()->getTableName($modelClassName = NULL); 

Gibt den DB-Tabellen-Namen für ein Model zurück

$model = new \Nng\MyExt\Domain\Model\Test;
\nn\t3::Obj()->getTableName( $model );   // 'tx_myext_domain_model_test'
\nn\t3::Obj()->getTableName( Test::class );  // 'tx_myext_domain_model_test'
Copied!

| @return string

Source Code 

public function getTableName ( $modelClassName = null )
{
	if (is_object($modelClassName)) {
		$modelClassName = get_class( $modelClassName );
	}
	$tableName = '';
	$dataMapper = GeneralUtility::makeInstance( DataMapper::class );
	try {
		$tableName = $dataMapper->getDataMap($modelClassName)->getTableName();
	} catch ( \Exception $e ) {
	} catch ( \Error $e ) {
		// silent
	}
	return $tableName;
}
Copied!

Obj::isFalFile() 

\nn\t3::Obj()->isFalFile($obj); 

Prüft, ob es sich bei dem Object um eine \TYPO3\CMS\Core\Resource\FileReference handelt.

\nn\t3::Obj()->isFalFile( $obj );
Copied!

| @return boolean

Source Code 

public function isFalFile ( $obj )
{
	if (!is_object($obj)) return false;
	if (is_a($obj, \TYPO3\CMS\Core\Resource\FileReference::class)) return true;
	return false;
}
Copied!

Obj::isFile() 

\nn\t3::Obj()->isFile($obj); 

Prüft, ob es sich bei dem Object um ein \TYPO3\CMS\Core\Resource\File handelt.

\nn\t3::Obj()->isFile( $obj );
Copied!

| @return boolean

Source Code 

public function isFile ( $obj )
{
	if (!is_object($obj)) return false;
	if (is_a($obj, \TYPO3\CMS\Core\Resource\File::class)) return true;
	return false;
}
Copied!

Obj::isFileReference() 

\nn\t3::Obj()->isFileReference($obj); 

Prüft, ob es sich bei dem Object um eine \TYPO3\CMS\Extbase\Domain\Model\FileReference handelt.

\nn\t3::Obj()->isFileReference( $obj );
Copied!

| @return boolean

Source Code 

public function isFileReference ( $obj )
{
	if (!is_object($obj)) return false;
	if (is_a($obj, \TYPO3\CMS\Extbase\Domain\Model\FileReference::class)) return true;
	$tableName = \nn\t3::Obj()->getTableName($obj);
	return $tableName == 'sys_file_reference';
}
Copied!

Obj::isModel() 

\nn\t3::Obj()->isModel($obj); 

Prüft, ob es sich bei dem Object um ein Domain-Model handelt.

\nn\t3::Obj()->isModel( $obj );
Copied!

| @return boolean

Source Code 

public function isModel ( $obj )
{
	if (!is_object($obj) || is_string($obj)) return false;
	return is_a($obj, \TYPO3\CMS\Extbase\DomainObject\AbstractEntity::class);
}
Copied!

Obj::isSimpleType() 

\nn\t3::Obj()->isSimpleType($type = ''); 

Prüft, ob es sich bei einem Typ (string) um einen "einfachen" Typ handelt. Einfache Typen sind alle Typen außer Models, Klassen etc. - also z.B. array, string, boolean etc.

$isSimple = \nn\t3::Obj()->isSimpleType( 'string' );                           // true
$isSimple = \nn\t3::Obj()->isSimpleType( \My\Extname\ClassName::class );     // false
Copied!

| @return boolean

Source Code 

public function isSimpleType( $type = '' )
{
	return in_array($type, ['array', 'string', 'float', 'double', 'integer', 'int', 'boolean', 'bool']);
}
Copied!

Obj::isStorage() 

\nn\t3::Obj()->isStorage($obj); 

Prüft, ob es sich bei dem Object um eine Storage handelt.

\nn\t3::Obj()->isStorage( $obj );
Copied!

| @return boolean

Source Code 

public function isStorage ( $obj )
{
	if (!is_object($obj) || is_string($obj)) return false;
	$type = get_class($obj);
	return is_a($obj, ObjectStorage::class) || $type == LazyObjectStorage::class || $type == ObjectStorage::class || $type == \TYPO3\CMS\Extbase\Persistence\ObjectStorage::class;
}
Copied!

Obj::isSysCategory() 

\nn\t3::Obj()->isSysCategory($obj); 

Prüft, ob es sich bei dem Object um eine SysCategory handelt. Berücksichtigt alle Modelle, die in sys_category gespeichert werden.

\nn\t3::Obj()->isSysCategory( $obj );

$cat = new \GeorgRinger\News\Domain\Model\Category();
\nn\t3::Obj()->isSysCategory( $cat );
Copied!

| @return boolean

Source Code 

public function isSysCategory ( $obj )
{
	if (!is_object($obj)) return false;
	if (is_a($obj, \TYPO3\CMS\Extbase\Domain\Model\Category::class)) return true;
	$tableName = \nn\t3::Obj()->getTableName($obj);
	return $tableName == 'sys_category';
}
Copied!

Obj::merge() 

\nn\t3::Obj()->merge($model = NULL, $overlay = NULL); 

Merge eines Arrays in ein Object

\nn\t3::Obj( \My\Doman\Model )->merge(['title'=>'Neuer Titel']);
Copied!

Damit können sogar FileReferences geschrieben / überschrieben werden. In diesem Beispiel wird $data mit einem existierende Model gemerged. | falMedia ist im Beispiel eine ObjectStorage. Das erste Element in falMedia exisitert bereits in der Datenbank (uid = 12). Hier wird nur der Titel aktualisiert. Das zweite Element im Array (ohne uid) ist neu. Dafür wird automatisch eine neue | sys_file_reference in der Datenbank erzeugt.

$data = [
    'uid' => 10,
    'title' => 'Der Titel',
    'falMedia' => [
        ['uid'=>12, 'title'=>'1. Bildtitel'],
        ['title'=>'NEU Bildtitel', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
    ]
];
$oldModel = $repository->findByUid( $data['uid'] );
$mergedModel = \nn\t3::Obj($oldModel)->merge($data);
Copied!

Hinweis Um ein neues Model mit Daten aus einem Array zu erzeugen gibt es die Methode $newModel = \nn\t3::Convert($data)->toModel( \My\Model\Name::class );

| @return Object

Source Code 

public function merge( $model = null, $overlay = null )
{
	$overlay = $this->initialArgument !== null ? $model : $overlay;
	$model = $this->initialArgument !== null ? $this->initialArgument : $model;
	$schema = \nn\t3::Obj()->getClassSchema($model);
	$modelProperties = $schema->getProperties();
	if (!is_array($overlay)) return $model;
	foreach ($overlay as $propName=>$value) {
		if ($propInfo = $modelProperties[$propName] ?? false) {
			// Typ für Property des Models, z.B. `string`
			$propType = $this->get( $propInfo, 'type');
			$isSysFile = is_a( $propType, \TYPO3\CMS\Core\Resource\File::class, true );
			if ($this->isSimpleType($propType)) {
				// -----
				// Es ist ein "einfacher Typ" (`string`, `int` etc.). Kann direkt gesetzt werden!
				$this->set( $model, $propName, $value );
				continue;
			}
			if (!class_exists($propType)) {
				\nn\t3::Exception( "Class of type `{$propType}` is not defined." );
			}
			$curPropValue = $this->get( $model, $propName );
			if (!$isSysFile) {
				// Es ist ein `Model`, `FileReference` etc.
			$child = \nn\t3::newClass( $propType );
			}
			if ($isSysFile) {
				$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
				$uid = false;
				// '1'
				if (is_numeric($value)) {
					$uid = $value;
				}
				// ['uid'=>1]
				if (!$uid && is_array($value)) {
					$uid = $value['uid'] ?? false;
				}
				// 'index.php?eID=dumpFile&t=f&f=255&token=...' or 'https://www.website.com/fileadmin/file.txt'
				if (!$uid && is_string($value)) {
					$queryParams = [];
					$parsedUrl = parse_url($value);
					parse_str($parsedUrl['query'], $queryParams);
					if (($queryParams['eID'] ?? false) == 'dumpFile' && $uid = intval($queryParams['f'] ?? 0)) {
						$value = $resourceFactory->getFileObject($uid);
					} else if ($parsedUrl['host'] ?? false) {
						$value = ltrim($parsedUrl['path'], '/');
					}
				}
				if ($uid) {
					$value = $resourceFactory->getFileObject(intval($uid));
				} else {
					try {
						// '/var/www/path/to/file.txt' or '1:/path/to/file.txt' or '/fileadmin/path/to/file.txt'
						$value = $resourceFactory->getFileObjectFromCombinedIdentifier($value);
					} catch( \Exception $e ) {
						$value = null;
					}
				}
			} else if ($this->isFileReference($child)) {
				// -----
				// Die Property ist eine einzelne `SysFileReference` – keine `ObjectStorage`
				$curPublicUrl = \nn\t3::File()->getPublicUrl( $curPropValue );
				$publicUrl = \nn\t3::File()->getPublicUrl( $value );
				if ($curPublicUrl == $publicUrl) {
					// An der URL hat sich nichts geändert. Bisherige `SysFileReference` weiter verwenden.
					$value = $curPropValue;
				} else {
					// Neue URL. Falls bereits ein FAL am Model: Entfernen
					if ($this->isFileReference($curPropValue)) {
						$persistenceManager = GeneralUtility::makeInstance( PersistenceManager::class );
						$persistenceManager->remove( $curPropValue );
					}
					// ... und neues FAL erzeugen
					if ($value) {
						\nn\t3::Fal()->attach( $model, $propName, $value );
						continue;
					} else {
						$value = null;
					}
				}
			} else if ($this->isStorage($child)) {
				// -----
				// Die Property ist eine `ObjectStorage`
				$value = $this->forceArray( $value );
				$childPropType = \nn\t3::Obj()->get($propInfo, 'elementType');
				if (!class_exists($childPropType)) {
					\nn\t3::Exception( "Class of type `{$childPropType}` is not defined." );
				}
				// sys_file stored in the ObjectStorage?
				$isSysFile = is_a($childPropType, \TYPO3\CMS\Core\Resource\File::class, true);
				$isFileReference = false;
				if (!$isSysFile) {
					$storageItemInstance = \nn\t3::newClass( $childPropType );
					$isFileReference = $this->isFileReference( $storageItemInstance );
				}
				// Array der existierende Items in der `ObjectStorage` holen. Key ist `uid` oder `publicUrl`
				$existingStorageItemsByUid = [];
				if ($curPropValue) {
					foreach ($curPropValue as $item) {
						$uid = $isFileReference ? \nn\t3::File()->getPublicUrl( $item ) : $this->get( $item, 'uid' );
						if (!isset($existingStorageItemsByUid)) {
							$existingStorageItemsByUid[$uid] = [];
						}
						$existingStorageItemsByUid[$uid][] = $item;
					}
				}
				$storageClassName = get_class($child);
				$objectStorage =  \nn\t3::newClass( $storageClassName );
				// Jedes Item in die Storage einfügen. Dabei werden bereits vorhandene Items aus der alten Storage verwendet.
				foreach ($value as $itemData) {
					$uid = false;
					// `[1, ...]`
					if (is_numeric($itemData)) $uid = $itemData;
					// `[['publicUrl'=>'bild.jpg'], ...]` oder `[['bild.jpg'], ...]`
					if (!$uid && $isFileReference) $uid = \nn\t3::File()->getPublicUrl( $itemData );
					// `[['uid'=>'1'], ...]`
					if (!$uid) $uid = $this->get( $itemData, 'uid' );
					// Gibt es das Item bereits? Dann vorhandenes Item verwenden, kein neues erzeugen!
					$arrayReference = $existingStorageItemsByUid[$uid] ?? [];
					$item = array_shift($arrayReference);
					// Item bereits vorhanden?
					if ($item) {
						// ... dann das bisherige Item verwenden.
						// $item = \nn\t3::Obj( $item )->merge( $itemData );
					} else if ($isSysFile) {
						\nn\t3::Exception( "Converting to SysFile not supported yet." );
					} else if ($isFileReference) {
						// sonst: Falls eine FileReference gewünscht ist, dann neu erzeugen!
						$item = \nn\t3::Fal()->createForModel( $model, $propName, $itemData );
					} else if ($uid) {
						// Alles AUSSER `FileReference` – und `uid` übergeben/bekannt? Dann das Model aus der Datenbank laden.
						$item = \nn\t3::Db()->get( $uid, $childPropType );
						// Model nicht in DB gefunden? Dann ignorieren.
						if (!$item) continue;
					} else {
						// Keine `FileReference` und KEINE `uid` übergeben? Dann neues Model erzeugen.
						$item = \nn\t3::newClass( $childPropType );
					}
					// Model konnte nicht erzeugt / gefunden werden? Dann ignorieren!
					if (!$item) continue;
					// Merge der neuen Overlay-Daten und ans Storage hängen
					$item = \nn\t3::Obj( $item )->merge( $itemData );
					$objectStorage->attach( $item );
				}
				$value = $objectStorage;
			}
			else if ( is_a($child, \DateTime::class, true )) {
				// -----
				// Die Property ist ein `DateTime`
				if ($value) {
					$value = (new \DateTime())->setTimestamp( $value );
				} else {
					$value = null;
				}
			}
			else {
				// -----
				// Property enthält eine einzelne Relation, ist aber weder eine `FileReference` noch eine `ObjectStorage`
				if ($uid = is_numeric($value) ? $value : $this->get( $value, 'uid' )) {
					$child = \nn\t3::Db()->get( $uid, get_class($child) );
					if (!$child) $value = null;
				}
				if ($value) {
					$value = \nn\t3::Obj( $child )->merge( $value );
				}
			}
			$this->set( $model, $propName, $value );
		}
	}
	return $model;
}
Copied!

Obj::parseType() 

\nn\t3::Obj()->parseType($paramType = ''); 

Einen String mit Infos zu ObjectStorage<Model> parsen.

\nn\t3::Obj()->parseType( 'string' );
\nn\t3::Obj()->parseType( 'Nng\Nnrestapi\Domain\Model\ApiTest' );
\nn\t3::Obj()->parseType( '\TYPO3\CMS\Extbase\Persistence\ObjectStorage<Nng\Nnrestapi\Domain\Model\ApiTest>' );
Copied!

Git ein Array mit Infos zurück: | type ist dabei nur gesetzt, falls es ein Array oder eine ObjectStorage ist. | elementType ist immer der Typ des Models oder das TypeHinting der Variable

[
    'elementType' => 'Nng\Nnrestapi\Domain\Model\ApiTest',
    'type' => 'TYPO3\CMS\Extbase\Persistence\ObjectStorage',
    'simple' => FALSE
]
Copied!

| @return array

Source Code 

public function parseType( $paramType = '' )
{
	if (!$paramType || !trim($paramType)) {
		return ['elementType'=>'', 'type'=>'', 'simple'=>true ];
	}
	if (class_exists(TypeHandlingUtility::class)) {
		$typeInfo = \TYPO3\CMS\Extbase\Utility\TypeHandlingUtility::parseType( $paramType );
	} else {
		preg_match( '/([^<]*)<?([^>]*)?>?/', $paramType, $type );
		$typeInfo = [
			'elementType' => ltrim($type[2], '\\'),
			'type' => ltrim($type[1], '\\')
		];
	}
	if (!$typeInfo['elementType']) {
		$typeInfo['elementType'] = $typeInfo['type'];
		$typeInfo['type'] = '';
	}
	$typeInfo['simple'] = $this->isSimpleType($typeInfo['elementType']);
	return $typeInfo;
}
Copied!

Obj::prop() 

\nn\t3::Obj()->prop($obj, $key); 

Zugriff auf einen Key in einem Object oder Array. Der Key kann auch ein Pfad sein, z.B. "img.0.uid"

nnt3::Obj()->prop( $obj, 'img.0.uid' );

@param mixed $obj Model oder Array
@param string $key der Key, der geholt werden soll

| @return mixed

Source Code 

public function prop ( $obj, $key )
{
	if ($key == '') return '';
	$key = explode('.', $key);
	if (count($key) == 1) return $this->accessSingleProperty($obj, $key[0]);
	foreach ($key as $k) {
		$obj = $this->accessSingleProperty($obj, $k);
		if (!$obj) return '';
	}
	return $obj;
}
Copied!

Obj::props() 

\nn\t3::Obj()->props($obj, $keys = []); 

Einzelne Properties eines Objects oder Arrays holen

\nn\t3::Obj()->props( $obj, ['uid', 'pid'] );
\nn\t3::Obj()->props( $obj, 'uid' );
Copied!

| @return array

Source Code 

public function props ( $obj, $keys = [] )
{
	if (is_string($keys)) {
		$keys = [$keys];
	}
	$arr = [];
	foreach ($keys as $k) {
		$arr[$k] = $this->prop( $obj, $k );
	}
	return $arr;
}
Copied!

Obj::set() 

\nn\t3::Obj()->set($obj, $key = '', $val = '', $useSetter = true); 

Setzt einen Wert in einem Object oder Array.

\nn\t3::Obj()->set( $obj, 'title', $val );
Copied!
@param mixed $obj Model oder Array
@param string $key der Key / Property
@param mixed $val der Wert, der gesetzt werden soll
@param boolean $useSetter setKey()-Methode zum Setzen verwenden

| @return mixed

Source Code 

public function set( $obj, $key = '', $val = '', $useSetter = true)
{
	$settable = ObjectAccess::isPropertySettable($obj, $key);
	if (!$settable) {
		$key = GeneralUtility::underscoredToLowerCamelCase( $key );
		$settable = ObjectAccess::isPropertySettable($obj, $key);
	}
	if ($settable) {
		if (is_object($obj)) {
			$modelProperties = $this->getProps($obj);
			if ($type = $modelProperties[$key] ?? false) {
				// SysFileReference wird gebraucht, aber SysFile wurde übergeben?
				if (is_a($type, FalFileReference::class, true )) {
					if (!$val) {
						$val = '';
					} else if ($this->isFile( $val )) {
						$val = \nn\t3::Fal()->fromFalFile( $val );
					}
				}
				// ObjectStorage soll geleert werden?
				if (is_a($type, ObjectStorage::class, true )) {
					$val = new ObjectStorage();
				}
				switch ($type) {
					case 'int':
						$val = (int)$val;
						break;
					case 'float':
						$val = (float)$val;
						break;
				}
			}
		}
		if (in_array($key, ['deleted', 'hidden'])) $val = $val ? true : false;
		ObjectAccess::setProperty($obj, $key, $val, !$useSetter);
	}
	return $obj;
}
Copied!

Obj::toArray() 

\nn\t3::Obj()->toArray($obj, $depth = 3, $fields = [], $addClass = false); 

Konvertiert ein Object in ein Array Bei Memory-Problemen wegen Rekursionen: Max-Tiefe angebenen!

\nn\t3::Obj()->toArray($obj, 2, ['uid', 'title']);
\nn\t3::Obj()->toArray($obj, 1, ['uid', 'title', 'parent.uid']);
Copied!
@param mixed $obj ObjectStorage, Model oder Array das Konvertiert werden soll
@param integer $depth Tiefe, die konvertiert werden soll. Bei rekursivem Konvertieren unbedingt nutzen
@param array $fields nur diese Felder aus dem Object / Array zurückgeben
@param boolean $addClass '__class' mit Infos zur Klasse ergänzen?

| @return array

Source Code 

public function toArray ( $obj, $depth = 3, $fields = [], $addClass = false )
{
	if ($obj === null) {
		return null;
	}
	$isSimpleType = $this->isSimpleType( gettype($obj) );
	$isStorage = !$isSimpleType && $this->isStorage($obj);
	if ($depth < 0) {
		return $isSimpleType && !is_array($obj) ? $obj : self::END_OF_RECURSION;
	}
	if ($isSimpleType && !is_array($obj)) {
		return $obj;
	}
	$type = is_object($obj) ? get_class($obj) : false;
	$final = [];
	$depth--;
	if (is_a($obj, \TYPO3\CMS\Extbase\Persistence\Generic\QueryResult::class)) {
		$obj = $obj->toArray();
	} else if (is_a($obj, \DateTime::class)) {
		// DateTime in UTC konvertieren
		$utc = $obj->getTimestamp();
		return $utc;
	} else if ($isStorage) {
		// StorageObject in einfaches Array konvertieren
		$obj = $this->forceArray( $obj );
		if ($addClass) $obj['__class'] = ObjectStorage::class;
	} else if (\nn\t3::Obj()->isSysCategory($obj)) {
		//$categoryData = ['uid' => $obj->getUid(), 'title'=>$obj->getTitle(), 'parent'=>$parent];
		$categoryData = [];
		foreach ($this->getKeys($obj) as $k) {
			if ($k == 'parent') {
				$categoryData[$k] = $this->toArray( $obj->getParent(), $depth, $fields, $addClass );
				continue;
			}
			$categoryData[$k] = ObjectAccess::getProperty($obj, $k);
		}
		if ($addClass) $categoryData['__class'] = $type;
		return $categoryData;
	} else if (\nn\t3::Obj()->isFalFile($obj)) {
		// SysFile in Array konvertieren
		$falData = ['uid' => $obj->getUid(), 'title'=>$obj->getTitle(), 'publicUrl'=>$obj->getPublicUrl()];
		if ($addClass) $falData['__class'] = $type;
		return $falData;
	} else if (\nn\t3::Obj()->isFileReference($obj)) {
		// FileReference in einfaches Array konvertieren
		$map = ['uid', 'pid', 'title', 'alternative', 'link', 'description', 'size', 'publicUrl', 'crop', 'type'];
		$falData = [];
		if ($originalResource = $obj->getOriginalResource()) {
			$props = $originalResource->getProperties();
			$props['publicUrl'] = $originalResource->getPublicUrl();
			foreach ($map as $k=>$v) {
				$falData[$v] = $props[$v];
			}
		}
		// Falls FAL nicht über Backend erzeugt wurde, fehlt evtl. das Feld "crop". Also: mit default nachrüsten
		if (!$falData['crop']) {
			$falData['crop'] = json_encode(['default'=>['cropArea' => ['x'=>0, 'y'=>0, 'width'=>1, 'height'=>1]]]);
		}
		if ($addClass) $falData['__class'] = FalFileReference::class;
		return $falData;
	} else if ($type) {
		// Alle anderen Objekte
		$keys = $fields ?: $this->getKeys($obj);
		foreach ($keys as $field) {
			$val = $this->prop($obj, $field);
			$val = $this->toArray($val, $depth, $fields, $addClass);
			if ($val === self::END_OF_RECURSION) continue;
			$final[$field] = $val;
		}
		return $final;
	}
	foreach ($obj as $k=>$v) {
		$val = $this->toArray( $v, $depth, $fields, $addClass );
		if ($val === self::END_OF_RECURSION) continue;
		$final[$k] = $val;
	}
	return $final;
}
Copied!

Page 

\nn\t3::Page() 

Alles rund um die pages Tabelle.

Overview of Methods 

\nn\t3::Page()->addCssFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

CSS-Datei in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addCss( 'path/to/style.css' );
Copied!

| @return void

| ➜ Go to source code of Page::addCssFile()

\nn\t3::Page()->addCssLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

CSS-Library in <head> einschleusen

\nn\t3::Page()->addCssLibrary( 'path/to/style.css' );
Copied!

| @return void

| ➜ Go to source code of Page::addCssLibrary()

\nn\t3::Page()->addFooter($str = ''); 

CSS oder JS oder HTML-Code an Footer anhängen. Entscheidet selbst, welche Methode des PageRenderes zu verwenden ist.

\nn\t3::Page()->addFooter( 'fileadmin/style.css' );
\nn\t3::Page()->addFooter( ['fileadmin/style.css', 'js/script.js'] );
\nn\t3::Page()->addFooter( 'js/script.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addFooter()

\nn\t3::Page()->addFooterData($html = ''); 

HTML-Code vor Ende der <body> einschleusen Siehe \nn\t3::Page()->addFooter() für einfachere Version.

\nn\t3::Page()->addFooterData( '<script src="..."></script>' );
Copied!

| @return void

| ➜ Go to source code of Page::addFooterData()

\nn\t3::Page()->addHeader($str = ''); 

CSS oder JS oder HTML-Code an Footer anhängen. Entscheidet selbst, welche Methode des PageRenderes zu verwenden ist.

\nn\t3::Page()->addHeader( 'fileadmin/style.css' );
\nn\t3::Page()->addHeader( ['fileadmin/style.css', 'js/script.js'] );
\nn\t3::Page()->addHeader( 'js/script.js' );
\nn\t3::Page()->addHeader( '<script>....</script>' );
Copied!

| @return void

| ➜ Go to source code of Page::addHeader()

\nn\t3::Page()->addHeaderData($html = ''); 

HTML-Code in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addHeaderData( '<script src="..."></script>' );
Copied!

| @return void

| ➜ Go to source code of Page::addHeaderData()

\nn\t3::Page()->addJsFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Datei in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addJsFile( 'path/to/file.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addJsFile()

\nn\t3::Page()->addJsFooterFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Datei am Ende der <body> einschleusen Siehe \nn\t3::Page()->addJsFooterFile() für einfachere Version.

\nn\t3::Page()->addJsFooterFile( 'path/to/file.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addJsFooterFile()

\nn\t3::Page()->addJsFooterLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Library am Ende der <body> einschleusen

\nn\t3::Page()->addJsFooterLibrary( 'path/to/file.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addJsFooterLibrary()

\nn\t3::Page()->addJsLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Library in <head> einschleusen.

\nn\t3::Page()->addJsLibrary( 'path/to/file.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addJsLibrary()

\nn\t3::Page()->clearCache($pid = NULL); 

Seiten-Cache einer (oder mehrerer) Seiten löschen

\nn\t3::Page()->clearCache( $pid );
\nn\t3::Page()->clearCache( [1,2,3] );
\nn\t3::Page()->clearCache();
Copied!

| @return void

| ➜ Go to source code of Page::clearCache()

\nn\t3::Page()->get($uid = NULL); 

Daten einer Seiten holen (aus Tabelle "pages")

\nn\t3::Page()->get( $uid );
Copied!

| @return array

| ➜ Go to source code of Page::get()

\nn\t3::Page()->getChildPids($parentPid = 0, $recursive = 999); 

Liste der Child-Uids einer oder mehrerer Seiten holen.

\nn\t3::Page()->getChildPids( 123, 1 );
\nn\t3::Page()->getChildPids( [123, 124], 99 );
Copied!

| @return array

| ➜ Go to source code of Page::getChildPids()

\nn\t3::Page()->getData($pids = NULL); 

Daten einer Seiten holen (Tabelle pages).

// data der aktuellen Seite
\nn\t3::Page()->getData();

// data der Seite mit pid = 123 holen
\nn\t3::Page()->getData( 123 );

// data der Seiten mit pids = 123 und 456 holen. Key des Arrays = pid
\nn\t3::Page()->getData( [123, 456] );
Copied!

| @return array

| ➜ Go to source code of Page::getData()

\nn\t3::Page()->getField($key, $slide = false, $override = ''); 

Einzelnes Feld aus page-Data holen. Der Wert kann per slide = true von übergeordneten Seiten geerbt werden.

(!) Wichtig: Eigene Felder müssen in der ext_localconf.php als rootLine definiert werden! Siehe auch \nn\t3::Registry()->rootLineFields(['key', '...']);

\nn\t3::Page()->getField('layout');
\nn\t3::Page()->getField('backend_layout_next_level', true, 'backend_layout');
Copied!

Exisitiert auch als ViewHelper:

{nnt3:page.data(key:'uid')}
{nnt3:page.data(key:'media', slide:1)}
{nnt3:page.data(key:'backend_layout_next_level', slide:1, override:'backend_layout')}
Copied!

| @return mixed

| ➜ Go to source code of Page::getField()

\nn\t3::Page()->getPageRenderer(); 

Page-Renderer holen

\nn\t3::Page()->getPageRenderer();
Copied!

| @return PageRenderer

| ➜ Go to source code of Page::getPageRenderer()

\nn\t3::Page()->getPid($fallback = NULL); 

PID der aktuellen Seite holen. Im Frontend: Die aktuelle TSFE->id Im Backend: Die Seite, die im Seitenbaum ausgewählt wurde Ohne Context: Die pid der site-Root

\nn\t3::Page()->getPid();
\nn\t3::Page()->getPid( $fallbackPid );
Copied!

| @return int

| ➜ Go to source code of Page::getPid()

\nn\t3::Page()->getPidFromRequest(); 

PID aus Request-String holen, z.B. in Backend Modulen. Hacky. ToDo: Prüfen, ob es eine bessere Methode gibt.

\nn\t3::Page()->getPidFromRequest();
Copied!

| @return int

| ➜ Go to source code of Page::getPidFromRequest()

\nn\t3::Page()->getRootline($pid = NULL); 

Rootline für gegebene PID holen

\nn\t3::Page()->getRootline();
Copied!

| @return array

| ➜ Go to source code of Page::getRootline()

\nn\t3::Page()->getSiteRoot($returnAll = false); 

PID der Site-Root(s) holen. Entspricht der Seite im Backend, die die "Weltkugel" als Symbol hat (in den Seiteneigenschaften "als Anfang der Webseite nutzen")

\nn\t3::Page()->getSiteRoot();
Copied!

| @return int

| ➜ Go to source code of Page::getSiteRoot()

\nn\t3::Page()->getSubpages($pid = NULL, $includeHidden = false, $includeAllTypes = false); 

Menü für gegebene PID holen

\nn\t3::Page()->getSubpages();
\nn\t3::Page()->getSubpages( $pid );
\nn\t3::Page()->getSubpages( $pid, true );   // Auch versteckte Seiten holen
\nn\t3::Page()->getSubpages( $pid, false, true );    // Alle Seiten-Typen holen
\nn\t3::Page()->getSubpages( $pid, false, [PageRepository::DOKTYPE_SYSFOLDER] ); // Bestimmte Seiten-Typen holen
Copied!
@param int $pid
@param bool $includeHidden
@param bool|array $includeAllTypes
@return array

| ➜ Go to source code of Page::getSubpages()

\nn\t3::Page()->getTitle(); 

Aktuellen Page-Title (ohne Suffix) holen

\nn\t3::Page()->getTitle();
Copied!

| @return string

| ➜ Go to source code of Page::getTitle()

\nn\t3::Page()->hasSubpages($pid = NULL); 

Prüft, ob eine Seite Untermenüs hat

\nn\t3::Page()->hasSubpages();
Copied!

| @return boolean

| ➜ Go to source code of Page::hasSubpages()

\nn\t3::Page()->setTitle($title = ''); 

PageTitle (<title>-Tag) ändern Funktioniert nicht, wenn EXT:advancedtitle aktiviert ist!

\nn\t3::Page()->setTitle('YEAH!');
Copied!

Auch als ViewHelper vorhanden:

{nnt3:page.title(title:'Yeah')}
{entry.title->nnt3:page.title()}
Copied!

| @return void

| ➜ Go to source code of Page::setTitle()

Methods 

Page::addCssFile() 

\nn\t3::Page()->addCssFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

CSS-Datei in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addCss( 'path/to/style.css' );
Copied!

| @return void

Source Code 

public function addCssFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$this->getPageRenderer()->addCssFile( $path, 'stylesheet', 'all', '', $compress, $atTop, $wrap, $concat );
}
Copied!

Page::addCssLibrary() 

\nn\t3::Page()->addCssLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

CSS-Library in <head> einschleusen

\nn\t3::Page()->addCssLibrary( 'path/to/style.css' );
Copied!

| @return void

Source Code 

public function addCssLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$this->getPageRenderer()->addCssLibrary( $path, 'stylesheet', 'all', '', $compress, $atTop, $wrap, $concat );
}
Copied!

Page::addFooter() 

\nn\t3::Page()->addFooter($str = ''); 

CSS oder JS oder HTML-Code an Footer anhängen. Entscheidet selbst, welche Methode des PageRenderes zu verwenden ist.

\nn\t3::Page()->addFooter( 'fileadmin/style.css' );
\nn\t3::Page()->addFooter( ['fileadmin/style.css', 'js/script.js'] );
\nn\t3::Page()->addFooter( 'js/script.js' );
Copied!

| @return void

Source Code 

public function addFooter ( $str = '' ) {
	if (!is_array($str)) $str = [$str];
	foreach ($str as $n) {
		if (strpos($n, '<') !== false) {
			$this->addFooterData( $n );
		} else {
			$suffix = \nn\t3::File()->suffix($n);
			if ($suffix == 'js') {
				$this->addJsFooterFile( $n );
			} else {
				// addCssFooterFile() scheint nicht zu existieren
				$this->addCssLibrary( $n );
			}
		}
	}
}
Copied!

Page::addFooterData() 

\nn\t3::Page()->addFooterData($html = ''); 

HTML-Code vor Ende der <body> einschleusen Siehe \nn\t3::Page()->addFooter() für einfachere Version.

\nn\t3::Page()->addFooterData( '<script src="..."></script>' );
Copied!

| @return void

Source Code 

public function addFooterData( $html = '' ) {
	$this->getPageRenderer()->addFooterData( $html );
}
Copied!

Page::addHeader() 

\nn\t3::Page()->addHeader($str = ''); 

CSS oder JS oder HTML-Code an Footer anhängen. Entscheidet selbst, welche Methode des PageRenderes zu verwenden ist.

\nn\t3::Page()->addHeader( 'fileadmin/style.css' );
\nn\t3::Page()->addHeader( ['fileadmin/style.css', 'js/script.js'] );
\nn\t3::Page()->addHeader( 'js/script.js' );
\nn\t3::Page()->addHeader( '<script>....</script>' );
Copied!

| @return void

Source Code 

public function addHeader ( $str = '' ) {
	if (!is_array($str)) $str = [$str];
	foreach ($str as $n) {
		if (strpos($n, '<') !== false) {
			$this->addHeaderData( $n );
		} else {
			$suffix = \nn\t3::File()->suffix($n);
			if ($suffix == 'js') {
				$this->addJsFile( $n );
			} else {
				// addCssFooterFile() scheint nicht zu existieren
				$this->addCssLibrary( $n );
			}
		}
	}
}
Copied!

Page::addHeaderData() 

\nn\t3::Page()->addHeaderData($html = ''); 

HTML-Code in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addHeaderData( '<script src="..."></script>' );
Copied!

| @return void

Source Code 

public function addHeaderData( $html = '' ) {
	$this->getPageRenderer()->addHeaderData( $html );
}
Copied!

Page::addJsFile() 

\nn\t3::Page()->addJsFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Datei in <head> einschleusen Siehe \nn\t3::Page()->addHeader() für einfachere Version.

\nn\t3::Page()->addJsFile( 'path/to/file.js' );
Copied!

| @return void

Source Code 

public function addJsFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$pageRenderer = $this->getPageRenderer();
	$pageRenderer->addJsFile( $path, NULL, $compress, $atTop, $wrap, $concat );
}
Copied!

Page::addJsFooterFile() 

\nn\t3::Page()->addJsFooterFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Datei am Ende der <body> einschleusen Siehe \nn\t3::Page()->addJsFooterFile() für einfachere Version.

\nn\t3::Page()->addJsFooterFile( 'path/to/file.js' );
Copied!

| @return void

Source Code 

public function addJsFooterFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$this->getPageRenderer()->addJsFooterFile( $path, NULL, $compress, $atTop, $wrap, $concat );
}
Copied!

Page::addJsFooterLibrary() 

\nn\t3::Page()->addJsFooterLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Library am Ende der <body> einschleusen

\nn\t3::Page()->addJsFooterLibrary( 'path/to/file.js' );
Copied!

| @return void

Source Code 

public function addJsFooterLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$this->getPageRenderer()->addJsFooterLibrary( $path, $path, NULL, $compress, $atTop, $wrap, $concat );
}
Copied!

Page::addJsLibrary() 

\nn\t3::Page()->addJsLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS-Library in <head> einschleusen.

\nn\t3::Page()->addJsLibrary( 'path/to/file.js' );
Copied!

| @return void

Source Code 

public function addJsLibrary($path, $compress = false, $atTop = false, $wrap = false, $concat = false ) {
	$pageRenderer = $this->getPageRenderer();
	$pageRenderer->addJsLibrary( $path, $path, NULL, $compress, $atTop, $wrap, $concat );
}
Copied!

Page::clearCache() 

\nn\t3::Page()->clearCache($pid = NULL); 

Seiten-Cache einer (oder mehrerer) Seiten löschen

\nn\t3::Page()->clearCache( $pid );
\nn\t3::Page()->clearCache( [1,2,3] );
\nn\t3::Page()->clearCache();
Copied!

| @return void

Source Code 

public function clearCache ( $pid = null ) {
	$pidList = \nn\t3::Arrays($pid ?: 'all')->trimExplode();
	if (\nn\t3::Environment()->isFrontend()) {
		// Im Frontend-Context
		$cacheService = GeneralUtility::makeInstance( CacheService::class );
		$cacheManager = GeneralUtility::makeInstance( CacheManager::class );
		foreach ($pidList as $pid) {
			if ($pid == 'all') {
				$cacheService->clearCachesOfRegisteredPageIds();
				$cacheService->clearPageCache();
			} else {
				$cacheService->clearPageCache($pid);
				$cacheManager->flushCachesInGroupByTags('pages', [ 'pageId_'.$pid ]);
				$cacheService->getPageIdStack()->push($pid);
				$cacheService->clearCachesOfRegisteredPageIds();
			}
		}
	} else {
		// Im Backend-Context kann der DataHandler verwendet werden
		$dataHandler = GeneralUtility::makeInstance( DataHandler::class );
		$dataHandler->admin = 1;
		$dataHandler->start([], []);
		foreach ($pidList as $pid) {
			$dataHandler->clear_cacheCmd($pid);
		}
	}
}
Copied!

Page::get() 

\nn\t3::Page()->get($uid = NULL); 

Daten einer Seiten holen (aus Tabelle "pages")

\nn\t3::Page()->get( $uid );
Copied!

| @return array

Source Code 

public function get ( $uid = null ) {
	$pageRepository = GeneralUtility::makeInstance( PageRepository::class );
	return $pageRepository->getPage( $uid );
}
Copied!

Page::getChildPids() 

\nn\t3::Page()->getChildPids($parentPid = 0, $recursive = 999); 

Liste der Child-Uids einer oder mehrerer Seiten holen.

\nn\t3::Page()->getChildPids( 123, 1 );
\nn\t3::Page()->getChildPids( [123, 124], 99 );
Copied!

| @return array

Source Code 

public function getChildPids( $parentPid = 0, $recursive = 999 )
{
	if (!$parentPid) return [];
	if (!is_array($parentPid)) $parentPid = [$parentPid];
	$mergedPids = [];
	$treeRepository = GeneralUtility::makeInstance( PageRepository::class );
	foreach ($parentPid as $pid) {
		$childPids = \nn\t3::Arrays( $treeRepository->getPageIdsRecursive( [$pid], $recursive ) )->intExplode();
		$mergedPids = array_merge( $childPids, $mergedPids );
	}
	return $mergedPids;
}
Copied!

Page::getData() 

\nn\t3::Page()->getData($pids = NULL); 

Daten einer Seiten holen (Tabelle pages).

// data der aktuellen Seite
\nn\t3::Page()->getData();

// data der Seite mit pid = 123 holen
\nn\t3::Page()->getData( 123 );

// data der Seiten mit pids = 123 und 456 holen. Key des Arrays = pid
\nn\t3::Page()->getData( [123, 456] );
Copied!

| @return array

Source Code 

public function getData ( $pids = null ) {
	if (!$pids) $pids = $this->getPid( $pids );
	$returnArray = is_array( $pids );
	if (!$returnArray) $pids = [$pids];
	if (\nn\t3::Environment()->isFrontend()) {
		$pages = [];
		foreach ($pids as $pid) {
			$pages[$pid] = $this->get( $pid );
		}
		if (!$returnArray) $pages = array_pop( $pages );
		return $pages;
	}
	return [];
}
Copied!

Page::getField() 

\nn\t3::Page()->getField($key, $slide = false, $override = ''); 

Einzelnes Feld aus page-Data holen. Der Wert kann per slide = true von übergeordneten Seiten geerbt werden.

(!) Wichtig: Eigene Felder müssen in der ext_localconf.php als rootLine definiert werden! Siehe auch \nn\t3::Registry()->rootLineFields(['key', '...']);

\nn\t3::Page()->getField('layout');
\nn\t3::Page()->getField('backend_layout_next_level', true, 'backend_layout');
Copied!

Exisitiert auch als ViewHelper:

{nnt3:page.data(key:'uid')}
{nnt3:page.data(key:'media', slide:1)}
{nnt3:page.data(key:'backend_layout_next_level', slide:1, override:'backend_layout')}
Copied!

| @return mixed

Source Code 

public function getField( $key, $slide = false, $override = '' ) {
	// Rootline holen. Enthält Breadcrumb aller Menüpunkte von aktueller Seite aufwärts
	$rootline = $this->getRootline();
	$currentPage = $rootline[0];
	// Kein Slide? Dann nur aktuelle Seite verwenden
	if (!$slide) {
		$rootline = array_slice($rootline, 0, 1, true);
	}
	// Override gesetzt und Wert in aktueller Seite vorhanden? Dann verwenden.
	if ($override && $currentPage[$override]) {
		$key = $override;
	}
	// Infos zum gesuchten Column aus TCA holen
	$tcaColumn = \nn\t3::TCA()->getColumn( 'pages', $key )['config'] ?? [];
	foreach ($rootline as $page) {
		$val = false;
		if ($page[$key]) $val = $page[$key];
		if ($val) {
			// Ist es eine SysFileReference? Dann "echtes" SysFileReference-Object zurückgeben
			// ToDo: Prüfen, ob Typ besser ermittelt werden kann
			// evtl. bei \TYPO3\CMS\Core\Utility\RootlineUtility->enrichWithRelationFields() schauen.
			$isFal = in_array($tcaColumn['type'], ['inline', 'file']);
			if ($isFal && $tcaColumn['foreign_table'] == 'sys_file_reference') {
				$fileRepository = GeneralUtility::makeInstance( \TYPO3\CMS\Core\Resource\FileRepository::class );
				$fileObjects = $fileRepository->findByRelation('pages', $key, $page['uid']);
				return $fileObjects;
			}
			return $val;
		}
	}
	return null;
}
Copied!

Page::getPageRenderer() 

\nn\t3::Page()->getPageRenderer(); 

Page-Renderer holen

\nn\t3::Page()->getPageRenderer();
Copied!

| @return PageRenderer

Source Code 

public function getPageRenderer() {
	if (\nn\t3::Environment()->isFrontend()) {
		return GeneralUtility::makeInstance( PageRenderer::class );
	}
	return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
}
Copied!

Page::getPid() 

\nn\t3::Page()->getPid($fallback = NULL); 

PID der aktuellen Seite holen. Im Frontend: Die aktuelle TSFE->id Im Backend: Die Seite, die im Seitenbaum ausgewählt wurde Ohne Context: Die pid der site-Root

\nn\t3::Page()->getPid();
\nn\t3::Page()->getPid( $fallbackPid );
Copied!

| @return int

Source Code 

public function getPid ( $fallback = null ) {
	// Normaler Frontend-Content: Alles beim alten
	if (\nn\t3::Environment()->isFrontend()) {
		if (($GLOBALS['TSFE'] ?? false) && $pid = $GLOBALS['TSFE']->id) {
			return $pid;
		}
		$request = \nn\t3::Environment()->getRequest();
		$pageArguments = $request->getAttribute('routing');
		if ($pid = $pageArguments['pageId'] ?? null) {
			return $pid;
		}
		$siteRoot = $this->getSiteRoot();
		if ($siteRoot && ($pid = $siteRoot['uid'] ?? false)) {
			return $pid;
		}
		return $pid;
	}
	// Versuch, PID über den Request zu bekommen
	if ($pid = $this->getPidFromRequest()) return $pid;
	// PID über site-configuration (yaml) ermitteln
	$site = \nn\t3::Environment()->getSite();
	if ($site && ($pid = $site->getConfiguration()['rootPageId'] ?? false)) return $pid;
	// Context nicht klar, dann PID der Site-Root holen
	if ($siteRoot = $this->getSiteRoot()) return $siteRoot['uid'];
	// Letzte Chance: Fallback angegeben?
	if ($fallback) return $fallback;
	// Keine Chance
	if (\nn\t3::Environment()->isFrontend()) {
		\nn\t3::Errors()->Exception('\nn\t3::Page()->getPid() could not determine pid');
	}
}
Copied!

Page::getPidFromRequest() 

\nn\t3::Page()->getPidFromRequest(); 

PID aus Request-String holen, z.B. in Backend Modulen. Hacky. ToDo: Prüfen, ob es eine bessere Methode gibt.

\nn\t3::Page()->getPidFromRequest();
Copied!

| @return int

Source Code 

public function getPidFromRequest ()
{
	if (\TYPO3\CMS\Core\Core\Environment::isCli()) {
		return 0;
	}
	if ($request = \nn\t3::Environment()->getRequest()) {
		$params = $request->getQueryParams();
		$pageUid = array_key_first($params['edit']['pages'] ?? []);
		if ($pageUid) return $pageUid;
	}
	$pageUid = $_REQUEST['popViewId'] ?? false;
	if (!$pageUid) $pageUid = preg_replace( '/(.*)(id=)([0-9]*)(.*)/i', '\\3', $_REQUEST['returnUrl'] ?? '' );
	if (!$pageUid) $pageUid = preg_replace( '/(.*)(id=)([0-9]*)(.*)/i', '\\3', $_POST['returnUrl'] ?? '' );
	if (!$pageUid) $pageUid = preg_replace( '/(.*)(id=)([0-9]*)(.*)/i', '\\3', $_GET['returnUrl'] ?? '' );
	if (!$pageUid && ($_GET['edit']['pages'] ?? false)) $pageUid = array_keys($_GET['edit']['pages'])[0] ?? 0;
	if (!$pageUid) $pageUid = $_GET['id'] ?? 0;
	return (int) $pageUid;
}
Copied!

Page::getRootline() 

\nn\t3::Page()->getRootline($pid = NULL); 

Rootline für gegebene PID holen

\nn\t3::Page()->getRootline();
Copied!

| @return array

Source Code 

public function getRootline( $pid = null )
{
	if (!$pid) $pid = $this->getPid();
	if (!$pid) return [];
	try {
		$rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $pid);
		return $rootLine->get() ?: [];
	} catch ( \Exception $e ) {
		return [];
	}
}
Copied!

Page::getSiteRoot() 

\nn\t3::Page()->getSiteRoot($returnAll = false); 

PID der Site-Root(s) holen. Entspricht der Seite im Backend, die die "Weltkugel" als Symbol hat (in den Seiteneigenschaften "als Anfang der Webseite nutzen")

\nn\t3::Page()->getSiteRoot();
Copied!

| @return int

Source Code 

public function getSiteRoot( $returnAll = false ) {
	$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
	$queryBuilder
		->select('*')
		->from('pages')
		->andWhere($queryBuilder->expr()->eq('is_siteroot', '1'));
	if ($returnAll) return $queryBuilder->executeQuery()->fetchAllAssociative();
	return $queryBuilder->executeQuery()->fetchAssociative();
}
Copied!

Page::getSubpages() 

\nn\t3::Page()->getSubpages($pid = NULL, $includeHidden = false, $includeAllTypes = false); 

Menü für gegebene PID holen

\nn\t3::Page()->getSubpages();
\nn\t3::Page()->getSubpages( $pid );
\nn\t3::Page()->getSubpages( $pid, true );   // Auch versteckte Seiten holen
\nn\t3::Page()->getSubpages( $pid, false, true );    // Alle Seiten-Typen holen
\nn\t3::Page()->getSubpages( $pid, false, [PageRepository::DOKTYPE_SYSFOLDER] ); // Bestimmte Seiten-Typen holen
Copied!
@param int $pid
@param bool $includeHidden
@param bool|array $includeAllTypes
@return array

Source Code 

public function getSubpages( $pid = null, $includeHidden = false, $includeAllTypes = false ) {
	if (!$pid) $pid = $this->getPid();
	if (!$pid) return [];
	$page = GeneralUtility::makeInstance( PageRepository::class );
	$hideTypes = [
		$page::DOKTYPE_SPACER,
		$page::DOKTYPE_BE_USER_SECTION,
		$page::DOKTYPE_SYSFOLDER
	];
	if ($includeAllTypes === true) {
		$hideTypes = [];
	} else if ($includeAllTypes !== false) {
		if (!is_array($includeAllTypes)) {
			$includeAllTypes = [$includeAllTypes];
		}
		$hideTypes = array_diff($hideTypes, $includeAllTypes);
	}
	$constraints = [];
	$constraints[] = 'hidden = 0';
	$constraints[] = 'doktype NOT IN (' . join(',', $hideTypes) . ')';
	if (!$includeHidden) {
		$constraints[] = 'nav_hide = 0';
	}
	return $page->getMenu( $pid, '*', 'sorting', join(' AND ', $constraints) );
}
Copied!

Page::getTitle() 

\nn\t3::Page()->getTitle(); 

Aktuellen Page-Title (ohne Suffix) holen

\nn\t3::Page()->getTitle();
Copied!

| @return string

Source Code 

public function getTitle () {
	$titleProvider = GeneralUtility::makeInstance( PageTitleProvider::class );
	return $titleProvider->getRawTitle();
}
Copied!

Page::hasSubpages() 

\nn\t3::Page()->hasSubpages($pid = NULL); 

Prüft, ob eine Seite Untermenüs hat

\nn\t3::Page()->hasSubpages();
Copied!

| @return boolean

Source Code 

public function hasSubpages( $pid = null ) {
	return count( $this->getSubpages($pid) ) > 0;
}
Copied!

Page::setTitle() 

\nn\t3::Page()->setTitle($title = ''); 

PageTitle (<title>-Tag) ändern Funktioniert nicht, wenn EXT:advancedtitle aktiviert ist!

\nn\t3::Page()->setTitle('YEAH!');
Copied!

Auch als ViewHelper vorhanden:

{nnt3:page.title(title:'Yeah')}
{entry.title->nnt3:page.title()}
Copied!

| @return void

Source Code 

public function setTitle ( $title = '' ) {
	$titleProvider = GeneralUtility::makeInstance( PageTitleProvider::class );
	$titleProvider->setTitle( htmlspecialchars(strip_tags($title)) );
}
Copied!

Registry 

\nn\t3::Registry() 

Hilfreiche Methoden zum Registrieren von Extension-Komponenten wie Plugins, Backend-Module, FlexForms etc.

Overview of Methods 

\nn\t3::Registry()->addPageConfig($str = ''); 

Page-Config hinzufügen

\nn\t3::Registry()->addPageConfig( 'test.was = 10' );
\nn\t3::Registry()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::Settings()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

| ➜ Go to source code of Registry::addPageConfig()

\nn\t3::Registry()->clearCacheHook($classMethodPath = ''); 

Fügt einen Hook ein, der beim Klick auf "Cache löschen" ausgeführt wird. Folgendes Script kommt in die ext_localconf.php der eigenen Extension:

\nn\t3::Registry()->clearCacheHook( \My\Ext\Path::class . '->myMethod' );
Copied!

| @return void

| ➜ Go to source code of Registry::clearCacheHook()

\nn\t3::Registry()->configurePlugin($vendorName = '', $pluginName = '', $cacheableActions = [], $uncacheableActions = []); 

Ein Plugin konfigurieren. In ext_localconf.php nutzen.

\nn\t3::Registry()->configurePlugin( 'Nng\Nncalendar', 'Nncalendar',
    [\Nng\ExtName\Controller\MainController::class => 'index,list'],
    [\Nng\ExtName\Controller\MainController::class => 'show']
);
Copied!

| @return void

| ➜ Go to source code of Registry::configurePlugin()

\nn\t3::Registry()->flexform($vendorName = '', $pluginName = '', $path = ''); 

Ein Flexform für ein Plugin registrieren.

\nn\t3::Registry()->flexform( 'nncalendar', 'nncalendar', 'FILE:EXT:nnsite/Configuration/FlexForm/flexform.xml' );
\nn\t3::Registry()->flexform( 'Nng\Nncalendar', 'nncalendar', 'FILE:EXT:nnsite/Configuration/FlexForm/flexform.xml' );
Copied!

| @return void

| ➜ Go to source code of Registry::flexform()

\nn\t3::Registry()->fluidNamespace($referenceNames = [], $namespaces = []); 

Globalen Namespace für Fluid registrieren. Meistens in ext_localconf.php genutzt.

\nn\t3::Registry()->fluidNamespace( 'nn', 'Nng\Nnsite\ViewHelpers' );
\nn\t3::Registry()->fluidNamespace( ['nn', 'nng'], 'Nng\Nnsite\ViewHelpers' );
\nn\t3::Registry()->fluidNamespace( ['nn', 'nng'], ['Nng\Nnsite\ViewHelpers', 'Other\Namespace\Fallback'] );
Copied!

| @return void

| ➜ Go to source code of Registry::fluidNamespace()

\nn\t3::Registry()->get($extName = '', $path = ''); 

Eine Wert aus der Tabelle sys_registry holen.

\nn\t3::Registry()->get( 'nnsite', 'lastRun' );
Copied!

| @return void

| ➜ Go to source code of Registry::get()

\nn\t3::Registry()->getVendorExtensionName($combinedVendorPluginName = ''); 

Plugin-Name generieren. Abhängig von Typo3-Version wird der Plugin-Name mit oder ohne Vendor zurückgegeben.

\nn\t3::Registry()->getVendorExtensionName( 'nncalendar' );    // => Nng.Nncalendar
\nn\t3::Registry()->getVendorExtensionName( 'Nng\Nncalendar' );    // => Nng.Nncalendar
Copied!

| @return string

| ➜ Go to source code of Registry::getVendorExtensionName()

\nn\t3::Registry()->icon($identifier = '', $path = ''); 

Ein Icon registrieren. Klassischerweise in ext_tables.php genutzt.

\nn\t3::Registry()->icon('nncalendar-plugin', 'EXT:myextname/Resources/Public/Icons/wizicon.svg');
Copied!

| @return void

| ➜ Go to source code of Registry::icon()

\nn\t3::Registry()->parseControllerActions($controllerActionList = []); 

Liste mit 'ControllerName' => 'action,list,show' parsen. Immer den vollen Klassen-Pfad in der ::class Schreibweise angeben. Berücksichtigt, dass vor Typo3 10 nur der einfache Klassen-Name (z.B. Main) als Key verwendet wird.

\nn\t3::Registry()->parseControllerActions(
    [\Nng\ExtName\Controller\MainController::class => 'index,list'],
);
Copied!

| @return array

| ➜ Go to source code of Registry::parseControllerActions()

\nn\t3::Registry()->plugin($vendorName = '', $pluginName = '', $title = '', $icon = '', $tcaGroup = NULL); 

Ein Plugin registrieren zur Auswahl über das Dropdown CType im Backend. In Configuration/TCA/Overrides/tt_content.php nutzen – oder ext_tables.php (veraltet).

\nn\t3::Registry()->plugin( 'nncalendar', 'nncalendar', 'Kalender', 'EXT:pfad/zum/icon.svg' );
\nn\t3::Registry()->plugin( 'Nng\Nncalendar', 'nncalendar', 'Kalender', 'EXT:pfad/zum/icon.svg' );
Copied!

| @return void

| ➜ Go to source code of Registry::plugin()

\nn\t3::Registry()->pluginGroup($vendorName = '', $groupLabel = '', $plugins = []); 

Vereinfacht das Registrieren einer Liste von Plugins, die im list_type Dropdown zu einer Gruppe zusammengefasst werden.

In Configuration/TCA/Overrides/tt_content.php nutzen:

\nn\t3::Registry()->pluginGroup(
    'Nng\Myextname',
    'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_group_name',
    [
        'list' => [
            'title'       => 'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_list.name',
            'icon'        => 'EXT:myextname/Resources/Public/Icons/Extension.svg',
            'flexform'    => 'FILE:EXT:myextname/Configuration/FlexForm/list.xml',
        ],
        'show' => [
            'title'       => 'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_show.name',
            'icon'        => 'EXT:myextname/Resources/Public/Icons/Extension.svg',
            'flexform'    => 'FILE:EXT:myextname/Configuration/FlexForm/show.xml'
        ],
    ]
);
Copied!

| @return void

| ➜ Go to source code of Registry::pluginGroup()

\nn\t3::Registry()->rootLineFields($fields = [], $translate = true); 

Ein Feld in der Tabelle pages registrieren, das auf Unterseiten vererbbar / geslided werden soll. In der ext_localconf.php registrieren:

\nn\t3::Registry()->rootLineFields(['slidefield']);
\nn\t3::Registry()->rootLineFields('slidefield');
Copied!

Typoscript-Setup:

page.10 = FLUIDTEMPLATE
page.10.variables {
    footer = TEXT
    footer {
        data = levelfield:-1, footerelement, slide
    }
}
Copied!

| @return void

| ➜ Go to source code of Registry::rootLineFields()

\nn\t3::Registry()->set($extName = '', $path = '', $settings = [], $clear = false); 

Einen Wert in der Tabelle sys_registry speichern. Daten in dieser Tabelle bleiben über die Session hinaus erhalten. Ein Scheduler-Job kann z.B. speichern, wann er das letzte Mal ausgeführt wurde.

Arrays werden per default rekursiv zusammengeführt / gemerged:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['eins'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['zwei'=>'2'] );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['eins'=>1, 'zwei'=>2]
Copied!

Mit true am Ende werden die vorherigen Werte gelöscht:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['eins'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['zwei'=>'2'], true );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['zwei'=>2]
Copied!

| @return array

| ➜ Go to source code of Registry::set()

Methods 

Registry::addPageConfig() 

\nn\t3::Registry()->addPageConfig($str = ''); 

Page-Config hinzufügen

\nn\t3::Registry()->addPageConfig( 'test.was = 10' );
\nn\t3::Registry()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::Settings()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

Source Code 

public function addPageConfig( $str = '' )
{
	$GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'] .= "\n" . $str;
}
Copied!

Registry::clearCacheHook() 

\nn\t3::Registry()->clearCacheHook($classMethodPath = ''); 

Fügt einen Hook ein, der beim Klick auf "Cache löschen" ausgeführt wird. Folgendes Script kommt in die ext_localconf.php der eigenen Extension:

\nn\t3::Registry()->clearCacheHook( \My\Ext\Path::class . '->myMethod' );
Copied!

| @return void

Source Code 

public function clearCacheHook( $classMethodPath = '' )
{
	$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'][] = $classMethodPath;
}
Copied!

Registry::configurePlugin() 

\nn\t3::Registry()->configurePlugin($vendorName = '', $pluginName = '', $cacheableActions = [], $uncacheableActions = []); 

Ein Plugin konfigurieren. In ext_localconf.php nutzen.

\nn\t3::Registry()->configurePlugin( 'Nng\Nncalendar', 'Nncalendar',
    [\Nng\ExtName\Controller\MainController::class => 'index,list'],
    [\Nng\ExtName\Controller\MainController::class => 'show']
);
Copied!

| @return void

Source Code 

public function configurePlugin ( $vendorName = '', $pluginName = '', $cacheableActions = [], $uncacheableActions = [] )
{
	$registrationName = $this->getVendorExtensionName($vendorName);
	$pluginName = GeneralUtility::underscoredToUpperCamelCase( $pluginName );
	\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
		$registrationName, $pluginName,
		$this->parseControllerActions($cacheableActions),
		$this->parseControllerActions($uncacheableActions)
	);
}
Copied!

Registry::flexform() 

\nn\t3::Registry()->flexform($vendorName = '', $pluginName = '', $path = ''); 

Ein Flexform für ein Plugin registrieren.

\nn\t3::Registry()->flexform( 'nncalendar', 'nncalendar', 'FILE:EXT:nnsite/Configuration/FlexForm/flexform.xml' );
\nn\t3::Registry()->flexform( 'Nng\Nncalendar', 'nncalendar', 'FILE:EXT:nnsite/Configuration/FlexForm/flexform.xml' );
Copied!

| @return void

Source Code 

public function flexform ( $vendorName = '', $pluginName = '', $path = '' )
{
	// \Nng\Nnsite => nnsite
	$extName = strtolower( array_pop(explode('\\', $vendorName)) );
	$pluginKey = "{$extName}_{$pluginName}";
	$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginKey] = 'pi_flexform';
	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue($pluginKey, $path);
}
Copied!

Registry::fluidNamespace() 

\nn\t3::Registry()->fluidNamespace($referenceNames = [], $namespaces = []); 

Globalen Namespace für Fluid registrieren. Meistens in ext_localconf.php genutzt.

\nn\t3::Registry()->fluidNamespace( 'nn', 'Nng\Nnsite\ViewHelpers' );
\nn\t3::Registry()->fluidNamespace( ['nn', 'nng'], 'Nng\Nnsite\ViewHelpers' );
\nn\t3::Registry()->fluidNamespace( ['nn', 'nng'], ['Nng\Nnsite\ViewHelpers', 'Other\Namespace\Fallback'] );
Copied!

| @return void

Source Code 

public function fluidNamespace ( $referenceNames = [], $namespaces = [] )
{
	if (is_string($referenceNames)) $referenceNames = [$referenceNames];
	if (is_string($namespaces)) $namespaces = [$namespaces];
	foreach ($referenceNames as $key) {
		$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces'][$key] = $namespaces;
	}
}
Copied!

Registry::get() 

\nn\t3::Registry()->get($extName = '', $path = ''); 

Eine Wert aus der Tabelle sys_registry holen.

\nn\t3::Registry()->get( 'nnsite', 'lastRun' );
Copied!

| @return void

Source Code 

public function get ( $extName = '', $path = '' )
{
	$registry = GeneralUtility::makeInstance( CoreRegistry::class );
	return $registry->get( $extName, $path );
}
Copied!

Registry::getVendorExtensionName() 

\nn\t3::Registry()->getVendorExtensionName($combinedVendorPluginName = ''); 

Plugin-Name generieren. Abhängig von Typo3-Version wird der Plugin-Name mit oder ohne Vendor zurückgegeben.

\nn\t3::Registry()->getVendorExtensionName( 'nncalendar' );    // => Nng.Nncalendar
\nn\t3::Registry()->getVendorExtensionName( 'Nng\Nncalendar' );    // => Nng.Nncalendar
Copied!

| @return string

Source Code 

public function getVendorExtensionName( $combinedVendorPluginName = '' )
{
	// Nng als Vendor-Name verwenden, falls nichts angegeben.
	$combinedVendorPluginName = str_replace('\\', '.', $combinedVendorPluginName);
	if (strpos($combinedVendorPluginName, '.') === false) {
		$combinedVendorPluginName = 'Nng.'.$combinedVendorPluginName;
	}
	$parts = explode('.', $combinedVendorPluginName);
	$vendorName = GeneralUtility::underscoredToUpperCamelCase( $parts[0] );
	$pluginName = GeneralUtility::underscoredToUpperCamelCase( $parts[1] );
	$registrationName = "{$pluginName}";
	return $registrationName;
}
Copied!

Registry::icon() 

\nn\t3::Registry()->icon($identifier = '', $path = ''); 

Ein Icon registrieren. Klassischerweise in ext_tables.php genutzt.

\nn\t3::Registry()->icon('nncalendar-plugin', 'EXT:myextname/Resources/Public/Icons/wizicon.svg');
Copied!

| @return void

Source Code 

public function icon ( $identifier = '', $path = '' )
{
	$iconRegistry = GeneralUtility::makeInstance( \TYPO3\CMS\Core\Imaging\IconRegistry::class );
	$suffix = strtolower(pathinfo( $path, PATHINFO_EXTENSION ));
	if ($suffix != 'svg') {
		$suffix = 'bitmap';
	}
	$provider = 'TYPO3\\CMS\\Core\\Imaging\\IconProvider\\' . ucfirst($suffix) . 'IconProvider';
	$iconRegistry->registerIcon(
		$identifier,
		$provider,
		['source' => $path]
	);
}
Copied!

Registry::parseControllerActions() 

\nn\t3::Registry()->parseControllerActions($controllerActionList = []); 

Liste mit 'ControllerName' => 'action,list,show' parsen. Immer den vollen Klassen-Pfad in der ::class Schreibweise angeben. Berücksichtigt, dass vor Typo3 10 nur der einfache Klassen-Name (z.B. Main) als Key verwendet wird.

\nn\t3::Registry()->parseControllerActions(
    [\Nng\ExtName\Controller\MainController::class => 'index,list'],
);
Copied!

| @return array

Source Code 

public function parseControllerActions( $controllerActionList = [] )
{
	return $controllerActionList;
}
Copied!

Registry::plugin() 

\nn\t3::Registry()->plugin($vendorName = '', $pluginName = '', $title = '', $icon = '', $tcaGroup = NULL); 

Ein Plugin registrieren zur Auswahl über das Dropdown CType im Backend. In Configuration/TCA/Overrides/tt_content.php nutzen – oder ext_tables.php (veraltet).

\nn\t3::Registry()->plugin( 'nncalendar', 'nncalendar', 'Kalender', 'EXT:pfad/zum/icon.svg' );
\nn\t3::Registry()->plugin( 'Nng\Nncalendar', 'nncalendar', 'Kalender', 'EXT:pfad/zum/icon.svg' );
Copied!

| @return void

Source Code 

public function plugin ( $vendorName = '', $pluginName = '', $title = '', $icon = '', $tcaGroup = null )
{
	\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( $this->getVendorExtensionName($vendorName), $pluginName, $title, $icon, $tcaGroup );
}
Copied!

Registry::pluginGroup() 

\nn\t3::Registry()->pluginGroup($vendorName = '', $groupLabel = '', $plugins = []); 

Vereinfacht das Registrieren einer Liste von Plugins, die im list_type Dropdown zu einer Gruppe zusammengefasst werden.

In Configuration/TCA/Overrides/tt_content.php nutzen:

\nn\t3::Registry()->pluginGroup(
    'Nng\Myextname',
    'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_group_name',
    [
        'list' => [
            'title'       => 'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_list.name',
            'icon'        => 'EXT:myextname/Resources/Public/Icons/Extension.svg',
            'flexform'    => 'FILE:EXT:myextname/Configuration/FlexForm/list.xml',
        ],
        'show' => [
            'title'       => 'LLL:EXT:myextname/Resources/Private/Language/locallang_db.xlf:pi_show.name',
            'icon'        => 'EXT:myextname/Resources/Public/Icons/Extension.svg',
            'flexform'    => 'FILE:EXT:myextname/Configuration/FlexForm/show.xml'
        ],
    ]
);
Copied!

| @return void

Source Code 

public function pluginGroup ( $vendorName = '', $groupLabel = '', $plugins = [] )
{
	// My\ExtName => ext_name
	$extName = GeneralUtility::camelCaseToLowerCaseUnderscored(array_pop(explode('\\', $vendorName)));
	$groupName = $extName . '_group';
	// ab TYPO3 10 können im Plugin-Dropdown optgroups gebildet werden
	\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItemGroup( 'tt_content', 'list_type', $groupName, $groupLabel, 'before:default' );
	foreach ($plugins as $listType=>$config) {
		$this->plugin( $vendorName, $listType, $config['title'] ?? '', $config['icon'] ?? '', $groupName );
		if ($flexform = $config['flexform'] ?? false) {
			$this->flexform( $vendorName, $listType, $flexform );
		}
	}
}
Copied!

Registry::rootLineFields() 

\nn\t3::Registry()->rootLineFields($fields = [], $translate = true); 

Ein Feld in der Tabelle pages registrieren, das auf Unterseiten vererbbar / geslided werden soll. In der ext_localconf.php registrieren:

\nn\t3::Registry()->rootLineFields(['slidefield']);
\nn\t3::Registry()->rootLineFields('slidefield');
Copied!

Typoscript-Setup:

page.10 = FLUIDTEMPLATE
page.10.variables {
    footer = TEXT
    footer {
        data = levelfield:-1, footerelement, slide
    }
}
Copied!

| @return void

Source Code 

public function rootLineFields ( $fields = [], $translate = true )
{
	if (is_string($fields)) $fields = [$fields];
	if (!isset($GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'])) {
		$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'] = '';
	}
	$GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'] .= ($GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'] ? ',' : '') . join(',', $fields);
	if ($translate) {
		if (!isset($GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'])) {
			$GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'] = '';
		}
		$GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'] .= join(',', $fields);
	}
}
Copied!

Registry::set() 

\nn\t3::Registry()->set($extName = '', $path = '', $settings = [], $clear = false); 

Einen Wert in der Tabelle sys_registry speichern. Daten in dieser Tabelle bleiben über die Session hinaus erhalten. Ein Scheduler-Job kann z.B. speichern, wann er das letzte Mal ausgeführt wurde.

Arrays werden per default rekursiv zusammengeführt / gemerged:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['eins'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['zwei'=>'2'] );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['eins'=>1, 'zwei'=>2]
Copied!

Mit true am Ende werden die vorherigen Werte gelöscht:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['eins'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['zwei'=>'2'], true );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['zwei'=>2]
Copied!

| @return array

Source Code 

public function set ( $extName = '', $path = '', $settings = [], $clear = false )
{
	$registry = GeneralUtility::makeInstance( CoreRegistry::class );
	if (!$clear && is_array($settings)) {
		$curSettings = $this->get( $extName, $path ) ?: [];
		$settings = \nn\t3::Arrays( $curSettings )->merge( $settings, true, true );
	}
	$registry->set( $extName,  $path, $settings );
	return $settings;
}
Copied!

Request 

\nn\t3::Request() 

Zugriff auf GET / POST Variablen, Filecontainer etc.

Overview of Methods 

\nn\t3::Request()->DELETE($url = '', $queryParams = [], $headers = []); 

Sendet einen DELETE Request (per curl) an einen Server

\nn\t3::Request()->DELETE( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->DELETE( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

| ➜ Go to source code of Request::DELETE()

\nn\t3::Request()->GET($url = '', $queryParams = [], $headers = [], $dontNestArrays = false); 

Sendet einen GET Request (per curl) an einen Server

\nn\t3::Request()->GET( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->GET( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );

// falls 'a'=>[1,2,3] als a=1&a=2&a=3 gesendet werdne soll, statt a[]=1&a[]=2&a[]=3
 \nn\t3::Request()->GET( 'https://...', ['a'=>[1,2,3]], [], true );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

| ➜ Go to source code of Request::GET()

\nn\t3::Request()->GET_JSON($url = '', $queryParams = [], $headers = NULL); 

Sendet ein GET Request an einen Server und parsed das Ergebnis als JSON

\nn\t3::Request()->GET_JSON( 'https://...', ['a'=>'123'] );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

| ➜ Go to source code of Request::GET_JSON()

\nn\t3::Request()->GP($varName = NULL); 

Merge aus $_GET und $_POST-Variablen

\nn\t3::Request()->GP();
Copied!

| @return array

| ➜ Go to source code of Request::GP()

\nn\t3::Request()->JSON($url = '', $data = [], $headers = NULL); 

Sendet ein JSON per POST an einen Server

\nn\t3::Request()->JSON( 'https://...', ['a'=>'123'] );
Copied!
@param string $url
@param array $data
@param array|null $headers
@return array

| ➜ Go to source code of Request::JSON()

\nn\t3::Request()->POST($url = '', $postData = [], $headers = [], $requestType = 'POST'); 

Sendet einen POST Request (per CURL) an einen Server.

\nn\t3::Request()->POST( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->POST( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $postData
@param array $headers
@return array

| ➜ Go to source code of Request::POST()

\nn\t3::Request()->PUT($url = '', $data = [], $headers = []); 

Sendet einen PUT Request (per curl) an einen Server

\nn\t3::Request()->PUT( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->PUT( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $data
@param array $headers
@return array

| ➜ Go to source code of Request::PUT()

\nn\t3::Request()->PUT_JSON($url = '', $data = [], $headers = []); 

Sendet einen PUT Request (per curl) an einen Server als JSON

\nn\t3::Request()->PUT_JSON( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->PUT_JSON( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $data
@param array $headers
@return array

| ➜ Go to source code of Request::PUT_JSON()

\nn\t3::Request()->files($path = NULL, $forceArray = false); 

File-Uploads aus $_FILES holen und normalisieren.

Normalisiert folgende File-Upload-Varianten. Enfernt leere Datei-Uploads aus dem Array.

<input name="image" type="file" />
<input name="image[key]" type="file" />
<input name="images[]" type="file" multiple="1" />
<input name="images[key][]" type="file" multiple="1" />
Copied!

Beispiele: ALLE Datei-Infos aus $_FILESholen.

\nn\t3::Request()->files();
\nn\t3::Request()->files( true ); // Array erzwingen
Copied!

Datei-Infos aus tx_nnfesubmit_nnfesubmit[...] holen.

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit');
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit', true);    // Array erzwingen
Copied!

Nur Dateien aus tx_nnfesubmit_nnfesubmit[fal_media] holen.

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media' );
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media', true ); // Array erzwingen
Copied!

| @return array

| ➜ Go to source code of Request::files()

\nn\t3::Request()->getAuthorizationHeader(); 

Den Authorization-Header aus dem Request auslesen.

\nn\t3::Request()->getAuthorizationHeader();
Copied!

Wichtig: Wenn das hier nicht funktioniert, fehlt in der .htaccess wahrscheinlich folgende Zeile:

# nnhelpers: Verwenden, wenn PHP im PHP-CGI-Mode ausgeführt wird
RewriteRule . - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
Copied!

| @return string

| ➜ Go to source code of Request::getAuthorizationHeader()

\nn\t3::Request()->getBasicAuth(); 

Den Basic Authorization Header aus dem Request auslesen. Falls vorhanden, wird der Username und das Passwort zurückgeben.

$credentials = \nn\t3::Request()->getBasicAuth(); // ['username'=>'...', 'password'=>'...']
Copied!

Beispiel-Aufruf von einem Testscript aus:

echo file_get_contents('https://username:password@www.testsite.com');
Copied!

| @return array

| ➜ Go to source code of Request::getBasicAuth()

\nn\t3::Request()->getBearerToken(); 

Den Bearer-Header auslesen. Wird u.a. verwendet, um ein JWT (Json Web Token) zu übertragen.

\nn\t3::Request()->getBearerToken();
Copied!

| @return string|null

| ➜ Go to source code of Request::getBearerToken()

\nn\t3::Request()->getJwt(); 

Den JWT (Json Web Token) aus dem Request auslesen, validieren und bei erfolgreichem Prüfen der Signatur den Payload des JWT zurückgeben.

\nn\t3::Request()->getJwt();
Copied!

| @return array|string

| ➜ Go to source code of Request::getJwt()

\nn\t3::Request()->getUri($varName = NULL); 

Request-URI zurückgeben. Im Prinzip die URL / der GET-String in der Browser URL-Leiste, der in $_SERVER['REQUEST_URI'] gespeichert wird.

\nn\t3::Request()->getUri();
Copied!

| @return string

| ➜ Go to source code of Request::getUri()

\nn\t3::Request()->mergeGetParams($url = '', $getParams = [], $dontNestArrays = false); 

@param string $url
@param array $getParams
@param bool $dontNestArrays
@return string

| ➜ Go to source code of Request::mergeGetParams()

Methods 

Request::DELETE() 

\nn\t3::Request()->DELETE($url = '', $queryParams = [], $headers = []); 

Sendet einen DELETE Request (per curl) an einen Server

\nn\t3::Request()->DELETE( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->DELETE( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

Source Code 

public function DELETE( $url = '', $queryParams = [], $headers = [] )
{
	// ['Accept-Encoding'=>'gzip'] --> ['Accept-Encoding: gzip']
	array_walk( $headers, function (&$v, $k) {
		if (!is_numeric($k)) $v = $k . ': ' . $v;
	});
	$headers = array_values($headers);
	$url = $this->mergeGetParams($url, $queryParams);
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url );
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers );
	// follow redirects
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	$result = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	$error = curl_error($ch);
	curl_close($ch);
	if ($httpcode >= 300) {
		return [
			'error'		=> true,
			'status' 	=> $httpcode,
			'content'	=> $error,
			'response'	=> @json_decode($result, true) ?: $result,
		];
	}
	return [
		'error'		=> false,
		'status' 	=> 200,
		'content' 	=> $result,
	];
}
Copied!

Request::files() 

\nn\t3::Request()->files($path = NULL, $forceArray = false); 

File-Uploads aus $_FILES holen und normalisieren.

Normalisiert folgende File-Upload-Varianten. Enfernt leere Datei-Uploads aus dem Array.

<input name="image" type="file" />
<input name="image[key]" type="file" />
<input name="images[]" type="file" multiple="1" />
<input name="images[key][]" type="file" multiple="1" />
Copied!

Beispiele: ALLE Datei-Infos aus $_FILESholen.

\nn\t3::Request()->files();
\nn\t3::Request()->files( true ); // Array erzwingen
Copied!

Datei-Infos aus tx_nnfesubmit_nnfesubmit[...] holen.

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit');
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit', true);    // Array erzwingen
Copied!

Nur Dateien aus tx_nnfesubmit_nnfesubmit[fal_media] holen.

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media' );
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media', true ); // Array erzwingen
Copied!

| @return array

Source Code 

public function files( $path = null, $forceArray = false )
{
	if (!$_FILES) return [];
	if ($path === true) {
		$path = false;
		$forceArray = true;
	}
	$fileInfosByKey = [];
	// 'tx_nnfesubmit_nnfesubmit' => ['name' => ..., 'size' => ...]
	foreach ($_FILES as $varName => $aspects) {
		if (!($fileInfosByKey[$varName] ?? false)) {
			$fileInfosByKey[$varName] = [];
		}
		foreach ($aspects as $aspectKey => $vars) {
			// $aspectKey ist IMMER 'name' || 'tmp_name' || 'size' || 'error'
			if (!is_array($vars)) {
				// <input type="file" name="image" />
				if ($forceArray) {
					$fileInfosByKey[$varName][0][$aspectKey] = $vars;
				} else {
					$fileInfosByKey[$varName][$aspectKey] = $vars;
				}
			} else {
				foreach ($vars as $varKey => $varValue) {
					// <input type="file" name="images[]" multiple="1" />
					if (is_numeric($varKey)) {
						$fileInfosByKey[$varName][$varKey][$aspectKey] = $varValue;
					}
					if (!is_numeric($varKey)) {
						if (!is_array($varValue)) {
							// <input type="file" name="image[key]" />
							if ($forceArray) {
								$fileInfosByKey[$varName][$varKey][0][$aspectKey] = $varValue;
							} else {
								$fileInfosByKey[$varName][$varKey][$aspectKey] = $varValue;
							}
						} else {
							// <input type="file" name="images[key][]" multiple="1" />
							foreach ($varValue as $n=>$v) {
								$fileInfosByKey[$varName][$varKey][$n][$aspectKey] = $v;
							}
						}
					}
				}
			}
		}
	}
	// Leere Uploads entfernen
	foreach ($fileInfosByKey as $k=>$v) {
		if (isset($v['error']) && $v['error'] == UPLOAD_ERR_NO_FILE) {
			unset($fileInfosByKey[$k]);
		}
		if (is_array($v)) {
			foreach ($v as $k1=>$v1) {
				if (isset($v1['error']) && $v1['error'] == UPLOAD_ERR_NO_FILE) {
					unset($fileInfosByKey[$k][$k1]);
				}
				if (is_array($v1)) {
					foreach ($v1 as $k2=>$v2) {
						if (isset($v2['error']) && $v2['error'] == UPLOAD_ERR_NO_FILE) {
							unset($fileInfosByKey[$k][$k1][$k2]);
						}
					}
				}
			}
		}
	}
	if (!$path) return $fileInfosByKey;
	return \nn\t3::Settings()->getFromPath( $path, $fileInfosByKey );
}
Copied!

Request::GET() 

\nn\t3::Request()->GET($url = '', $queryParams = [], $headers = [], $dontNestArrays = false); 

Sendet einen GET Request (per curl) an einen Server

\nn\t3::Request()->GET( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->GET( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );

// falls 'a'=>[1,2,3] als a=1&a=2&a=3 gesendet werdne soll, statt a[]=1&a[]=2&a[]=3
 \nn\t3::Request()->GET( 'https://...', ['a'=>[1,2,3]], [], true );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

Source Code 

public function GET( $url = '', $queryParams = [], $headers = [], $dontNestArrays = false )
{
	// ['Accept-Encoding'=>'gzip'] --> ['Accept-Encoding: gzip']
	array_walk( $headers, function (&$v, $k) {
		if (!is_numeric($k)) $v = $k . ': ' . $v;
	});
	$headers = array_values($headers);
	$url = $this->mergeGetParams($url, $queryParams, $dontNestArrays);
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url );
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers );
	// follow redirects
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	$result = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	$error = curl_error($ch);
	curl_close($ch);
	if ($httpcode >= 300) {
		return [
			'error'		=> true,
			'status' 	=> $httpcode,
			'content'	=> $error,
			'response'	=> @json_decode($result, true) ?: $result,
		];
	}
	return [
		'error'		=> false,
		'status' 	=> 200,
		'content' 	=> $result,
	];
}
Copied!

Request::getAuthorizationHeader() 

\nn\t3::Request()->getAuthorizationHeader(); 

Den Authorization-Header aus dem Request auslesen.

\nn\t3::Request()->getAuthorizationHeader();
Copied!

Wichtig: Wenn das hier nicht funktioniert, fehlt in der .htaccess wahrscheinlich folgende Zeile:

# nnhelpers: Verwenden, wenn PHP im PHP-CGI-Mode ausgeführt wird
RewriteRule . - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
Copied!

| @return string

Source Code 

public function getAuthorizationHeader()
{
	$headers = null;
	if (isset($_SERVER['Authorization'])) {
		$headers = trim($_SERVER['Authorization']);
	} else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
		$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
	} elseif (function_exists('apache_request_headers')) {
		$requestHeaders = apache_request_headers();
		foreach ($requestHeaders as $k=>$v) {
			$requestHeaders[ucwords($k)] = $v;
		}
		if (isset($requestHeaders['Authorization'])) {
			$headers = trim($requestHeaders['Authorization']);
		}
	}
	return $headers;
}
Copied!

Request::getBasicAuth() 

\nn\t3::Request()->getBasicAuth(); 

Den Basic Authorization Header aus dem Request auslesen. Falls vorhanden, wird der Username und das Passwort zurückgeben.

$credentials = \nn\t3::Request()->getBasicAuth(); // ['username'=>'...', 'password'=>'...']
Copied!

Beispiel-Aufruf von einem Testscript aus:

echo file_get_contents('https://username:password@www.testsite.com');
Copied!

| @return array

Source Code 

public function getBasicAuth()
{
	$username = '';
	$password = '';
	if (isset($_SERVER['PHP_AUTH_USER'])) {
		$username = $_SERVER['PHP_AUTH_USER'];
		$password = $_SERVER['PHP_AUTH_PW'];
	} else {
		$check = ['HTTP_AUTHENTICATION', 'HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION'];
		foreach ($check as $key) {
			$value = $_SERVER[$key] ?? false;
			$isBasic = strpos(strtolower($value), 'basic') === 0;
			if ($value && $isBasic) {
				$decodedValue = base64_decode(substr($value, 6));
				[$username, $password] = explode(':', $decodedValue) ?: ['', ''];
				break;
			}
		}
	}
	if (!$username && !$password) return [];
	return ['username'=>$username, 'password'=>$password];
}
Copied!

Request::getBearerToken() 

\nn\t3::Request()->getBearerToken(); 

Den Bearer-Header auslesen. Wird u.a. verwendet, um ein JWT (Json Web Token) zu übertragen.

\nn\t3::Request()->getBearerToken();
Copied!

| @return string|null

Source Code 

public function getBearerToken()
{
	$headers = $this->getAuthorizationHeader();
	if (!empty($headers)) {
		if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
			return $matches[1];
		}
	}
	return null;
}
Copied!

Request::getJwt() 

\nn\t3::Request()->getJwt(); 

Den JWT (Json Web Token) aus dem Request auslesen, validieren und bei erfolgreichem Prüfen der Signatur den Payload des JWT zurückgeben.

\nn\t3::Request()->getJwt();
Copied!

| @return array|string

Source Code 

public function getJwt()
{
	$jwt = $this->getBearerToken();
	return \nn\t3::Encrypt()->parseJwt($jwt);
}
Copied!

Request::getUri() 

\nn\t3::Request()->getUri($varName = NULL); 

Request-URI zurückgeben. Im Prinzip die URL / der GET-String in der Browser URL-Leiste, der in $_SERVER['REQUEST_URI'] gespeichert wird.

\nn\t3::Request()->getUri();
Copied!

| @return string

Source Code 

public function getUri ( $varName = null )
{
	return GeneralUtility::getIndpEnv('REQUEST_URI');
}
Copied!

Request::GET_JSON() 

\nn\t3::Request()->GET_JSON($url = '', $queryParams = [], $headers = NULL); 

Sendet ein GET Request an einen Server und parsed das Ergebnis als JSON

\nn\t3::Request()->GET_JSON( 'https://...', ['a'=>'123'] );
Copied!
@param string $url
@param array $queryParams
@param array $headers
@return array

Source Code 

public function GET_JSON( $url = '', $queryParams = [], $headers = null )
{
	if ($headers === null) {
		$headers = ['Accept' => 'application/json'];
	}
	$result = $this->GET( $url, $queryParams, $headers );
	return @json_decode($result['content'], true) ?: $result['content'];
}
Copied!

Request::GP() 

\nn\t3::Request()->GP($varName = NULL); 

Merge aus $_GET und $_POST-Variablen

\nn\t3::Request()->GP();
Copied!

| @return array

Source Code 

public function GP ( $varName = null )
{
	$gp = [];
	if ($request = $GLOBALS['TYPO3_REQUEST'] ?? null) {
		ArrayUtility::mergeRecursiveWithOverrule($gp, $request->getQueryParams() ?: []);
		ArrayUtility::mergeRecursiveWithOverrule($gp, $request->getParsedBody() ?: []);
	} else {
		ArrayUtility::mergeRecursiveWithOverrule($gp, $_GET ?: []);
		ArrayUtility::mergeRecursiveWithOverrule($gp, $_POST ?: []);
	}
	if ($varName) {
		$val = \nn\t3::Settings()->getFromPath( $varName, $gp );
		return $val ?? null;
	}
	return $gp;
}
Copied!

Request::JSON() 

\nn\t3::Request()->JSON($url = '', $data = [], $headers = NULL); 

Sendet ein JSON per POST an einen Server

\nn\t3::Request()->JSON( 'https://...', ['a'=>'123'] );
Copied!
@param string $url
@param array $data
@param array|null $headers
@return array

Source Code 

public function JSON( $url = '', $data = [], $headers = null )
{
	if ($headers === null) {
		$headers = ['Content-Type' => 'application/json'];
	}
	return $this->POST( $url, json_encode($data), $headers );
}
Copied!

Request::mergeGetParams() 

\nn\t3::Request()->mergeGetParams($url = '', $getParams = [], $dontNestArrays = false); 

@param string $url
@param array $getParams
@param bool $dontNestArrays
@return string

Source Code 

public function mergeGetParams( $url = '', $getParams = [], $dontNestArrays = false )
{
	$parts = parse_url($url);
	$getP = [];
	if ($parts['query'] ?? false) {
		parse_str($parts['query'], $getP);
	}
	ArrayUtility::mergeRecursiveWithOverrule($getP, $getParams, true, true );
	$uP = explode('?', $url);
	$params = GeneralUtility::implodeArrayForUrl('', $getP);
	if ($dontNestArrays) {
		$params = preg_replace('/\[[0-9]*\]/', '', $params);
	}
	$outurl = $uP[0] . ($params ? '?' . substr($params, 1) : '');
	return $outurl;
}
Copied!

Request::POST() 

\nn\t3::Request()->POST($url = '', $postData = [], $headers = [], $requestType = 'POST'); 

Sendet einen POST Request (per CURL) an einen Server.

\nn\t3::Request()->POST( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->POST( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $postData
@param array $headers
@return array

Source Code 

public function POST( $url = '', $postData = [], $headers = [], $requestType = 'POST' )
{
	// ['Accept-Encoding'=>'gzip'] --> ['Accept-Encoding: gzip']
	array_walk( $headers, function (&$v, $k) {
		if (!is_numeric($k)) $v = $k . ': ' . $v;
	});
	if (is_array($postData)) {
		$postData = http_build_query($postData);
	}
	$headers = array_values($headers);
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postData );
	// follow redirects
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $requestType);
	$headers[] = 'Content-Type: application/x-www-form-urlencoded';
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	$result = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	$error = curl_error($ch);
	curl_close($ch);
	if ($httpcode >= 300) {
		return [
			'error'		=> true,
			'status' 	=> $httpcode,
			'content'	=> $error,
			'response'	=> @json_decode($result, true) ?: $result,
		];
	}
	return [
		'error'		=> false,
		'status' 	=> 200,
		'content' 	=> $result
	];
}
Copied!

Request::PUT() 

\nn\t3::Request()->PUT($url = '', $data = [], $headers = []); 

Sendet einen PUT Request (per curl) an einen Server

\nn\t3::Request()->PUT( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->PUT( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $data
@param array $headers
@return array

Source Code 

public function PUT( $url = '', $data = [], $headers = [] )
{
	return $this->POST( $url, $data, $headers, 'PUT' );
}
Copied!

Request::PUT_JSON() 

\nn\t3::Request()->PUT_JSON($url = '', $data = [], $headers = []); 

Sendet einen PUT Request (per curl) an einen Server als JSON

\nn\t3::Request()->PUT_JSON( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->PUT_JSON( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );
Copied!
@param string $url
@param array $data
@param array $headers
@return array

Source Code 

public function PUT_JSON( $url = '', $data = [], $headers = [] )
{
	return $this->POST( $url, json_encode($data), $headers, 'PUT' );
}
Copied!

Settings 

\nn\t3::Settings() 

Methoden, um den Zugriff auf TypoScript Setup, Constanten und PageTsConfig zu vereinfachen.

Overview of Methods 

\nn\t3::Settings()->addPageConfig($str = ''); 

Page-Config hinzufügen Alias zu \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::Settings()->addPageConfig( 'test.was = 10' );
\nn\t3::Settings()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::Settings()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

| ➜ Go to source code of Settings::addPageConfig()

\nn\t3::Settings()->get($extensionName = '', $path = ''); 

Holt das TypoScript-Setup und dort den Abschnitt "settings". Werte aus dem FlexForm werden dabei nicht gemerged. Alias zu \nn\t3::Settings()->getSettings().

\nn\t3::Settings()->get( 'nnsite' );
\nn\t3::Settings()->get( 'nnsite', 'path.in.settings' );
Copied!

| @return array

| ➜ Go to source code of Settings::get()

\nn\t3::Settings()->getCachedTyposcript(); 

High-Peformance-Version für das Initialisieren des TSFE im Backend. Das komplette TypoScript Setup holen, inkl. '.'-Syntax.

Wird über Filecache gespeichert.

\nn\t3::Settings()->getCachedTyposcript();
Copied!

| @return array

| ➜ Go to source code of Settings::getCachedTyposcript()

\nn\t3::Settings()->getConstants($tsPath = ''); 

Array der TypoScript-Konstanten holen.

\nn\t3::Settings()->getConstants();
\nn\t3::Settings()->getConstants('pfad.zur.konstante');
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.constants(path:'pfad.zur.konstante')}
Copied!

| @return array

| ➜ Go to source code of Settings::getConstants()

\nn\t3::Settings()->getExtConf($extName = ''); 

Extension-Konfiguration holen. Kommen aus der LocalConfiguration.php, werden über die Extension-Einstellungen im Backend bzw. ext_conf_template.txt definiert

Früher: $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['your_extension_key']

\nn\t3::Settings()->getExtConf( 'extname' );
Copied!

| @return mixed

| ➜ Go to source code of Settings::getExtConf()

\nn\t3::Settings()->getFromPath($tsPath = '', $setup = NULL); 

Setup von einem gegebenen Pfad holen, z.B. 'plugin.tx_example.settings'

\nn\t3::Settings()->getFromPath('plugin.pfad');
\nn\t3::Settings()->getFromPath('L', \nn\t3::Request()->GP());
\nn\t3::Settings()->getFromPath('a.b', ['a'=>['b'=>1]]);
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.setup(path:'pfad.zur.setup')}
Copied!

| @return array

| ➜ Go to source code of Settings::getFromPath()

\nn\t3::Settings()->getFullTypoScriptFromConfigurationManager(); 

Vollständiges TypoScript über den Configuration Manager holen.

Ein simpler Wrapper für die Core-Funktion aber mit try { ... } catch() Fallback.

Funktioniert nicht in jedem Kontext – z.B. nicht im CLI-Kontext! Besser: \nn\t3::Settings()->parseTypoScriptForPage(); verwenden.

Gibt die Notation mit Punkten zurück. Das kann per | \nn\t3::TypoScript()->convertToPlainArray() in ein normales Array umgewandelt werden.

// ==> ['plugin.']['example.'][...]
$setup = \nn\t3::Settings()->getFullTypoScriptFromConfigurationManager();
Copied!

| @return array

| ➜ Go to source code of Settings::getFullTypoScriptFromConfigurationManager()

\nn\t3::Settings()->getFullTyposcript($pid = NULL); 

Das komplette TypoScript Setup holen, als einfaches Array - ohne "."-Syntax Funktioniert sowohl im Frontend als auch Backend, mit und ohne übergebener pid

\nn\t3::Settings()->getFullTyposcript();
\nn\t3::Settings()->getFullTyposcript( $pid );
Copied!

| @return array

| ➜ Go to source code of Settings::getFullTyposcript()

\nn\t3::Settings()->getMergedSettings($extensionName = NULL, $ttContentUidOrSetupArray = []); 

Merge aus TypoScript-Setup für ein Plugin und seinem Flexform holen. Gibt das TypoScript-Array ab plugin.tx_extname.settings... zurück.

Wichtig: $extensionName nur angeben, wenn das Setup einer FREMDEN Extension geholt werden soll oder es keinen Controller-Context gibt, weil der Aufruf aus dem Backend gemacht wird... sonst werden die FlexForm-Werte nicht berücksichtigt!

Im FlexForm <settings.flexform.varName> verwenden! | <settings.flexform.varName> überschreibt dann settings.varName im TypoScript-Setup

| $ttContentUidOrSetupArray kann uid eines tt_content-Inhaltselementes sein oder ein einfaches Array zum Überschreiben der Werte aus dem TypoScript / FlexForm

\nn\t3::Settings()->getMergedSettings();
\nn\t3::Settings()->getMergedSettings( 'nnsite' );
\nn\t3::Settings()->getMergedSettings( $extensionName, $ttContentUidOrSetupArray );
Copied!

| @return array

| ➜ Go to source code of Settings::getMergedSettings()

\nn\t3::Settings()->getPageConfig($tsPath = '', $pid = NULL); 

Page-Configuration holen

\nn\t3::Settings()->getPageConfig();
\nn\t3::Settings()->getPageConfig('RTE.default.preset');
\nn\t3::Settings()->getPageConfig( $tsPath, $pid );
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.page(path:'pfad.zur.pageconfig')}
Copied!

| @return array

| ➜ Go to source code of Settings::getPageConfig()

\nn\t3::Settings()->getPlugin($extName = NULL); 

Das Setup für ein bestimmtes Plugin holen.

\nn\t3::Settings()->getPlugin('extname') ergibt TypoScript ab plugin.tx_extname...
Copied!

Wichtig: $extensionName nur angeben, wenn das Setup einer FREMDEN Extension geholt werden soll oder es keinen Controller-Context gibt, weil der Aufruf z.B. aus dem Backend gemacht wird

| @return array

| ➜ Go to source code of Settings::getPlugin()

\nn\t3::Settings()->getSettings($extensionName = '', $path = ''); 

Holt das TypoScript-Setup und dort den Abschnitt "settings". Werte aus dem FlexForm werden dabei nicht gemerged.

\nn\t3::Settings()->getSettings( 'nnsite' );
\nn\t3::Settings()->getSettings( 'nnsite', 'example.path' );
Copied!

| @return array

| ➜ Go to source code of Settings::getSettings()

\nn\t3::Settings()->getSiteConfig($request = NULL); 

Site-Konfiguration holen. Das ist die Konfiguration, die ab TYPO3 9 in den YAML-Dateien im Ordner /sites definiert wurden. Einige der Einstellungen sind auch über das Seitenmodul "Sites" einstellbar.

Im Kontext einer MiddleWare ist evtl. die site noch nicht geparsed / geladen. In diesem Fall kann der $request aus der MiddleWare übergeben werden, um die Site zu ermitteln.

$config = \nn\t3::Settings()->getSiteConfig();
$config = \nn\t3::Settings()->getSiteConfig( $request );
Copied!

| @return array

| ➜ Go to source code of Settings::getSiteConfig()

\nn\t3::Settings()->getStoragePid($extName = NULL); 

Aktuelle (ERSTE) StoragePid für das aktuelle Plugin holen. Gespeichert im TypoScript-Setup der Extension unter | plugin.tx_extname.persistence.storagePid bzw. im FlexForm des Plugins auf der jeweiligen Seite.

WICHTIG: Merge mit gewählter StoragePID aus dem FlexForm passiert nur, wenn $extNameleer gelassen wird.

\nn\t3::Settings()->getStoragePid();         // 123
\nn\t3::Settings()->getStoragePid('nnsite');   // 466
Copied!

| @return string

| ➜ Go to source code of Settings::getStoragePid()

\nn\t3::Settings()->getStoragePids($extName = NULL, $recursive = 0); 

ALLE storagePids für das aktuelle Plugin holen. Gespeichert als komma-separierte Liste im TypoScript-Setup der Extension unter | plugin.tx_extname.persistence.storagePid bzw. im FlexForm des Plugins auf der jeweiligen Seite.

WICHTIG: Merge mit gewählter StoragePID aus dem FlexForm passiert nur, wenn $extNameleer gelassen wird.

\nn\t3::Settings()->getStoragePids();                    // [123, 466]
\nn\t3::Settings()->getStoragePids('nnsite');          // [123, 466]
Copied!

Auch die child-PageUids holen? | true nimmt den Wert für "Rekursiv" aus dem FlexForm bzw. aus dem TypoScript der Extension von plugin.tx_extname.persistence.recursive

\nn\t3::Settings()->getStoragePids(true);                // [123, 466, 124, 467, 468]
\nn\t3::Settings()->getStoragePids('nnsite', true);        // [123, 466, 124, 467, 468]
Copied!

Alternativ kann für die Tiefe / Rekursion auch ein numerischer Wert übergeben werden.

\nn\t3::Settings()->getStoragePids(2);               // [123, 466, 124, 467, 468]
\nn\t3::Settings()->getStoragePids('nnsite', 2);       // [123, 466, 124, 467, 468]
Copied!

| @return array

| ➜ Go to source code of Settings::getStoragePids()

\nn\t3::Settings()->parseTypoScriptForPage($pageUid = 0, $request = NULL); 

TypoScript für bestimmte pageUid parsen.

Gibt die Notation mit Punkten zurück. Das kann per | \nn\t3::TypoScript()->convertToPlainArray() in ein normales Array umgewandelt werden.

// TypoScript für aktuelle pageUid holen
\nn\t3::Settings()->parseTypoScriptForPage();

// TypoScript für bestimmte pageUid holen
\nn\t3::Settings()->parseTypoScriptForPage(123);
Copied!
@param int $pid PageUid
@param ServerRequestInterface $request
@return array

| ➜ Go to source code of Settings::parseTypoScriptForPage()

\nn\t3::Settings()->setExtConf($extName = '', $key = '', $value = ''); 

Extension-Konfiguration schreiben. Schreibt eine Extension-Konfiguration in die LocalConfiguration.php. Die Werte können bei entsprechender Konfiguration in der ext_conf_template.txt auch über den Extension-Manager / die Extension Konfiguration im Backend bearbeitet werden.

\nn\t3::Settings()->setExtConf( 'extname', 'key', 'value' );
Copied!

| @return mixed

| ➜ Go to source code of Settings::setExtConf()

Methods 

Settings::addPageConfig() 

\nn\t3::Settings()->addPageConfig($str = ''); 

Page-Config hinzufügen Alias zu \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::Settings()->addPageConfig( 'test.was = 10' );
\nn\t3::Settings()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::Settings()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

Source Code 

public function addPageConfig( $str = '' )
{
	\nn\t3::Registry()->addPageConfig( $str );
}
Copied!

Settings::get() 

\nn\t3::Settings()->get($extensionName = '', $path = ''); 

Holt das TypoScript-Setup und dort den Abschnitt "settings". Werte aus dem FlexForm werden dabei nicht gemerged. Alias zu \nn\t3::Settings()->getSettings().

\nn\t3::Settings()->get( 'nnsite' );
\nn\t3::Settings()->get( 'nnsite', 'path.in.settings' );
Copied!

| @return array

Source Code 

public function get( $extensionName = '', $path = '' )
{
	return $this->getSettings( $extensionName, $path );
}
Copied!

Settings::getCachedTyposcript() 

\nn\t3::Settings()->getCachedTyposcript(); 

High-Peformance-Version für das Initialisieren des TSFE im Backend. Das komplette TypoScript Setup holen, inkl. '.'-Syntax.

Wird über Filecache gespeichert.

\nn\t3::Settings()->getCachedTyposcript();
Copied!

| @return array

Source Code 

public function getCachedTyposcript()
{
	if ($cache = \nn\t3::Cache()->read('nnhelpers_fullTsCache')) {
		return $cache;
	}
	$setup = $this->getFullTyposcript();
	\nn\t3::Cache()->write('nnhelpers_fullTsCache', $setup);
	return $this->typoscriptFullCache = $setup;
}
Copied!

Settings::getConstants() 

\nn\t3::Settings()->getConstants($tsPath = ''); 

Array der TypoScript-Konstanten holen.

\nn\t3::Settings()->getConstants();
\nn\t3::Settings()->getConstants('pfad.zur.konstante');
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.constants(path:'pfad.zur.konstante')}
Copied!

| @return array

Source Code 

public function getConstants ( $tsPath = '' )
{
	$constants = [];
	if ($request = $GLOBALS['TYPO3_REQUEST'] ?? false) {
		if ($ts = $request->getAttribute('frontend.typoscript')) {
			try {
				$constants = $ts->getSettingsTree()->toArray();
			} catch ( \Exception $e ) {
				// this might be related to https://forge.typo3.org/projects/typo3cms-core/issues
				\nn\t3::Exception('TypoScript-Setup could not be loaded. If you are trying to access it from a Middleware or the CLI, try using $request->getAttribute(\'frontend.controller\')->config[\'INTincScript\'][] = []; in your Middleware to disable caching.');
			}
		}
	}
	$config = \nn\t3::TypoScript()->convertToPlainArray( $constants );
	return $tsPath ? $this->getFromPath( $tsPath, $config ) : $config;
}
Copied!

Settings::getExtConf() 

\nn\t3::Settings()->getExtConf($extName = ''); 

Extension-Konfiguration holen. Kommen aus der LocalConfiguration.php, werden über die Extension-Einstellungen im Backend bzw. ext_conf_template.txt definiert

Früher: $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['your_extension_key']

\nn\t3::Settings()->getExtConf( 'extname' );
Copied!

| @return mixed

Source Code 

public function getExtConf( $extName = '' )
{
	return GeneralUtility::makeInstance(ExtensionConfiguration::class)->get($extName) ?: [];
}
Copied!

Settings::getFromPath() 

\nn\t3::Settings()->getFromPath($tsPath = '', $setup = NULL); 

Setup von einem gegebenen Pfad holen, z.B. 'plugin.tx_example.settings'

\nn\t3::Settings()->getFromPath('plugin.pfad');
\nn\t3::Settings()->getFromPath('L', \nn\t3::Request()->GP());
\nn\t3::Settings()->getFromPath('a.b', ['a'=>['b'=>1]]);
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.setup(path:'pfad.zur.setup')}
Copied!

| @return array

Source Code 

public function getFromPath( $tsPath = '', $setup = null )
{
	if (is_object($setup)) {
		$setup = (array) $setup;
	}
	$parts = \nn\t3::Arrays($tsPath)->trimExplode('.');
	$setup = $setup ?: $this->getFullTyposcript();
	if (!$parts) {
		return $setup;
	}
	$root = array_shift($parts);
	$plugin = array_shift($parts);
	$setup = $setup[$root] ?? [];
	if (!$plugin) return $setup;
	$setup = $setup[$plugin] ?? [];
	if (!count($parts)) return $setup;
	while (count($parts) > 0) {
		$part = array_shift($parts);
		if (count($parts) == 0) {
			return isset($setup[$part]) && is_array($setup[$part]) ? $setup[$part] : ($setup[$part] ?? '');
		}
		if (is_array($setup)) {
			$setup = $setup[$part] ?? '';
		}
	}
	return $setup;
}
Copied!

Settings::getFullTyposcript() 

\nn\t3::Settings()->getFullTyposcript($pid = NULL); 

Das komplette TypoScript Setup holen, als einfaches Array - ohne "."-Syntax Funktioniert sowohl im Frontend als auch Backend, mit und ohne übergebener pid

\nn\t3::Settings()->getFullTyposcript();
\nn\t3::Settings()->getFullTyposcript( $pid );
Copied!

| @return array

Source Code 

public function getFullTyposcript( $pid = null )
{
	if ($this->typoscriptSetupCache) return $this->typoscriptSetupCache;
	$setup = false;
	try {
		$setup = $this->parseTypoScriptForPage($pid);
		if (!$setup) {
			$setup = $this->getFullTypoScriptFromConfigurationManager();
		}
	} catch ( \Exception $e ) {
		// this might be related to https://forge.typo3.org/projects/typo3cms-core/issues
		$setup = false;
	}
	if (!$setup) {
		\nn\t3::Exception('TypoScript-Setup could not be loaded. If you are trying to access it from a Middleware or the CLI, try using $request->getAttribute(\'frontend.controller\')->config[\'INTincScript\'][] = []; in your Middleware to disable caching.');
	}
	$this->typoscriptSetupCache = \nn\t3::TypoScript()->convertToPlainArray($setup);
	return $this->typoscriptSetupCache;
}
Copied!

Settings::getFullTypoScriptFromConfigurationManager() 

\nn\t3::Settings()->getFullTypoScriptFromConfigurationManager(); 

Vollständiges TypoScript über den Configuration Manager holen.

Ein simpler Wrapper für die Core-Funktion aber mit try { ... } catch() Fallback.

Funktioniert nicht in jedem Kontext – z.B. nicht im CLI-Kontext! Besser: \nn\t3::Settings()->parseTypoScriptForPage(); verwenden.

Gibt die Notation mit Punkten zurück. Das kann per | \nn\t3::TypoScript()->convertToPlainArray() in ein normales Array umgewandelt werden.

// ==> ['plugin.']['example.'][...]
$setup = \nn\t3::Settings()->getFullTypoScriptFromConfigurationManager();
Copied!

| @return array

Source Code 

public function getFullTypoScriptFromConfigurationManager()
{
	try {
		$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
		$setup = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
		return $setup;
	} catch ( \Exception $e ) {
		// silence is golden
		return [];
	}
}
Copied!

Settings::getMergedSettings() 

\nn\t3::Settings()->getMergedSettings($extensionName = NULL, $ttContentUidOrSetupArray = []); 

Merge aus TypoScript-Setup für ein Plugin und seinem Flexform holen. Gibt das TypoScript-Array ab plugin.tx_extname.settings... zurück.

Wichtig: $extensionName nur angeben, wenn das Setup einer FREMDEN Extension geholt werden soll oder es keinen Controller-Context gibt, weil der Aufruf aus dem Backend gemacht wird... sonst werden die FlexForm-Werte nicht berücksichtigt!

Im FlexForm <settings.flexform.varName> verwenden! | <settings.flexform.varName> überschreibt dann settings.varName im TypoScript-Setup

| $ttContentUidOrSetupArray kann uid eines tt_content-Inhaltselementes sein oder ein einfaches Array zum Überschreiben der Werte aus dem TypoScript / FlexForm

\nn\t3::Settings()->getMergedSettings();
\nn\t3::Settings()->getMergedSettings( 'nnsite' );
\nn\t3::Settings()->getMergedSettings( $extensionName, $ttContentUidOrSetupArray );
Copied!

| @return array

Source Code 

public function getMergedSettings( $extensionName = null, $ttContentUidOrSetupArray = [] )
{
	// Setup für das aktuelle Plugin holen, inkl. Felder aus dem FlexForm
	try {
		$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
		$pluginSettings = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, $extensionName) ?: [];
	} catch ( \Exception $e ) {
		$pluginSettings = [];
	}
	// Fallback: Setup für das Plugin aus globaler TS-Konfiguration holen
	if (!$pluginSettings) {
		$setup = $this->getPlugin( $extensionName );
		$pluginSettings = $setup['settings'] ?? [];
	}
	// Eine tt_content.uid wurde übergeben. FlexForm des Elementes aus DB laden
	if ($ttContentUidOrSetupArray && !is_array($ttContentUidOrSetupArray)) {
		$flexform =  \nn\t3::Flexform()->getFlexform($ttContentUidOrSetupArray);
		$ttContentUidOrSetupArray =  $flexform['settings'] ?? [];
	}
	// Im Flexform sollten die Felder über settings.flexform.varname definiert werden
	$flexformSettings = $ttContentUidOrSetupArray['flexform'] ?? $pluginSettings['flexform'] ?? [];
	// Merge
	ArrayUtility::mergeRecursiveWithOverrule( $pluginSettings, $flexformSettings, true, false );
	// Referenz zu settings.flexform behalten
	if ($flexformSettings) {
		$pluginSettings['flexform'] = $flexformSettings;
	}
	return $pluginSettings;
}
Copied!

Settings::getPageConfig() 

\nn\t3::Settings()->getPageConfig($tsPath = '', $pid = NULL); 

Page-Configuration holen

\nn\t3::Settings()->getPageConfig();
\nn\t3::Settings()->getPageConfig('RTE.default.preset');
\nn\t3::Settings()->getPageConfig( $tsPath, $pid );
Copied!

Existiert auch als ViewHelper:

{nnt3:ts.page(path:'pfad.zur.pageconfig')}
Copied!

| @return array

Source Code 

public function getPageConfig( $tsPath = '', $pid = null )
{
	$pid = $pid ?: \nn\t3::Page()->getPid();
	$config = \TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig( $pid );
	$config = \nn\t3::TypoScript()->convertToPlainArray( $config );
	return $tsPath ? $this->getFromPath( $tsPath, $config ) : $config;
}
Copied!

Settings::getPlugin() 

\nn\t3::Settings()->getPlugin($extName = NULL); 

Das Setup für ein bestimmtes Plugin holen.

\nn\t3::Settings()->getPlugin('extname') ergibt TypoScript ab plugin.tx_extname...
Copied!

Wichtig: $extensionName nur angeben, wenn das Setup einer FREMDEN Extension geholt werden soll oder es keinen Controller-Context gibt, weil der Aufruf z.B. aus dem Backend gemacht wird

| @return array

Source Code 

public function getPlugin($extName = null)
{
	if (!$extName) {
		try {
			$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
			$setup = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK) ?: [];
		return $setup;
		} catch ( \Exception $e ) {
			// silence is golden
		}
	}
	// Fallback: Setup für das Plugin aus globaler TS-Konfiguration holen
	$setup = $this->getFullTyposcript();
	if (!$setup || !($setup['plugin'] ?? false)) return [];
	if (isset($setup['plugin'][$extName])) {
		return $setup['plugin'][$extName];
	}
	if (isset($setup['plugin']["tx_{$extName}"])) {
		return $setup['plugin']["tx_{$extName}"];
	}
	return $setup['plugin']["tx_{$extName}_{$extName}"] ?? [];
}
Copied!

Settings::getSettings() 

\nn\t3::Settings()->getSettings($extensionName = '', $path = ''); 

Holt das TypoScript-Setup und dort den Abschnitt "settings". Werte aus dem FlexForm werden dabei nicht gemerged.

\nn\t3::Settings()->getSettings( 'nnsite' );
\nn\t3::Settings()->getSettings( 'nnsite', 'example.path' );
Copied!

| @return array

Source Code 

public function getSettings( $extensionName = '', $path = '' )
{
	$pluginSettings = $this->getPlugin( $extensionName );
	if (!$pluginSettings) return [];
	if (!$path) return $pluginSettings['settings'] ?? [];
	return $this->getFromPath( 'settings.'.$path, $pluginSettings ?? [] );
}
Copied!

Settings::getSiteConfig() 

\nn\t3::Settings()->getSiteConfig($request = NULL); 

Site-Konfiguration holen. Das ist die Konfiguration, die ab TYPO3 9 in den YAML-Dateien im Ordner /sites definiert wurden. Einige der Einstellungen sind auch über das Seitenmodul "Sites" einstellbar.

Im Kontext einer MiddleWare ist evtl. die site noch nicht geparsed / geladen. In diesem Fall kann der $request aus der MiddleWare übergeben werden, um die Site zu ermitteln.

$config = \nn\t3::Settings()->getSiteConfig();
$config = \nn\t3::Settings()->getSiteConfig( $request );
Copied!

| @return array

Source Code 

public function getSiteConfig( $request = null )
{
	$site = \nn\t3::Environment()->getSite();
	if (!$site) return [];
	if (!is_a($site, \TYPO3\CMS\Core\Site\Entity\NullSite::class)) {
		return $site->getConfiguration() ?? [];
	}
	return [];
}
Copied!

Settings::getStoragePid() 

\nn\t3::Settings()->getStoragePid($extName = NULL); 

Aktuelle (ERSTE) StoragePid für das aktuelle Plugin holen. Gespeichert im TypoScript-Setup der Extension unter | plugin.tx_extname.persistence.storagePid bzw. im FlexForm des Plugins auf der jeweiligen Seite.

WICHTIG: Merge mit gewählter StoragePID aus dem FlexForm passiert nur, wenn $extNameleer gelassen wird.

\nn\t3::Settings()->getStoragePid();         // 123
\nn\t3::Settings()->getStoragePid('nnsite');   // 466
Copied!

| @return string

Source Code 

public function getStoragePid ( $extName = null )
{
	$pids = $this->getStoragePids( $extName );
	return array_pop( $pids );
}
Copied!

Settings::getStoragePids() 

\nn\t3::Settings()->getStoragePids($extName = NULL, $recursive = 0); 

ALLE storagePids für das aktuelle Plugin holen. Gespeichert als komma-separierte Liste im TypoScript-Setup der Extension unter | plugin.tx_extname.persistence.storagePid bzw. im FlexForm des Plugins auf der jeweiligen Seite.

WICHTIG: Merge mit gewählter StoragePID aus dem FlexForm passiert nur, wenn $extNameleer gelassen wird.

\nn\t3::Settings()->getStoragePids();                    // [123, 466]
\nn\t3::Settings()->getStoragePids('nnsite');          // [123, 466]
Copied!

Auch die child-PageUids holen? | true nimmt den Wert für "Rekursiv" aus dem FlexForm bzw. aus dem TypoScript der Extension von plugin.tx_extname.persistence.recursive

\nn\t3::Settings()->getStoragePids(true);                // [123, 466, 124, 467, 468]
\nn\t3::Settings()->getStoragePids('nnsite', true);        // [123, 466, 124, 467, 468]
Copied!

Alternativ kann für die Tiefe / Rekursion auch ein numerischer Wert übergeben werden.

\nn\t3::Settings()->getStoragePids(2);               // [123, 466, 124, 467, 468]
\nn\t3::Settings()->getStoragePids('nnsite', 2);       // [123, 466, 124, 467, 468]
Copied!

| @return array

Source Code 

public function getStoragePids ( $extName = null, $recursive = 0 )
{
	// numerischer Wert: ->getStoragePids( 3 ) oder Boolean: ->getStoragePids( true )
	if (is_numeric($extName) || $extName === true ) {
		$recursive = $extName;
		$extName = null;
	}
	// $cObjData nur holen, falls kein extName angegeben wurde
	$cObjData = $extName === null ? [] : \nn\t3::Tsfe()->cObjData();
	$setup = $this->getPlugin( $extName  );
	// Wenn `recursive = true`, dann Wert aus FlexForm bzw. TypoScript nehmen
	$recursive = $recursive === true ? ($cObjData['recursive'] ?? $setup['persistence']['recursive'] ?? false) : $recursive;
	$pids = $cObjData['pages'] ?? $setup['persistence']['storagePid'] ?? '';
	$pids = \nn\t3::Arrays( $pids )->intExplode();
	// Child-Uids ergänzen?
	$childList = $recursive > 0 ? \nn\t3::Page()->getChildPids( $pids, $recursive ) : [];
	return array_merge( $pids, $childList );
}
Copied!

Settings::parseTypoScriptForPage() 

\nn\t3::Settings()->parseTypoScriptForPage($pageUid = 0, $request = NULL); 

TypoScript für bestimmte pageUid parsen.

Gibt die Notation mit Punkten zurück. Das kann per | \nn\t3::TypoScript()->convertToPlainArray() in ein normales Array umgewandelt werden.

// TypoScript für aktuelle pageUid holen
\nn\t3::Settings()->parseTypoScriptForPage();

// TypoScript für bestimmte pageUid holen
\nn\t3::Settings()->parseTypoScriptForPage(123);
Copied!
@param int $pid PageUid
@param ServerRequestInterface $request
@return array

Source Code 

public function parseTypoScriptForPage($pageUid = 0, $request = null): array
{
	if (!$pageUid) {
		$pageUid = \nn\t3::Page()->getPid();
	}
	$helper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TypoScriptHelper::class );
	$result = $helper->getTypoScript( $pageUid );
	return $result;
}
Copied!

Settings::setExtConf() 

\nn\t3::Settings()->setExtConf($extName = '', $key = '', $value = ''); 

Extension-Konfiguration schreiben. Schreibt eine Extension-Konfiguration in die LocalConfiguration.php. Die Werte können bei entsprechender Konfiguration in der ext_conf_template.txt auch über den Extension-Manager / die Extension Konfiguration im Backend bearbeitet werden.

\nn\t3::Settings()->setExtConf( 'extname', 'key', 'value' );
Copied!

| @return mixed

Source Code 

public function setExtConf( $extName = '', $key = '', $value = '' )
{
	$coreConfigurationManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
	$result = $coreConfigurationManager->setLocalConfigurationValueByPath("EXTENSIONS/{$extName}/{$key}", $value);
	return $result;
}
Copied!

Slug 

\nn\t3::Slug() 

URL-Pfade (Slug) generieren und manipulieren

Overview of Methods 

\nn\t3::Slug()->create($model); 

Generiert einen slug (URL-Pfad) für ein Model. Ermittelt automatisch das TCA-Feld für den Slug.

\nn\t3::Slug()->create( $model );
Copied!

| @return string

| ➜ Go to source code of Slug::create()

Methods 

Slug::create() 

\nn\t3::Slug()->create($model); 

Generiert einen slug (URL-Pfad) für ein Model. Ermittelt automatisch das TCA-Feld für den Slug.

\nn\t3::Slug()->create( $model );
Copied!

| @return string

Source Code 

public function create( $model )
{
	if (!$model) return false;
	\nn\t3::Db()->persistAll();
	$uid = $model->getUid();
	if (!$uid) return false;
	$tableName = \nn\t3::Db()->getTableNameForModel( $model );
	$record = \nn\t3::Db()->findByUid( $tableName, $uid, true);
	$slugField = array_shift(\nn\t3::Db()->getColumnsByType( $tableName, 'slug' ));
	$slugFieldName = $slugField['fieldName'] ?? false;
	if (!$slugFieldName) return;
	$fieldConfig = $slugField['config'];
	$evalInfo = GeneralUtility::trimExplode(',', $fieldConfig['eval'], true);
	$slugHelper = GeneralUtility::makeInstance( SlugHelper::class, $tableName, $slugFieldName, $fieldConfig );
	$slug = $slugHelper->generate($record, $record['pid']);
	$state = RecordStateFactory::forName($tableName)
		->fromArray($record, $record['pid'], $record['uid']);
	if (in_array('uniqueInSite', $evalInfo)) {
		$slug = $slugHelper->buildSlugForUniqueInSite($slug, $state);
	} else if (in_array('uniqueInPid', $evalInfo)) {
		$slug = $slugHelper->buildSlugForUniqueInPid($slug, $state);
	} else if (in_array('unique', $evalInfo)) {
		$slug = $slugHelper->buildSlugForUniqueInTable($slug, $state);
	}
	\nn\t3::Obj()->set( $model, $slugFieldName, $slug );
	\nn\t3::Db()->update( $tableName, [$slugFieldName=>$slug], $uid);
	return $model;
}
Copied!

Storage 

\nn\t3::Storage() 

Alles rund um Storages

Overview of Methods 

\nn\t3::Storage()->clearStorageRowCache(); 

Löscht den StorageRowCache

\nn\t3::Storage()->clearStorageRowCache();
Copied!

| @return void

| ➜ Go to source code of Storage::clearStorageRowCache()

\nn\t3::Storage()->getFolder($file, $storage = NULL); 

Gibt den Folder-Object für einen Zielordner (oder Datei) innerhalb einer Storage zurück. Legt Ordner an, falls er noch nicht existiert

Beispiele:

\nn\t3::Storage()->getFolder( 'fileadmin/test/beispiel.txt' );
\nn\t3::Storage()->getFolder( 'fileadmin/test/' );
        ==>  gibt \Folder-Object für den Ordner 'test/' zurück
Copied!

| @return Folder

| ➜ Go to source code of Storage::getFolder()

\nn\t3::Storage()->getPid($extName = NULL); 

Im Controller: Aktuelle StoragePid für ein PlugIn holen. Alias zu \nn\t3::Settings()->getStoragePid()

\nn\t3::Storage()->getPid();
\nn\t3::Storage()->getPid('news');
Copied!

| @return string

| ➜ Go to source code of Storage::getPid()

Methods 

Storage::clearStorageRowCache() 

\nn\t3::Storage()->clearStorageRowCache(); 

Löscht den StorageRowCache

\nn\t3::Storage()->clearStorageRowCache();
Copied!

| @return void

Source Code 

public function clearStorageRowCache ()
{
	$this->storageRowCache = NULL;
	$this->initializeLocalCache();
}
Copied!

Storage::getFolder() 

\nn\t3::Storage()->getFolder($file, $storage = NULL); 

Gibt den Folder-Object für einen Zielordner (oder Datei) innerhalb einer Storage zurück. Legt Ordner an, falls er noch nicht existiert

Beispiele:

\nn\t3::Storage()->getFolder( 'fileadmin/test/beispiel.txt' );
\nn\t3::Storage()->getFolder( 'fileadmin/test/' );
        ==>  gibt \Folder-Object für den Ordner 'test/' zurück
Copied!

| @return Folder

Source Code 

public function getFolder( $file, $storage = null )
{
	$storage = $storage ?: \nn\t3::File()->getStorage( $file );
	if (!$storage) return false;
	$storageConfiguration = $storage->getConfiguration();
	$dirname = \nn\t3::File()->getFolder($file);
	$folderPathInStorage = substr($dirname, strlen($storageConfiguration['basePath']));
	// Ordner existiert bereits
	if ($storage->hasFolder($folderPathInStorage)) return $storage->getFolder( $folderPathInStorage );
	// Ordner muss angelegt werden
	return $storage->createFolder($folderPathInStorage);
}
Copied!

Storage::getPid() 

\nn\t3::Storage()->getPid($extName = NULL); 

Im Controller: Aktuelle StoragePid für ein PlugIn holen. Alias zu \nn\t3::Settings()->getStoragePid()

\nn\t3::Storage()->getPid();
\nn\t3::Storage()->getPid('news');
Copied!

| @return string

Source Code 

public function getPid ( $extName = null )
{
	return \nn\t3::Settings()->getStoragePid( $extName );
}
Copied!

SysCategory 

\nn\t3::SysCategory() 

Vereinfacht die Arbeit und den Zugriff auf die sys_category von Typo3

Overview of Methods 

\nn\t3::SysCategory()->findAll($branchUid = NULL); 

Liste aller sys_categories holen

\nn\t3::SysCategory()->findAll();
Copied!

| @return array

| ➜ Go to source code of SysCategory::findAll()

\nn\t3::SysCategory()->findAllByUid($branchUid = NULL); 

Liste aller sys_categories holen, uid als Key zurückgeben

\nn\t3::SysCategory()->findAllByUid();
Copied!

| @return array

| ➜ Go to source code of SysCategory::findAllByUid()

\nn\t3::SysCategory()->findByUid($uidList = NULL); 

sys_categories anhand von uid(s) holen.

\nn\t3::SysCategory()->findByUid( 12 );
\nn\t3::SysCategory()->findByUid( '12,11,5' );
\nn\t3::SysCategory()->findByUid( [12, 11, 5] );
Copied!

| @return array|\TYPO3\CMS\Extbase\Domain\Model\Category

| ➜ Go to source code of SysCategory::findByUid()

\nn\t3::SysCategory()->getTree($branchUid = NULL); 

Den gesamten SysCategory-Baum (als Array) holen. Jeder Knotenpunkt hat die Attribute 'parent' und 'children', um rekursiv durch Baum iterieren zu können.

// Gesamten Baum holen
\nn\t3::SysCategory()->getTree();

// Bestimmten Ast des Baums holen
\nn\t3::SysCategory()->getTree( $uid );

// Alle Äste des Baums holen, key ist die UID der SysCategory
\nn\t3::SysCategory()->getTree( true );
Copied!

ToDo: Prüfen, ob Caching sinnvoll ist

| @return array

| ➜ Go to source code of SysCategory::getTree()

Methods 

SysCategory::findAll() 

\nn\t3::SysCategory()->findAll($branchUid = NULL); 

Liste aller sys_categories holen

\nn\t3::SysCategory()->findAll();
Copied!

| @return array

Source Code 

public function findAll ( $branchUid = null )
{
	$categoryRepository = \nn\t3::injectClass( CategoryRepository::class );
	$allCategories = $categoryRepository->findAll();
	return $allCategories;
}
Copied!

SysCategory::findAllByUid() 

\nn\t3::SysCategory()->findAllByUid($branchUid = NULL); 

Liste aller sys_categories holen, uid als Key zurückgeben

\nn\t3::SysCategory()->findAllByUid();
Copied!

| @return array

Source Code 

public function findAllByUid ( $branchUid = null )
{
	$allCategories = $this->findAll( $branchUid );
	$allCategoriesByUid = [];
	foreach ($allCategories as $cat) {
		$allCategoriesByUid[$cat->getUid()] = $cat;
	}
	return $allCategoriesByUid;
}
Copied!

SysCategory::findByUid() 

\nn\t3::SysCategory()->findByUid($uidList = NULL); 

sys_categories anhand von uid(s) holen.

\nn\t3::SysCategory()->findByUid( 12 );
\nn\t3::SysCategory()->findByUid( '12,11,5' );
\nn\t3::SysCategory()->findByUid( [12, 11, 5] );
Copied!

| @return array|\TYPO3\CMS\Extbase\Domain\Model\Category

Source Code 

public function findByUid( $uidList = null )
{
	$returnFirst = !is_array($uidList) && is_numeric($uidList);
	$uidList = \nn\t3::Arrays($uidList)->intExplode();
	$allCategoriesByUid = $this->findAllByUid();
	$result = [];
	foreach ($uidList as $uid) {
		if ($cat = $allCategoriesByUid[$uid]) {
			$result[$uid] = $cat;
		}
	}
	return $returnFirst ? array_shift($result) : $result;
}
Copied!

SysCategory::getTree() 

\nn\t3::SysCategory()->getTree($branchUid = NULL); 

Den gesamten SysCategory-Baum (als Array) holen. Jeder Knotenpunkt hat die Attribute 'parent' und 'children', um rekursiv durch Baum iterieren zu können.

// Gesamten Baum holen
\nn\t3::SysCategory()->getTree();

// Bestimmten Ast des Baums holen
\nn\t3::SysCategory()->getTree( $uid );

// Alle Äste des Baums holen, key ist die UID der SysCategory
\nn\t3::SysCategory()->getTree( true );
Copied!

ToDo: Prüfen, ob Caching sinnvoll ist

| @return array

Source Code 

public function getTree ( $branchUid = null )
{
	// Alle Kategorien laden
	$allCategories = $this->findAll();
	// Array mit uid als Key erstellen
	$categoriesByUid = [0=>['children'=>[]]];
	foreach ($allCategories as $sysCategory) {
		// Object zu Array konvertieren
		$sysCatArray = \nn\t3::Obj()->toArray($sysCategory, 3);
		$sysCatArray['children'] = [];
		$sysCatArray['_parent'] = $sysCatArray['parent'];
		$categoriesByUid[$sysCatArray['uid']] = $sysCatArray;
	}
	// Baum generieren
	foreach ($categoriesByUid as $uid=>$sysCatArray) {
		$parent = $sysCatArray['_parent'] ?? [];
		if (($parent['uid'] ?? false) != $uid) {
			$parentUid = $parent ? $parent['uid'] : 0;
			$categoriesByUid[$parentUid]['children'][$uid] = &$categoriesByUid[$uid];
			$categoriesByUid[$uid]['parent'] = $parentUid > 0 ? $categoriesByUid[$parentUid] : false;
			unset($categoriesByUid[$uid]['_parent']);
		}
	}
	// Wurzel
	$root = $categoriesByUid[0]['children'] ?? false ?: [];
	// Ganzen Baum – oder nur bestimmten Branch zurückgeben?
	if (!$branchUid) return $root;
	// Alle Äste holen
	if ($branchUid === true) {
		return $categoriesByUid;
	}
	// bestimmten Branch holen
	return $categoriesByUid[$branchUid] ?? false ?: [];
}
Copied!

TCA 

\nn\t3::TCA() 

Methoden für die Konfiguration und den Zugriff auf Felder im TCA.

Overview of Methods 

\nn\t3::TCA()->addModuleOptionToPage($label, $identifier, $iconIdentifier = ''); 

In den Seiteneigenschaften unter "Verhalten -> Enthält Erweiterung" eine Auswahl-Option hinzufügen. Klassischerweise in Configuration/TCA/Overrides/pages.php genutzt, früher in ext_tables.php

// In ext_localconf.php das Icon registrieren (16 x 16 px SVG)
\nn\t3::Registry()->icon('icon-identifier', 'EXT:myext/Resources/Public/Icons/module.svg');

// In Configuration/TCA/Overrides/pages.php
\nn\t3::TCA()->addModuleOptionToPage('Beschreibung', 'identifier', 'icon-identifier');
Copied!

| @return void

| ➜ Go to source code of TCA::addModuleOptionToPage()

\nn\t3::TCA()->createConfig($tablename = '', $basics = [], $custom = []); 

Basis-Konfiguration für das TCA holen. Das sind die Felder wie hidden, starttime etc., die bei (fast) allen Tabellen immer gleich sind.

ALLE typischen Felder holen:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry', true,
    ['title'=>...]
)
Copied!

Nur bestimmte Felder holen:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry',
    ['sys_language_uid', 'l10n_parent', 'l10n_source', 'l10n_diffsource', 'hidden', 'cruser_id', 'pid', 'crdate', 'tstamp', 'sorting', 'starttime', 'endtime', 'fe_group'],
    ['title'=>...]
)
Copied!

| @return array

| ➜ Go to source code of TCA::createConfig()

\nn\t3::TCA()->getColorPickerTCAConfig(); 

Color Picker Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getColorPickerTCAConfig(),
Copied!

| @return array

| ➜ Go to source code of TCA::getColorPickerTCAConfig()

\nn\t3::TCA()->getColumn($tableName = '', $fieldName = '', $useSchemaManager = false); 

Holt Konfigurations-Array für ein Feld aus dem TCA. Alias zu \nn\t3::Db()->getColumn()

\nn\t3::TCA()->getColumn( 'pages', 'media' );
Copied!

| @return array

| ➜ Go to source code of TCA::getColumn()

\nn\t3::TCA()->getColumns($tableName = '', $useSchemaManager = false); 

Holt Konfigurations-Array für eine Tabelle aus dem TCA. Alias zu \nn\t3::Db()->getColumns()

\nn\t3::TCA()->getColumns( 'pages' );
Copied!

| @return array

| ➜ Go to source code of TCA::getColumns()

\nn\t3::TCA()->getConfig($path = ''); 

Eine Konfiguration aus dem TCA holen für einen Pfad holen. Liefert eine Referenz zu dem config-Array des ensprechenden Feldes zurück.

\nn\t3::TCA()->getConfig('tt_content.columns.tx_mask_iconcollection');
Copied!

| @return array

| ➜ Go to source code of TCA::getConfig()

\nn\t3::TCA()->getConfigForType($type = '', $override = []); 

Default Konfiguration für verschiedene, typische types im TCA holen. Dient als eine Art Alias, um die häufigst verwendeten config-Arrays schneller und kürzer schreiben zu können

\nn\t3::TCA()->getConfigForType( 'pid' );             // => ['type'=>'group', 'allowed'=>'pages', 'maxItems'=>1]
\nn\t3::TCA()->getConfigForType( 'contentElement' ); // => ['type'=>'group', 'allowed'=>'tt_content', 'maxItems'=>1]
\nn\t3::TCA()->getConfigForType( 'text' );           // => ['type'=>'text', 'rows'=>2, ...]
\nn\t3::TCA()->getConfigForType( 'rte' );            // => ['type'=>'text', 'enableRichtext'=>'true', ...]
\nn\t3::TCA()->getConfigForType( 'color' );          // => ['type'=>'color', ...]
\nn\t3::TCA()->getConfigForType( 'fal', 'image' );   // => ['type'=>'file', ...]
Copied!

Default-Konfigurationen können einfach überschrieben / erweitert werden:

\nn\t3::TCA()->getConfigForType( 'text', ['rows'=>5] );   // => ['type'=>'text', 'rows'=>5, ...]
Copied!

Für jeden Typ lässt sich der am häufigsten überschriebene Wert im config-Array auch per Übergabe eines fixen Wertes statt eines override-Arrays setzen:

\nn\t3::TCA()->getConfigForType( 'pid', 3 );               // => ['maxItems'=>3, ...]
\nn\t3::TCA()->getConfigForType( 'contentElement', 3 );    // => ['maxItems'=>3, ...]
\nn\t3::TCA()->getConfigForType( 'text', 10 );         // => ['rows'=>10, ...]
\nn\t3::TCA()->getConfigForType( 'rte', 'myRteConfig' ); // => ['richtextConfiguration'=>'myRteConfig', ...]
\nn\t3::TCA()->getConfigForType( 'color', '#ff6600' );   // => ['default'=>'#ff6600', ...]
\nn\t3::TCA()->getConfigForType( 'fal', 'image' );       // => [ config für das Feld mit dem Key `image` ]
Copied!

| @return array

| ➜ Go to source code of TCA::getConfigForType()

\nn\t3::TCA()->getFalFields($tableName = ''); 

Holt alle Feldnamen aus dem TCA-Array, die eine SysFileReference-Relation haben. Bei der Tabelle tt_content wären das z.B. assets, media etc.

\nn\t3::TCA()->getFalFields( 'pages' );    // => ['media', 'assets', 'image']
Copied!

| @return array

| ➜ Go to source code of TCA::getFalFields()

\nn\t3::TCA()->getFileFieldTCAConfig($fieldName = 'media', $override = []); 

FAL Konfiguration für das TCA holen.

Standard-Konfig inkl. Image-Cropper, Link und alternativer Bildtitel Diese Einstellung ändert sich regelmäßig, was bei der Menge an Parametern und deren wechselnden Position im Array eine ziemliche Zumutung ist.

https://bit.ly/2SUvASe

\nn\t3::TCA()->getFileFieldTCAConfig('media');
\nn\t3::TCA()->getFileFieldTCAConfig('media', ['maxitems'=>1, 'fileExtensions'=>'jpg']);
Copied!

Wird im TCA so eingesetzt:

'falprofileimage' => [
    'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage', ['maxitems'=>1]),
],
Copied!

| @return array

| ➜ Go to source code of TCA::getFileFieldTCAConfig()

\nn\t3::TCA()->getRteTCAConfig(); 

RTE Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getRteTCAConfig(),
Copied!

| @return array

| ➜ Go to source code of TCA::getRteTCAConfig()

\nn\t3::TCA()->getSlugTCAConfig($fields = []); 

Standard-Slug Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getSlugTCAConfig( 'title' )
'config' => \nn\t3::TCA()->getSlugTCAConfig( ['title', 'header'] )
Copied!
@param array|string $fields
@return array

| ➜ Go to source code of TCA::getSlugTCAConfig()

\nn\t3::TCA()->insertCountries($config, $a = NULL); 

Fügt Liste der Länder in ein TCA ein. Alias zu nnt3::Flexform->insertCountries( $config, $a = null ); Beschreibung und weitere Beispiele dort.

Beispiel im TCA:

'config' => [
    'type' => 'select',
    'itemsProcFunc' => 'nn\t3\Flexform->insertCountries',
    'insertEmpty' => true,
]
Copied!

| @return array

| ➜ Go to source code of TCA::insertCountries()

\nn\t3::TCA()->insertFlexform($path); 

Fügt ein Flexform in ein TCA ein.

Beispiel im TCA:

'config' => \nn\t3::TCA()->insertFlexform('FILE:EXT:nnsite/Configuration/FlexForm/slickslider_options.xml');
Copied!

| @return array

| ➜ Go to source code of TCA::insertFlexform()

\nn\t3::TCA()->insertOptions($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein TCA ein. Alias zu nnt3::Flexform->insertOptions( $config, $a = null ); Beschreibung und weitere Beispiele dort.

Beispiel im TCA:

'config' => [
    'type' => 'select',
    'itemsProcFunc' => 'nn\t3\Flexform->insertOptions',
    'typoscriptPath' => 'plugin.tx_nnnewsroom.settings.templates',
    //'pageconfigPath' => 'tx_nnnewsroom.colors',
]
Copied!

| @return array

| ➜ Go to source code of TCA::insertOptions()

\nn\t3::TCA()->setConfig($path = '', $override = []); 

Eine Konfiguration des TCA überschreiben, z.B. um ein mask-Feld mit einem eigenen renderType zu überschreiben oder Core-Einstellungen im TCA an den Tabellen pages oder tt_content zu ändern.

Folgendes Beispiel setzt/überschreibt im TCA das config-Array unter:

$GLOBALS['TCA']['tt_content']['columns']['mycol']['config'][...]
Copied!
\nn\t3::TCA()->setConfig('tt_content.columns.mycol', [
    'renderType' => 'nnsiteIconCollection',
    'iconconfig' => 'tx_nnsite.iconcollection',
]);
Copied!

Siehe auch \nn\t3::TCA()->setContentConfig() für eine Kurzfassung dieser Methode, wenn es um die Tabelle tt_content geht und \nn\t3::TCA()->setPagesConfig() für die Tabelle pages

| @return array

| ➜ Go to source code of TCA::setConfig()

\nn\t3::TCA()->setContentConfig($field = '', $override = [], $shortParams = NULL); 

Eine Konfiguration des TCA für die Tabelle tt_content setzen oder überschreiben.

Diese Beispiel überschreibt im TCA das config-Array der Tabelle tt_content für:

$GLOBALS['TCA']['tt_content']['columns']['title']['config'][...]
Copied!
\nn\t3::TCA()->setContentConfig( 'header', 'text' );     // ['type'=>'text', 'rows'=>2]
\nn\t3::TCA()->setContentConfig( 'header', 'text', 10 ); // ['type'=>'text', 'rows'=>10]
\nn\t3::TCA()->setContentConfig( 'header', ['type'=>'text', 'rows'=>10] ); // ['type'=>'text', 'rows'=>10]
Copied!

| @return array

| ➜ Go to source code of TCA::setContentConfig()

\nn\t3::TCA()->setPagesConfig($field = '', $override = [], $shortParams = NULL); 

Eine Konfiguration des TCA für die Tabelle pages setzen oder überschreiben.

Diese Beispiel überschreibt im TCA das config-Array der Tabelle pages für:

$GLOBALS['TCA']['pages']['columns']['title']['config'][...]
Copied!
\nn\t3::TCA()->setPagesConfig( 'title', 'text' );            // ['type'=>'text', 'rows'=>2]
\nn\t3::TCA()->setPagesConfig( 'title', 'text', 10 );        // ['type'=>'text', 'rows'=>10]
\nn\t3::TCA()->setPagesConfig( 'title', ['type'=>'text', 'rows'=>2] ); // ['type'=>'text', 'rows'=>2]
Copied!

| @return array

| ➜ Go to source code of TCA::setPagesConfig()

Methods 

TCA::addModuleOptionToPage() 

\nn\t3::TCA()->addModuleOptionToPage($label, $identifier, $iconIdentifier = ''); 

In den Seiteneigenschaften unter "Verhalten -> Enthält Erweiterung" eine Auswahl-Option hinzufügen. Klassischerweise in Configuration/TCA/Overrides/pages.php genutzt, früher in ext_tables.php

// In ext_localconf.php das Icon registrieren (16 x 16 px SVG)
\nn\t3::Registry()->icon('icon-identifier', 'EXT:myext/Resources/Public/Icons/module.svg');

// In Configuration/TCA/Overrides/pages.php
\nn\t3::TCA()->addModuleOptionToPage('Beschreibung', 'identifier', 'icon-identifier');
Copied!

| @return void

Source Code 

public function addModuleOptionToPage( $label, $identifier, $iconIdentifier = '')
{
	// Auswahl-Option hinzufügen
	$GLOBALS['TCA']['pages']['columns']['module']['config']['items'][] = [
		0 => $label,
		1 => $identifier,
		2 => $iconIdentifier
	];
	// Icon im Seitenbaum verwenden
	if ($iconIdentifier) {
		$GLOBALS['TCA']['pages']['ctrl']['typeicon_classes']['contains-'.$identifier] = $iconIdentifier;
	}
}
Copied!

TCA::createConfig() 

\nn\t3::TCA()->createConfig($tablename = '', $basics = [], $custom = []); 

Basis-Konfiguration für das TCA holen. Das sind die Felder wie hidden, starttime etc., die bei (fast) allen Tabellen immer gleich sind.

ALLE typischen Felder holen:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry', true,
    ['title'=>...]
)
Copied!

Nur bestimmte Felder holen:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry',
    ['sys_language_uid', 'l10n_parent', 'l10n_source', 'l10n_diffsource', 'hidden', 'cruser_id', 'pid', 'crdate', 'tstamp', 'sorting', 'starttime', 'endtime', 'fe_group'],
    ['title'=>...]
)
Copied!

| @return array

Source Code 

public function createConfig( $tablename = '', $basics = [], $custom = [] )
{
	if ($basics === true) {
		$basics = ['sys_language_uid', 'l10n_parent', 'l10n_source', 'l10n_diffsource', 'hidden', 'cruser_id', 'pid', 'crdate', 'tstamp', 'sorting', 'starttime', 'endtime', 'fe_group'];
	}
	$defaults = [
		'sys_language_uid' => [
			'exclude' => true,
			'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
			'config' => [
				'type' => 'language',
				'renderType' => 'selectSingle',
				'special' => 'languages',
				'items' => [
					[
						'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.allLanguages',
						'value' => -1,
						'iconIdentifierChecked' => 'flags-multiple'
					],
				],
				'default' => 0,
			]
		],
		'l10n_parent' => [
			'displayCond' => 'FIELD:sys_language_uid:>:0',
			'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
			'config' => [
				'type' => 'group',
				'allowed' => $tablename,
				'size' => 1,
				'maxitems' => 1,
				'minitems' => 0,
				'default' => 0,
			],
		],
		'l10n_source' => [
			'config' => [
				'type' => 'passthrough'
			]
		],
		'l10n_diffsource' => [
			'config' => [
				'type' => 'passthrough',
				'default' => ''
			]
		],
		'hidden' => [
			'exclude' => true,
			'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hidden',
			'config' => [
				'type' => 'check',
				'renderType' => 'checkboxToggle',
				'default' => 0,
				'items' => [
					[
						'label' => '',
						'value' => '',
					]
				],
			]
		],
		'cruser_id' => [
			'label' => 'cruser_id',
			'config' => [
				'type' => 'passthrough'
			]
		],
		'pid' => [
			'label' => 'pid',
			'config' => [
				'type' => 'passthrough'
			]
		],
		'crdate' => [
			'label' => 'crdate',
			'config' => [
				'type' => 'input',
			]
		],
		'tstamp' => [
			'label' => 'tstamp',
			'config' => [
				'type' => 'input',
			]
		],
		'sorting' => [
			'label' => 'sorting',
			'config' => [
				'type' => 'passthrough',
			]
		],
		'starttime' => [
			'exclude' => true,
			'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:starttime_formlabel',
			'config' => [
				'type' => 'datetime',
				'default' => 0,
				'behaviour' => [
					'allowLanguageSynchronization' => true,
				],
			]
		],
		'endtime' => [
			'exclude' => true,
			'label' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:endtime_formlabel',
			'config' => [
				'type' => 'datetime',
				'default' => 0,
				'range' => [
					'upper' => mktime(0, 0, 0, 1, 1, 2038),
				],
				'behaviour' => [
					'allowLanguageSynchronization' => true,
				],
			]
		],
		'fe_group' => [
			'exclude' => true,
			'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.fe_group',
			'config' => [
				'type' => 'select',
				'renderType' => 'selectMultipleSideBySide',
				'size' => 5,
				'maxitems' => 20,
				'items' => [
					[
						'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.hide_at_login',
						'value' => -1,
					],
					[
						'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.any_login',
						'value' => -2,
					],
					[
						'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.usergroups',
						'value' => '--div--',
					],
				],
				'exclusiveKeys' => '-1,-2',
				'foreign_table' => 'fe_groups',
				'foreign_table_where' => 'ORDER BY fe_groups.title',
			],
		],
	];
	$result = [];
	foreach ($basics as $key) {
		if ($config = $defaults[$key] ?? false) {
			$result[$key] = $config;
		}
	}
	return array_merge( $result, $custom );
}
Copied!

TCA::getColorPickerTCAConfig() 

\nn\t3::TCA()->getColorPickerTCAConfig(); 

Color Picker Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getColorPickerTCAConfig(),
Copied!

| @return array

Source Code 

public function getColorPickerTCAConfig()
{
	return [
		'type' => 'input',
		'renderType' => 'colorpicker',
		'size' => 10,
	];
}
Copied!

TCA::getColumn() 

\nn\t3::TCA()->getColumn($tableName = '', $fieldName = '', $useSchemaManager = false); 

Holt Konfigurations-Array für ein Feld aus dem TCA. Alias zu \nn\t3::Db()->getColumn()

\nn\t3::TCA()->getColumn( 'pages', 'media' );
Copied!

| @return array

Source Code 

public function getColumn( $tableName = '', $fieldName = '', $useSchemaManager = false)
{
	return \nn\t3::Db()->getColumn( $tableName, $fieldName, $useSchemaManager );
}
Copied!

TCA::getColumns() 

\nn\t3::TCA()->getColumns($tableName = '', $useSchemaManager = false); 

Holt Konfigurations-Array für eine Tabelle aus dem TCA. Alias zu \nn\t3::Db()->getColumns()

\nn\t3::TCA()->getColumns( 'pages' );
Copied!

| @return array

Source Code 

public function getColumns( $tableName = '', $useSchemaManager = false)
{
	return \nn\t3::Db()->getColumns( $tableName, $useSchemaManager );
}
Copied!

TCA::getConfig() 

\nn\t3::TCA()->getConfig($path = ''); 

Eine Konfiguration aus dem TCA holen für einen Pfad holen. Liefert eine Referenz zu dem config-Array des ensprechenden Feldes zurück.

\nn\t3::TCA()->getConfig('tt_content.columns.tx_mask_iconcollection');
Copied!

| @return array

Source Code 

public function &getConfig( $path = '' ) {
	$parts = \nn\t3::Arrays($path)->trimExplode('.');
	$ref = &$GLOBALS['TCA'];
	while (count($parts) > 0) {
		$part = array_shift($parts);
		$ref = &$ref[$part];
	}
	$ref = &$ref['config'];
	return $ref;
}
Copied!

TCA::getConfigForType() 

\nn\t3::TCA()->getConfigForType($type = '', $override = []); 

Default Konfiguration für verschiedene, typische types im TCA holen. Dient als eine Art Alias, um die häufigst verwendeten config-Arrays schneller und kürzer schreiben zu können

\nn\t3::TCA()->getConfigForType( 'pid' );             // => ['type'=>'group', 'allowed'=>'pages', 'maxItems'=>1]
\nn\t3::TCA()->getConfigForType( 'contentElement' ); // => ['type'=>'group', 'allowed'=>'tt_content', 'maxItems'=>1]
\nn\t3::TCA()->getConfigForType( 'text' );           // => ['type'=>'text', 'rows'=>2, ...]
\nn\t3::TCA()->getConfigForType( 'rte' );            // => ['type'=>'text', 'enableRichtext'=>'true', ...]
\nn\t3::TCA()->getConfigForType( 'color' );          // => ['type'=>'color', ...]
\nn\t3::TCA()->getConfigForType( 'fal', 'image' );   // => ['type'=>'file', ...]
Copied!

Default-Konfigurationen können einfach überschrieben / erweitert werden:

\nn\t3::TCA()->getConfigForType( 'text', ['rows'=>5] );   // => ['type'=>'text', 'rows'=>5, ...]
Copied!

Für jeden Typ lässt sich der am häufigsten überschriebene Wert im config-Array auch per Übergabe eines fixen Wertes statt eines override-Arrays setzen:

\nn\t3::TCA()->getConfigForType( 'pid', 3 );               // => ['maxItems'=>3, ...]
\nn\t3::TCA()->getConfigForType( 'contentElement', 3 );    // => ['maxItems'=>3, ...]
\nn\t3::TCA()->getConfigForType( 'text', 10 );         // => ['rows'=>10, ...]
\nn\t3::TCA()->getConfigForType( 'rte', 'myRteConfig' ); // => ['richtextConfiguration'=>'myRteConfig', ...]
\nn\t3::TCA()->getConfigForType( 'color', '#ff6600' );   // => ['default'=>'#ff6600', ...]
\nn\t3::TCA()->getConfigForType( 'fal', 'image' );       // => [ config für das Feld mit dem Key `image` ]
Copied!

| @return array

Source Code 

public function getConfigForType( $type = '', $override = [] )
{
	if (is_array($type)) return $type;
	// Fixer Wert statt Array in `override`? Für welches Key im `config`-Array verwenden?
	$overrideKey = false;
	switch ($type) {
		case 'pid':
			$config = ['type'=>'group', 'allowed'=>'pages', 'size' => 1, 'maxItems'=>1];
			$overrideKey = 'maxItems';
			break;
		case 'cid':
		case 'contentElement':
			$config = ['type'=>'group', 'allowed'=>'tt_content', 'size' => 1, 'maxItems'=>1];
			$overrideKey = 'maxItems';
			break;
		case 'text':
			$config = ['type'=>'text', 'rows'=>2, 'cols'=>50];
			$overrideKey = 'rows';
			break;
		case 'color':
			$config = \nn\t3::TCA()->getColorPickerTCAConfig();
			$overrideKey = 'default';
			break;
		case 'rte':
			$config = \nn\t3::TCA()->getRteTCAConfig();
			$overrideKey = 'richtextConfiguration';
			break;
		case 'fal':
			if (!$override) \nn\t3::Exception('`field` muss definiert sein!');
			if (is_string($override)) $override = ['field'=>$override];
			$config = \nn\t3::TCA()->getFileFieldTCAConfig( $override['field'], $override );
			break;
		default:
			$config = [];
	}
	if ($override) {
		if (!is_array($override) && $overrideKey) {
			$override = [$overrideKey=>$override];
		}
		$config = \nn\t3::Arrays()->merge( $config, $override );
	}
	return $config;
}
Copied!

TCA::getFalFields() 

\nn\t3::TCA()->getFalFields($tableName = ''); 

Holt alle Feldnamen aus dem TCA-Array, die eine SysFileReference-Relation haben. Bei der Tabelle tt_content wären das z.B. assets, media etc.

\nn\t3::TCA()->getFalFields( 'pages' );    // => ['media', 'assets', 'image']
Copied!

| @return array

Source Code 

public function getFalFields( $tableName = '' )
{
	$fields = array_filter( \nn\t3::Db()->getColumns( $tableName ), function ( $item ) {
		return ($item['config']['foreign_table'] ?? false) == 'sys_file_reference';
	});
	return array_keys( $fields );
}
Copied!

TCA::getFileFieldTCAConfig() 

\nn\t3::TCA()->getFileFieldTCAConfig($fieldName = 'media', $override = []); 

FAL Konfiguration für das TCA holen.

Standard-Konfig inkl. Image-Cropper, Link und alternativer Bildtitel Diese Einstellung ändert sich regelmäßig, was bei der Menge an Parametern und deren wechselnden Position im Array eine ziemliche Zumutung ist.

https://bit.ly/2SUvASe

\nn\t3::TCA()->getFileFieldTCAConfig('media');
\nn\t3::TCA()->getFileFieldTCAConfig('media', ['maxitems'=>1, 'fileExtensions'=>'jpg']);
Copied!

Wird im TCA so eingesetzt:

'falprofileimage' => [
    'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage', ['maxitems'=>1]),
],
Copied!

| @return array

Source Code 

public function getFileFieldTCAConfig( $fieldName = 'media', $override = [] )
{
	// Vereinfachte Übergabe der Optionen
	$options = array_merge([
		'label' => 'LLL:EXT:frontend/Resources/Private/Language/Database.xlf:tt_content.asset_references',
		'maxitems' => 999,
		'fileExtensions' => 'common-media-types',
		// 'fileUploadAllowed' => true,
		// 'fileByUrlAllowed' => true,
	], $override);
	/*
	$config = [
		'label' => $options['label'],
		'appearance' => [
			'fileUploadAllowed' => $options['fileUploadAllowed'],
			'fileByUrlAllowed' => $options['fileByUrlAllowed'],
		],
		'config' => [
			'type' => 'file',
			'maxitems' => $options['maxitems'],
			'allowed' => $options['fileExtensions'],
		]
	];
	*/
	$config = [
		'type' => 'file',
		'maxitems' => $options['maxitems'],
		'allowed' => $options['fileExtensions'],
	];
	if ($childConfig = $options['overrideChildTca'] ?? false) {
		$config['overrideChildTca'] = $childConfig;
	}
	return $config;
}
Copied!

TCA::getRteTCAConfig() 

\nn\t3::TCA()->getRteTCAConfig(); 

RTE Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getRteTCAConfig(),
Copied!

| @return array

Source Code 

public function getRteTCAConfig()
{
	return [
		'type' => 'text',
		'enableRichtext' => true,
	];
}
Copied!

TCA::getSlugTCAConfig() 

\nn\t3::TCA()->getSlugTCAConfig($fields = []); 

Standard-Slug Konfiguration für das TCA holen.

'config' => \nn\t3::TCA()->getSlugTCAConfig( 'title' )
'config' => \nn\t3::TCA()->getSlugTCAConfig( ['title', 'header'] )
Copied!
@param array|string $fields
@return array

Source Code 

public function getSlugTCAConfig( $fields = [] )
{
	if (is_string($fields)) {
		$fields = [$fields];
	}
	return [
		'type' => 'slug',
		'size' => 50,
		'generatorOptions' => [
			'fields' => $fields,
			'replacements' => [
				'/' => '-'
			],
		],
		'fallbackCharacter' => '-',
		'eval' => 'unique',
		'default' => ''
	];
}
Copied!

TCA::insertCountries() 

\nn\t3::TCA()->insertCountries($config, $a = NULL); 

Fügt Liste der Länder in ein TCA ein. Alias zu nnt3::Flexform->insertCountries( $config, $a = null ); Beschreibung und weitere Beispiele dort.

Beispiel im TCA:

'config' => [
    'type' => 'select',
    'itemsProcFunc' => 'nn\t3\Flexform->insertCountries',
    'insertEmpty' => true,
]
Copied!

| @return array

Source Code 

public function insertCountries( $config, $a = null )
{
	return \nn\t3::Flexform()->insertCountries( $config, $a );
}
Copied!

TCA::insertFlexform() 

\nn\t3::TCA()->insertFlexform($path); 

Fügt ein Flexform in ein TCA ein.

Beispiel im TCA:

'config' => \nn\t3::TCA()->insertFlexform('FILE:EXT:nnsite/Configuration/FlexForm/slickslider_options.xml');
Copied!

| @return array

Source Code 

public function insertFlexform( $path )
{
	return [
		'type' 	=> 'flex',
		'ds' 	=> ['default' => $path],
	];
}
Copied!

TCA::insertOptions() 

\nn\t3::TCA()->insertOptions($config, $a = NULL); 

Fügt Optionen aus TypoScript zur Auswahl in ein TCA ein. Alias zu nnt3::Flexform->insertOptions( $config, $a = null ); Beschreibung und weitere Beispiele dort.

Beispiel im TCA:

'config' => [
    'type' => 'select',
    'itemsProcFunc' => 'nn\t3\Flexform->insertOptions',
    'typoscriptPath' => 'plugin.tx_nnnewsroom.settings.templates',
    //'pageconfigPath' => 'tx_nnnewsroom.colors',
]
Copied!

| @return array

Source Code 

public function insertOptions ( $config, $a = null )
{
	return \nn\t3::Flexform()->insertOptions( $config, $a );
}
Copied!

TCA::setConfig() 

\nn\t3::TCA()->setConfig($path = '', $override = []); 

Eine Konfiguration des TCA überschreiben, z.B. um ein mask-Feld mit einem eigenen renderType zu überschreiben oder Core-Einstellungen im TCA an den Tabellen pages oder tt_content zu ändern.

Folgendes Beispiel setzt/überschreibt im TCA das config-Array unter:

$GLOBALS['TCA']['tt_content']['columns']['mycol']['config'][...]
Copied!
\nn\t3::TCA()->setConfig('tt_content.columns.mycol', [
    'renderType' => 'nnsiteIconCollection',
    'iconconfig' => 'tx_nnsite.iconcollection',
]);
Copied!

Siehe auch \nn\t3::TCA()->setContentConfig() für eine Kurzfassung dieser Methode, wenn es um die Tabelle tt_content geht und \nn\t3::TCA()->setPagesConfig() für die Tabelle pages

| @return array

Source Code 

public function setConfig( $path = '', $override = [] )
{
	if ($config = &$this->getConfig( $path )) {
		$config = \nn\t3::Arrays()->merge( $config, $override );
	}
	return $config;
}
Copied!

TCA::setContentConfig() 

\nn\t3::TCA()->setContentConfig($field = '', $override = [], $shortParams = NULL); 

Eine Konfiguration des TCA für die Tabelle tt_content setzen oder überschreiben.

Diese Beispiel überschreibt im TCA das config-Array der Tabelle tt_content für:

$GLOBALS['TCA']['tt_content']['columns']['title']['config'][...]
Copied!
\nn\t3::TCA()->setContentConfig( 'header', 'text' );     // ['type'=>'text', 'rows'=>2]
\nn\t3::TCA()->setContentConfig( 'header', 'text', 10 ); // ['type'=>'text', 'rows'=>10]
\nn\t3::TCA()->setContentConfig( 'header', ['type'=>'text', 'rows'=>10] ); // ['type'=>'text', 'rows'=>10]
Copied!

| @return array

Source Code 

public function setContentConfig( $field = '', $override = [], $shortParams = null )
{
	if (!isset($GLOBALS['TCA']['tt_content']['columns'][$field]['config'])) {
		$GLOBALS['TCA']['tt_content']['columns'][$field]['config'] = [];
	}
	$config = &$GLOBALS['TCA']['tt_content']['columns'][$field]['config'];
	return $config = \nn\t3::Arrays()->merge( $config, $this->getConfigForType($override, $shortParams) );
}
Copied!

TCA::setPagesConfig() 

\nn\t3::TCA()->setPagesConfig($field = '', $override = [], $shortParams = NULL); 

Eine Konfiguration des TCA für die Tabelle pages setzen oder überschreiben.

Diese Beispiel überschreibt im TCA das config-Array der Tabelle pages für:

$GLOBALS['TCA']['pages']['columns']['title']['config'][...]
Copied!
\nn\t3::TCA()->setPagesConfig( 'title', 'text' );            // ['type'=>'text', 'rows'=>2]
\nn\t3::TCA()->setPagesConfig( 'title', 'text', 10 );        // ['type'=>'text', 'rows'=>10]
\nn\t3::TCA()->setPagesConfig( 'title', ['type'=>'text', 'rows'=>2] ); // ['type'=>'text', 'rows'=>2]
Copied!

| @return array

Source Code 

public function setPagesConfig( $field = '', $override = [], $shortParams = null )
{
	if (!isset($GLOBALS['TCA']['pages']['columns'][$field]['config'])) {
		$GLOBALS['TCA']['pages']['columns'][$field]['config'] = [];
	}
	$config = &$GLOBALS['TCA']['pages']['columns'][$field]['config'];
	return $config = \nn\t3::Arrays()->merge( $config, $this->getConfigForType($override, $shortParams) );
}
Copied!

Template 

\nn\t3::Template() 

Fluid Templates rendern und Pfade zu Templates im View manipulieren.

Overview of Methods 

\nn\t3::Template()->findTemplate($view = NULL, $templateName = ''); 

Findet ein Template in einem Array von möglichen templatePaths des Views

\nn\t3::Template()->findTemplate( $this->view, 'example.html' );
Copied!

| @return string

| ➜ Go to source code of Template::findTemplate()

\nn\t3::Template()->getVariable($view, $varname = ''); 

Holt EINE Variables des aktuellen Views, sprich: Alles, was per assign() und assignMultiple() gesetzt wurde.

Im ViewHelper:

\nn\t3::Template()->getVariable( $renderingContext, 'varname' );
Copied!

Im Controller:

\nn\t3::Template()->getVariable( $this->view, 'varname' );
Copied!

| @return array

| ➜ Go to source code of Template::getVariable()

\nn\t3::Template()->getVariables($view); 

Holt die Variables des aktuellen Views, sprich: Alles, was per assign() und assignMultiple() gesetzt wurde.

Im ViewHelper:

\nn\t3::Template()->getVariables( $renderingContext );
Copied!

Im Controller:

\nn\t3::Template()->getVariables( $this->view );
Copied!

| @return array

| ➜ Go to source code of Template::getVariables()

\nn\t3::Template()->mergeTemplatePaths($defaultTemplatePaths = [], $additionalTemplatePaths = []); 

Pfade zu Templates, Partials, Layout mergen

\nn\t3::Template()->mergeTemplatePaths( $defaultTemplatePaths, $additionalTemplatePaths );
Copied!

| @return array

| ➜ Go to source code of Template::mergeTemplatePaths()

\nn\t3::Template()->removeControllerPath($view); 

Entfernt den Pfad des Controller-Names z.B. /Main/... aus der Suche nach Templates.

\nn\t3::Template()->removeControllerPath( $this->view );
Copied!

| @return void

| ➜ Go to source code of Template::removeControllerPath()

\nn\t3::Template()->render($templateName = NULL, $vars = [], $templatePaths = [], $request = NULL); 

Ein Fluid-Templates rendern per StandAlone-Renderer

\nn\t3::Template()->render( 'Templatename', $vars, $templatePaths );
\nn\t3::Template()->render( 'Templatename', $vars, 'myext' );
\nn\t3::Template()->render( 'Templatename', $vars, 'tx_myext_myplugin' );
\nn\t3::Template()->render( 'fileadmin/Fluid/Demo.html', $vars );
Copied!

Seit TYPO3 12 muss beim Aufruf aus einem Controller auch der $request übergeben werden:

\nn\t3::Template()->render( 'Templatename', $vars, $templatePaths, $this->request );
Copied!

| @return string

| ➜ Go to source code of Template::render()

\nn\t3::Template()->renderHtml($html = NULL, $vars = [], $templatePaths = [], $request = NULL); 

einfachen Fluid-Code rendern per StandAlone-Renderer

\nn\t3::Template()->renderHtml( '{_all->f:debug()} Test: {test}', $vars );
\nn\t3::Template()->renderHtml( ['Name: {name}', 'Test: {test}'], $vars );
\nn\t3::Template()->renderHtml( ['name'=>'{firstname} {lastname}', 'test'=>'{test}'], $vars );
Copied!

Seit TYPO3 12 muss beim Aufruf aus einem Controller auch der $request übergeben werden:

\nn\t3::Template()->renderHtml( 'Templatename', $vars, $templatePaths, $this->request );
Copied!

| @return string

| ➜ Go to source code of Template::renderHtml()

\nn\t3::Template()->setTemplatePaths($view = NULL, $defaultTemplatePaths = [], $additionalTemplatePaths = []); 

Setzt Templates, Partials und Layouts für einen View. $additionalTemplatePaths kann übergeben werden, um Pfade zu priorisieren

\nn\t3::Template()->setTemplatePaths( $this->view, $templatePaths );
Copied!

| @return array

| ➜ Go to source code of Template::setTemplatePaths()

Methods 

Template::findTemplate() 

\nn\t3::Template()->findTemplate($view = NULL, $templateName = ''); 

Findet ein Template in einem Array von möglichen templatePaths des Views

\nn\t3::Template()->findTemplate( $this->view, 'example.html' );
Copied!

| @return string

Source Code 

public function findTemplate( $view = null, $templateName = '' ) {
	$paths = array_reverse($view->getTemplateRootPaths());
	$templateName = pathinfo( $templateName, PATHINFO_FILENAME );
	foreach ($paths as $path) {
		if (\nn\t3::File()->exists( $path . $templateName . '.html')) {
			return $path . $templateName . '.html';
		}
		if (\nn\t3::File()->exists( $path . $templateName)) {
			return $path . $templateName;
		}
	}
	return false;
}
Copied!

Template::getVariable() 

\nn\t3::Template()->getVariable($view, $varname = ''); 

Holt EINE Variables des aktuellen Views, sprich: Alles, was per assign() und assignMultiple() gesetzt wurde.

Im ViewHelper:

\nn\t3::Template()->getVariable( $renderingContext, 'varname' );
Copied!

Im Controller:

\nn\t3::Template()->getVariable( $this->view, 'varname' );
Copied!

| @return array

Source Code 

public function getVariable( &$view, $varname = '' )
{
	$context = $view;
	if (method_exists($context, 'getRenderingContext')) {
		$context = $view->getRenderingContext();
	}
	return $context->getVariableProvider()->get($varname) ?: '';
}
Copied!

Template::getVariables() 

\nn\t3::Template()->getVariables($view); 

Holt die Variables des aktuellen Views, sprich: Alles, was per assign() und assignMultiple() gesetzt wurde.

Im ViewHelper:

\nn\t3::Template()->getVariables( $renderingContext );
Copied!

Im Controller:

\nn\t3::Template()->getVariables( $this->view );
Copied!

| @return array

Source Code 

public function getVariables( &$view )
{
	$context = $view;
	if (method_exists($context, 'getRenderingContext')) {
		$context = $view->getRenderingContext();
	}
	return $context->getVariableProvider()->getSource() ?: [];
}
Copied!

Template::mergeTemplatePaths() 

\nn\t3::Template()->mergeTemplatePaths($defaultTemplatePaths = [], $additionalTemplatePaths = []); 

Pfade zu Templates, Partials, Layout mergen

\nn\t3::Template()->mergeTemplatePaths( $defaultTemplatePaths, $additionalTemplatePaths );
Copied!

| @return array

Source Code 

public function mergeTemplatePaths ( $defaultTemplatePaths = [], $additionalTemplatePaths = [] ) {
	$pathsToMerge = ['templateRootPaths', 'partialRootPaths', 'layoutRootPaths'];
	foreach ($pathsToMerge as $field) {
		if ($paths = $additionalTemplatePaths[$field] ?? false) {
			if (!isset($defaultTemplatePaths[$field])) {
				$defaultTemplatePaths[$field] = [];
			}
			ArrayUtility::mergeRecursiveWithOverrule($defaultTemplatePaths[$field], $paths);
		}
	}
	if ($path = $additionalTemplatePaths['template'] ?? false) {
		$defaultTemplatePaths['template'] = $path;
	}
	return $defaultTemplatePaths;
}
Copied!

Template::removeControllerPath() 

\nn\t3::Template()->removeControllerPath($view); 

Entfernt den Pfad des Controller-Names z.B. /Main/... aus der Suche nach Templates.

\nn\t3::Template()->removeControllerPath( $this->view );
Copied!

| @return void

Source Code 

public function removeControllerPath( &$view ) {
	$view->getRenderingContext()->setControllerName('');
}
Copied!

Template::render() 

\nn\t3::Template()->render($templateName = NULL, $vars = [], $templatePaths = [], $request = NULL); 

Ein Fluid-Templates rendern per StandAlone-Renderer

\nn\t3::Template()->render( 'Templatename', $vars, $templatePaths );
\nn\t3::Template()->render( 'Templatename', $vars, 'myext' );
\nn\t3::Template()->render( 'Templatename', $vars, 'tx_myext_myplugin' );
\nn\t3::Template()->render( 'fileadmin/Fluid/Demo.html', $vars );
Copied!

Seit TYPO3 12 muss beim Aufruf aus einem Controller auch der $request übergeben werden:

\nn\t3::Template()->render( 'Templatename', $vars, $templatePaths, $this->request );
Copied!

| @return string

Source Code 

public function render ( $templateName = null, $vars = [], $templatePaths = [], $request = null )
{
	$view = \nn\t3::injectClass(StandaloneView::class);
	if (!$request) {
		$request = \nn\t3::Environment()->getRequest();
	}
	if ($request) {
		$view->setRequest( $request );
	}
	if ($templatePaths) {
		// String wurde als TemplatePath übergeben
		if (is_string($templatePaths)) {
			if ($paths = \nn\t3::Settings()->getPlugin($templatePaths)) {
				$templatePaths = $paths['view'];
			}
		}
		if ($templateName) {
			$templatePaths['template'] = $templateName;
		}
		$this->setTemplatePaths( $view, $templatePaths );
		$this->removeControllerPath( $view );
	} else {
		$view->setTemplatePathAndFilename( $templateName );
	}
	$view->assignMultiple( $vars );
	return $view->render();
}
Copied!

Template::renderHtml() 

\nn\t3::Template()->renderHtml($html = NULL, $vars = [], $templatePaths = [], $request = NULL); 

einfachen Fluid-Code rendern per StandAlone-Renderer

\nn\t3::Template()->renderHtml( '{_all->f:debug()} Test: {test}', $vars );
\nn\t3::Template()->renderHtml( ['Name: {name}', 'Test: {test}'], $vars );
\nn\t3::Template()->renderHtml( ['name'=>'{firstname} {lastname}', 'test'=>'{test}'], $vars );
Copied!

Seit TYPO3 12 muss beim Aufruf aus einem Controller auch der $request übergeben werden:

\nn\t3::Template()->renderHtml( 'Templatename', $vars, $templatePaths, $this->request );
Copied!

| @return string

Source Code 

public function renderHtml ( $html = null, $vars = [], $templatePaths = [], $request = null) {
	$returnArray = is_array($html);
	if (!$returnArray) $html = [$html];
	$view = \nn\t3::injectClass(StandaloneView::class);
	// @todo: Prüfen, of das geht?
	if (!$request) {
		//$request = $GLOBALS['TYPO3_REQUEST'] ?? false;
	}
	if ($request) {
		$view->setRequest( $request);
	}
	if ($templatePaths) {
		$this->setTemplatePaths( $view, $templatePaths );
		$this->removeControllerPath( $view );
	}
	if (is_array($vars)) {
		$view->assignMultiple( $vars );
	}
	foreach ($html as $k=>$v) {
		if (is_string($v) && trim($v)) {
			// ersetzt maskierte Viewhelper wie `{test-&gt;f:debug()}` mit `{test->f:debug()}`
			$v = preg_replace('/{([^}]*)(-&gt;|→)([^}]*)}/', '{$1->$3}', $v);
			$view->setTemplateSource( $v );
			$html[$k] = $view->render();
		} else {
			$html[$k] = $v;
		}
	}
	return $returnArray ? $html : $html[0];
}
Copied!

Template::setTemplatePaths() 

\nn\t3::Template()->setTemplatePaths($view = NULL, $defaultTemplatePaths = [], $additionalTemplatePaths = []); 

Setzt Templates, Partials und Layouts für einen View. $additionalTemplatePaths kann übergeben werden, um Pfade zu priorisieren

\nn\t3::Template()->setTemplatePaths( $this->view, $templatePaths );
Copied!

| @return array

Source Code 

public function setTemplatePaths ( $view = null, $defaultTemplatePaths = [], $additionalTemplatePaths = []) {
	$mergedPaths = $this->mergeTemplatePaths( $defaultTemplatePaths, $additionalTemplatePaths );
	if ($paths = $mergedPaths['templateRootPaths'] ?? false) {
		$view->setTemplateRootPaths($paths);
	}
	if ($paths = $mergedPaths['partialRootPaths'] ?? false) {
		$view->setPartialRootPaths($paths);
	}
	if ($paths = $mergedPaths['layoutRootPaths'] ?? false) {
		$view->setLayoutRootPaths($paths);
	}
   	if ($path = $mergedPaths['template'] ?? false) {
		$view->setTemplate($path);
	}
	return $mergedPaths;
}
Copied!

Tsfe 

\nn\t3::Tsfe() 

Alles rund um das Typo3 Frontend. Methoden zum Initialisieren des FE aus dem Backend-Context, Zugriff auf das cObj und cObjData etc.

Overview of Methods 

\nn\t3::Tsfe()->bootstrap($conf = []); 

Bootstrap Typo3

\nn\t3::Tsfe()->bootstrap();
\nn\t3::Tsfe()->bootstrap( ['vendorName'=>'Nng', 'extensionName'=>'Nnhelpers', 'pluginName'=>'Foo'] );
Copied!

| ➜ Go to source code of Tsfe::bootstrap()

\nn\t3::Tsfe()->cObj($request = NULL); 

$GLOBALS['TSFE']->cObj holen.

// seit TYPO3 12.4 innerhalb eines Controllers:
\nn\t3::Tsfe()->cObj( $this->request  )
Copied!

| @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer

| ➜ Go to source code of Tsfe::cObj()

\nn\t3::Tsfe()->cObjData($request = NULL, $var = NULL); 

$GLOBALS['TSFE']->cObj->data holen.

\nn\t3::Tsfe()->cObjData( $this->request ); => array mit DB-row des aktuellen Content-Elementes
\nn\t3::Tsfe()->cObjData( $this->request, 'uid' );  => uid des aktuellen Content-Elements
Copied!

| @return mixed

| ➜ Go to source code of Tsfe::cObjData()

\nn\t3::Tsfe()->cObjGetSingle($type = '', $conf = []); 

Ein TypoScript-Object rendern. Früher: $GLOBALS['TSFE']->cObj->cObjGetSingle()

\nn\t3::Tsfe()->cObjGetSingle('IMG_RESOURCE', ['file'=>'bild.jpg', 'file.'=>['maxWidth'=>200]] )
Copied!

| ➜ Go to source code of Tsfe::cObjGetSingle()

\nn\t3::Tsfe()->forceAbsoluteUrls($enable = true); 

Setzt config.absRefPrefix auf die aktuelle URL.

Damit werden beim Rendern der Links von Content-Elementen absolute URLs verwendet. Funktioniert zur Zeit (noch) nicht für Bilder.

\nn\t3::Environment()->forceAbsoluteUrls();
$html = \nn\t3::Content()->render(123);
Copied!

| ➜ Go to source code of Tsfe::forceAbsoluteUrls()

\nn\t3::Tsfe()->get($pid = NULL); 

$GLOBALS['TSFE'] holen. Falls nicht vorhanden (weil im BE) initialisieren.

\nn\t3::Tsfe()->get()
\nn\t3::Tsfe()->get()
Copied!

| @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController

| ➜ Go to source code of Tsfe::get()

\nn\t3::Tsfe()->includeHiddenRecords($includeHidden = false, $includeStartEnd = false, $includeDeleted = false); 

Ausgeblendete (hidden) Inhaltselemente im Frontend holen. Kann vor dem Rendern verwendet werden.

\nn\t3::Tsfe()->includeHiddenRecords(true, true, true);
$html = \nn\t3::Content()->render(123);
Copied!
@param bool $includeHidden
@param bool $includeStartEnd
@param bool $includeDeleted
@return void

| ➜ Go to source code of Tsfe::includeHiddenRecords()

\nn\t3::Tsfe()->init($pid = 0, $typeNum = 0); 

Das $GLOBALS['TSFE'] initialisieren. Dient nur zur Kompatibilität mit älterem Code, das noch $GLOBALS['TSFE'] verwendet.

// TypoScript holen auf die 'alte' Art
$pid = \nn\t3::Page()->getPid();
\nn\t3::Tsfe()->init($pid);
$setup = $GLOBALS['TSFE']->tmpl->setup;
Copied!
@param int $pid
@param int $typeNum
@return void

| ➜ Go to source code of Tsfe::init()

\nn\t3::Tsfe()->injectTypoScript($request = NULL); 

Vollständig initialisiertes TypoScript in den Request einschleusen.

Dies ist erforderlich, wenn in einem gecachten Frontend-Kontext ausgeführt wird, in dem das TypoScript-Setup-Array nicht initialisiert ist. Es verwendet den TypoScriptHelper, um ein vollständiges TypoScript-Objekt zu erstellen und es in das frontend.typoscript-Attribut des Requests einzuschleusen.

// In der Middleware:
$request = \nn\t3::Tsfe()->injectTypoScript( $request );
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest $request
@return \TYPO3\CMS\Core\Http\ServerRequest

| ➜ Go to source code of Tsfe::injectTypoScript()

\nn\t3::Tsfe()->softDisableCache($request = NULL); 

Cache für das Frontend deaktivieren.

"Softe" Variante: Nutzt ein fake USER_INT-Objekt, damit bereits gerenderte Elemente nicht neu gerendert werden müssen. Workaround für TYPO3 v12+, da TypoScript Setup & Constants nicht mehr initialisiert werden, wenn Seite vollständig aus dem Cache geladen werden.

\nn\t3::Tsfe()->softDisableCache()
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest $request
@return \TYPO3\CMS\Core\Http\ServerRequest

| ➜ Go to source code of Tsfe::softDisableCache()

Methods 

Tsfe::bootstrap() 

\nn\t3::Tsfe()->bootstrap($conf = []); 

Bootstrap Typo3

\nn\t3::Tsfe()->bootstrap();
\nn\t3::Tsfe()->bootstrap( ['vendorName'=>'Nng', 'extensionName'=>'Nnhelpers', 'pluginName'=>'Foo'] );
Copied!

Source Code 

public function bootstrap ( $conf = [] )
{
	$bootstrap = new \TYPO3\CMS\Extbase\Core\Bootstrap();
	if (!$conf) {
		$conf = [
			'vendorName'	=> 'Nng',
			'extensionName'	=> 'Nnhelpers',
			'pluginName'	=> 'Foo',
		];
	}
	$bootstrap->initialize($conf);
}
Copied!

Tsfe::cObj() 

\nn\t3::Tsfe()->cObj($request = NULL); 

$GLOBALS['TSFE']->cObj holen.

// seit TYPO3 12.4 innerhalb eines Controllers:
\nn\t3::Tsfe()->cObj( $this->request  )
Copied!

| @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer

Source Code 

public function cObj( $request = null )
{
	$request = $request ?: \nn\t3::Environment()->getSyntheticFrontendRequest();
	if ($request) {
		if ($cObj = $request->getAttribute('currentContentObject')) {
			return $cObj;
		}
	}
	$cObjRenderer = \nn\t3::injectClass(ContentObjectRenderer::class);
	$cObjRenderer->setRequest( $request );
	return $cObjRenderer;
}
Copied!

Tsfe::cObjData() 

\nn\t3::Tsfe()->cObjData($request = NULL, $var = NULL); 

$GLOBALS['TSFE']->cObj->data holen.

\nn\t3::Tsfe()->cObjData( $this->request ); => array mit DB-row des aktuellen Content-Elementes
\nn\t3::Tsfe()->cObjData( $this->request, 'uid' );  => uid des aktuellen Content-Elements
Copied!

| @return mixed

Source Code 

public function cObjData( $request = null, $var = null )
{
	if (is_string($request)) {
		$var = $request;
		$request = null;
	}
	if (!$request) {
		$request = \nn\t3::Environment()->getRequest();
	}
	if (!$request) {
		\nn\t3::Exception('
			\nn\t3::Tsfe()->cObjData() needs a $request as first parameter.
			In a Controller-Context use \nn\t3::Tsfe()->cObjData( $this->request ).
			For other contexts see here: https://bit.ly/3s6dzF0');
	}
	$cObj = $this->cObj( $request );
	if (!$cObj) return false;
	return $var ? ($cObj->data[$var] ?? null) : ($cObj->data ?? []);
}
Copied!

Tsfe::cObjGetSingle() 

\nn\t3::Tsfe()->cObjGetSingle($type = '', $conf = []); 

Ein TypoScript-Object rendern. Früher: $GLOBALS['TSFE']->cObj->cObjGetSingle()

\nn\t3::Tsfe()->cObjGetSingle('IMG_RESOURCE', ['file'=>'bild.jpg', 'file.'=>['maxWidth'=>200]] )
Copied!

Source Code 

public function cObjGetSingle( $type = '', $conf = [] )
{
	try {
		$content = $this->cObj()->cObjGetSingle( $type, $conf );
		return $content;
	} catch (\Error $e) {
		return 'ERROR: ' . $e->getMessage();
	}
}
Copied!

Tsfe::forceAbsoluteUrls() 

\nn\t3::Tsfe()->forceAbsoluteUrls($enable = true); 

Setzt config.absRefPrefix auf die aktuelle URL.

Damit werden beim Rendern der Links von Content-Elementen absolute URLs verwendet. Funktioniert zur Zeit (noch) nicht für Bilder.

\nn\t3::Environment()->forceAbsoluteUrls();
$html = \nn\t3::Content()->render(123);
Copied!

Source Code 

public function forceAbsoluteUrls( $enable = true )
{
	$request = \nn\t3::Environment()->getRequest();
	$fts = $request->getAttribute('frontend.typoscript');
	if (!$fts) return $request;
	$base = rtrim((string)$request->getAttribute('site')->getBase(), '/') . '/';
	$config = $fts->getConfigArray() ?? [];
	$config['absRefPrefix'] = $base;
	$config['forceAbsoluteUrls'] = $enable;
	if (method_exists($fts, 'setConfigArray')) {
		$fts->setConfigArray($config);
		$request = $request->withAttribute('frontend.typoscript', $fts);
	}
	\nn\t3::Environment()->setRequest($request);
	return $request;
}
Copied!

Tsfe::get() 

\nn\t3::Tsfe()->get($pid = NULL); 

$GLOBALS['TSFE'] holen. Falls nicht vorhanden (weil im BE) initialisieren.

\nn\t3::Tsfe()->get()
\nn\t3::Tsfe()->get()
Copied!

| @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController

Source Code 

public function get( $pid = null )
{
	if (!isset($GLOBALS['TSFE'])) $this->init( $pid );
	return $GLOBALS['TSFE'] ?? '';
}
Copied!

Tsfe::includeHiddenRecords() 

\nn\t3::Tsfe()->includeHiddenRecords($includeHidden = false, $includeStartEnd = false, $includeDeleted = false); 

Ausgeblendete (hidden) Inhaltselemente im Frontend holen. Kann vor dem Rendern verwendet werden.

\nn\t3::Tsfe()->includeHiddenRecords(true, true, true);
$html = \nn\t3::Content()->render(123);
Copied!
@param bool $includeHidden
@param bool $includeStartEnd
@param bool $includeDeleted
@return void

Source Code 

public function includeHiddenRecords($includeHidden = false, $includeStartEnd = false, $includeDeleted = false)
{
	$context = GeneralUtility::makeInstance(Context::class);
	$current = $context->getAspect('visibility');
	$includeHidden		= $includeHidden || (method_exists($current, 'includesHiddenPages') ? $current->includesHiddenPages() : false);
	$includeDeleted		= $includeDeleted || (method_exists($current, 'includesDeletedRecords') ? $current->includesDeletedRecords() : false);
	$includeStartEnd	= $includeStartEnd || (method_exists($current, 'includesStartEndRecords') ? $current->includesStartEndRecords() : false);
	$context->setAspect(
		'visibility',
		GeneralUtility::makeInstance(
			VisibilityAspect::class,
			$includeHidden,		// pages
			$includeHidden,		// tt_content
			$includeDeleted,
			$includeStartEnd
		)
	);
}
Copied!

Tsfe::init() 

\nn\t3::Tsfe()->init($pid = 0, $typeNum = 0); 

Das $GLOBALS['TSFE'] initialisieren. Dient nur zur Kompatibilität mit älterem Code, das noch $GLOBALS['TSFE'] verwendet.

// TypoScript holen auf die 'alte' Art
$pid = \nn\t3::Page()->getPid();
\nn\t3::Tsfe()->init($pid);
$setup = $GLOBALS['TSFE']->tmpl->setup;
Copied!
@param int $pid
@param int $typeNum
@return void

Source Code 

public function init($pid = 0, $typeNum = 0)
{
	if (isset($GLOBALS['TSFE'])) {
		return;
	}
	$request = \nn\t3::Environment()->getRequest();
	if (!$request) {
		return;
	}
	
	$cObj = $this->cObj( $request );
	$tsfe = $request->getAttribute('frontend.controller');
	if (!$tsfe) {
		return;
	}
	
	$tsfe->cObj = $cObj;
	$fts = $request->getAttribute('frontend.typoscript');
	if ($fts) {
		$tmpl = new stdClass();
		$tmpl->setup  = $fts->getSetupArray();
		$tmpl->config = $fts->getConfigArray();
		$tsfe->tmpl = $tmpl;
	}
	$pageRepository = GeneralUtility::makeInstance(PageRepository::class);
	$tsfe->sys_page = $pageRepository;
	$userSessionManager = \TYPO3\CMS\Core\Session\UserSessionManager::create('FE');
	$userSession = $userSessionManager->createAnonymousSession();
	$tsfe->fe_user = $userSession;
	$GLOBALS['TSFE'] = $tsfe;
}
Copied!

Tsfe::injectTypoScript() 

\nn\t3::Tsfe()->injectTypoScript($request = NULL); 

Vollständig initialisiertes TypoScript in den Request einschleusen.

Dies ist erforderlich, wenn in einem gecachten Frontend-Kontext ausgeführt wird, in dem das TypoScript-Setup-Array nicht initialisiert ist. Es verwendet den TypoScriptHelper, um ein vollständiges TypoScript-Objekt zu erstellen und es in das frontend.typoscript-Attribut des Requests einzuschleusen.

// In der Middleware:
$request = \nn\t3::Tsfe()->injectTypoScript( $request );
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest $request
@return \TYPO3\CMS\Core\Http\ServerRequest

Source Code 

public function injectTypoScript( $request = null ): \TYPO3\CMS\Core\Http\ServerRequest
{
	$request = $request ?: \nn\t3::Environment()->getRequest();
	// Check if TypoScript is already fully initialized
	$existingTs = $request->getAttribute('frontend.typoscript');
	if ($existingTs && $existingTs->hasSetup()) {
		try {
			$existingTs->getSetupArray();
			// If no exception, TypoScript is already available
			return $request;
		} catch (\RuntimeException $e) {
			// TypoScript not initialized, continue to inject
		}
	}
	// Create full TypoScript using the helper
	$pageUid = \nn\t3::Page()->getPid() ?: 1;
	$helper = \nn\t3::injectClass( TypoScriptHelper::class );
	$frontendTypoScript = $helper->getTypoScriptObject( $pageUid );
	// Inject the TypoScript into the request
	$request = $request->withAttribute('frontend.typoscript', $frontendTypoScript);
	// Update both the Environment singleton and the TYPO3 global request
	\nn\t3::Environment()->setRequest($request);
	$GLOBALS['TYPO3_REQUEST'] = $request;
	return $request;
}
Copied!

Tsfe::softDisableCache() 

\nn\t3::Tsfe()->softDisableCache($request = NULL); 

Cache für das Frontend deaktivieren.

"Softe" Variante: Nutzt ein fake USER_INT-Objekt, damit bereits gerenderte Elemente nicht neu gerendert werden müssen. Workaround für TYPO3 v12+, da TypoScript Setup & Constants nicht mehr initialisiert werden, wenn Seite vollständig aus dem Cache geladen werden.

\nn\t3::Tsfe()->softDisableCache()
Copied!
@param \TYPO3\CMS\Core\Http\ServerRequest $request
@return \TYPO3\CMS\Core\Http\ServerRequest

Source Code 

public function softDisableCache( $request = null ): \TYPO3\CMS\Core\Http\ServerRequest
{
	$request = $request ?: \nn\t3::Environment()->getRequest();
	$cacheInstruction = $request->getAttribute(
		'frontend.cache.instruction',
		new CacheInstruction()
	);
	$cacheInstruction->disableCache('App needs full TypoScript. Cache disabled by \nn\t3::Tsfe()->softDisableCache()');
	$request = $request->withAttribute('frontend.cache.instruction', $cacheInstruction);
	return $request;
}
Copied!

TypoScript 

\nn\t3::TypoScript() 

Methoden zum Parsen und Konvertieren von TypoScript

Overview of Methods 

\nn\t3::TypoScript()->addPageConfig($str = ''); 

Page-Config hinzufügen Alias zu \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::TypoScript()->addPageConfig( 'test.was = 10' );
\nn\t3::TypoScript()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::TypoScript()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

| ➜ Go to source code of TypoScript::addPageConfig()

\nn\t3::TypoScript()->convertToPlainArray($ts); 

TypoScript 'name.'-Syntax in normales Array umwandeln. Erleichtert den Zugriff

\nn\t3::TypoScript()->convertToPlainArray(['example'=>'test', 'example.'=>'here']);
Copied!

| @return array

| ➜ Go to source code of TypoScript::convertToPlainArray()

\nn\t3::TypoScript()->fromString($str = '', $overrideSetup = []); 

Wandelt einen Text in ein TypoScript-Array um.

$example = '
    lib.test {
      someVal = 10
    }
';
\nn\t3::TypoScript()->fromString($example);  => ['lib'=>['test'=>['someVal'=>10]]]
\nn\t3::TypoScript()->fromString($example, $mergeSetup); => ['lib'=>['test'=>['someVal'=>10]]]
Copied!

| @return array

| ➜ Go to source code of TypoScript::fromString()

Methods 

TypoScript::addPageConfig() 

\nn\t3::TypoScript()->addPageConfig($str = ''); 

Page-Config hinzufügen Alias zu \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::TypoScript()->addPageConfig( 'test.was = 10' );
\nn\t3::TypoScript()->addPageConfig( '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:extname/Configuration/TypoScript/page.txt">' );
\nn\t3::TypoScript()->addPageConfig( '@import "EXT:extname/Configuration/TypoScript/page.ts"' );
Copied!

| @return void

Source Code 

public function addPageConfig( $str = '' )
{
	\nn\t3::Registry()->addPageConfig( $str );
}
Copied!

TypoScript::convertToPlainArray() 

\nn\t3::TypoScript()->convertToPlainArray($ts); 

TypoScript 'name.'-Syntax in normales Array umwandeln. Erleichtert den Zugriff

\nn\t3::TypoScript()->convertToPlainArray(['example'=>'test', 'example.'=>'here']);
Copied!

| @return array

Source Code 

public function convertToPlainArray ($ts) {
	if (!$ts || !is_array($ts)) return [];
	$typoscriptService = \nn\t3::injectClass( TypoScriptService::class );
	return $typoscriptService->convertTypoScriptArrayToPlainArray($ts);
}
Copied!

TypoScript::fromString() 

\nn\t3::TypoScript()->fromString($str = '', $overrideSetup = []); 

Wandelt einen Text in ein TypoScript-Array um.

$example = '
    lib.test {
      someVal = 10
    }
';
\nn\t3::TypoScript()->fromString($example);  => ['lib'=>['test'=>['someVal'=>10]]]
\nn\t3::TypoScript()->fromString($example, $mergeSetup); => ['lib'=>['test'=>['someVal'=>10]]]
Copied!

| @return array

Source Code 

public function fromString ( $str = '', $overrideSetup = [] ) {
	if (!trim($str)) return $overrideSetup;
	$typoScriptStringFactory = GeneralUtility::makeInstance( TypoScriptStringFactory::class );
	$rootNode = $typoScriptStringFactory->parseFromStringWithIncludes('nnhelpers-fromstring', $str);
	$setup = $rootNode->toArray();
	if ($overrideSetup) {
		$setup = array_replace_recursive($overrideSetup, $setup);
	}
	return $this->convertToPlainArray($setup);
}
Copied!

Video 

\nn\t3::Video() 

Alles, was zum Thema Videos wichtig und hilfreich ist.

Overview of Methods 

\nn\t3::Video()->getEmbedUrl($type, $videoId = NULL); 

Einbettungs-URL anhand der Streaming-Plattform zurückgeben. Klassischerweise die URL, die im src-Attribut des <iframe> verwendet wird.

\nn\t3::Video()->getEmbedUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getEmbedUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );
Copied!

Existiert auch als ViewHelper:

{my.videourl->nnt3:video.embedUrl()}
Copied!

| @return string

| ➜ Go to source code of Video::getEmbedUrl()

\nn\t3::Video()->getExternalType($url = NULL); 

Gibt ein Array mit Infos über die Streaming-Platform und Code zum Einbetten eines Videos zurück.

\nn\t3::Video()->getExternalType( 'https://www.youtube.com/watch/abTAgsdjA' );
Copied!

| @return array

| ➜ Go to source code of Video::getExternalType()

\nn\t3::Video()->getWatchUrl($type, $videoId = NULL); 

Link-URL zum Video auf der externen Plattform z.B. um einen externen Link zum Video darzustellen

\nn\t3::Video()->getWatchUrl( $fileReference );
\nn\t3::Video()->getWatchUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getWatchUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );

// => https://www.youtube-nocookie.com/watch?v=kV8v2GKC8WA
Copied!

| @return string

| ➜ Go to source code of Video::getWatchUrl()

\nn\t3::Video()->isExternal($url = NULL); 

Prüft, ob es sich bei der URL um ein externes Video auf YouTube oder Vimeo handelt. Gibt ein Array mit Daten zum Einbetten zurück.

\nn\t3::Video()->isExternal( 'https://www.youtube.com/...' );
Copied!

| @return array

| ➜ Go to source code of Video::isExternal()

Methods 

Video::getEmbedUrl() 

\nn\t3::Video()->getEmbedUrl($type, $videoId = NULL); 

Einbettungs-URL anhand der Streaming-Plattform zurückgeben. Klassischerweise die URL, die im src-Attribut des <iframe> verwendet wird.

\nn\t3::Video()->getEmbedUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getEmbedUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );
Copied!

Existiert auch als ViewHelper:

{my.videourl->nnt3:video.embedUrl()}
Copied!

| @return string

Source Code 

public function getEmbedUrl ($type, $videoId = null)
{
	if (!$videoId && strpos($type, 'http') !== false) {
		$infos = $this->isExternal( $type );
		return $infos['embedUrl'];
	}
	switch ($type) {
		case 'youtube':
			return 'https://www.youtube-nocookie.com/embed/'.$videoId;
		case 'vimeo':
			return 'https://player.vimeo.com/video/'.$videoId;
	}
}
Copied!

Video::getExternalType() 

\nn\t3::Video()->getExternalType($url = NULL); 

Gibt ein Array mit Infos über die Streaming-Platform und Code zum Einbetten eines Videos zurück.

\nn\t3::Video()->getExternalType( 'https://www.youtube.com/watch/abTAgsdjA' );
Copied!

| @return array

Source Code 

public function getExternalType( $url = null )
{
	foreach (self::$VIDEO_PREGS as $type=>$pregs) {
		foreach ($pregs as $cnt => $arr) {
			foreach ($arr as $index => $preg) {
				if (preg_match($preg, $url, $match)) {
					return [
						'type'		=> $type,
						'videoId'	=> $match[$index],
						'embedUrl'	=> $this->getEmbedUrl($type, $match[$index]),
						'watchUrl'	=> $this->getWatchUrl($type, $match[$index]),
					];
				}
			}
		}
	}
	return [];
}
Copied!

Video::getWatchUrl() 

\nn\t3::Video()->getWatchUrl($type, $videoId = NULL); 

Link-URL zum Video auf der externen Plattform z.B. um einen externen Link zum Video darzustellen

\nn\t3::Video()->getWatchUrl( $fileReference );
\nn\t3::Video()->getWatchUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getWatchUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );

// => https://www.youtube-nocookie.com/watch?v=kV8v2GKC8WA
Copied!

| @return string

Source Code 

public function getWatchUrl ($type, $videoId = null )
{
	if (\nn\t3::Obj()->isFileReference($type)) {
		$type = $type->getOriginalResource()->getPublicUrl();
	}
	if (!$videoId && strpos($type, 'http') !== false) {
		$infos = $this->isExternal( $type );
		return $infos['watchUrl'];
	}
	switch ($type) {
		case 'youtube':
			return 'https://www.youtube-nocookie.com/watch?v='.$videoId;
		case 'vimeo':
			return 'https://vimeo.com/'.$videoId;
	}
}
Copied!

Video::isExternal() 

\nn\t3::Video()->isExternal($url = NULL); 

Prüft, ob es sich bei der URL um ein externes Video auf YouTube oder Vimeo handelt. Gibt ein Array mit Daten zum Einbetten zurück.

\nn\t3::Video()->isExternal( 'https://www.youtube.com/...' );
Copied!

| @return array

Source Code 

public function isExternal ( $url = null )
{
	return $this->getExternalType( $url );
}
Copied!

Additional Classes 

AnnotationHelper 

\nn\t3::AnnotationHelper() 

Diverse Methoden zum Parsen von PHP-Annotations

Overview of Methods 

\nn\t3::AnnotationHelper()->parse($rawAnnotation = '', $namespaces = []); 

Annotations parsen und ein Array mit dem "normalen" Kommentarblock und den einzelnen Annotations aus einem DocComment zurückgeben.

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...' );
Copied!

Nur Annotations holen, die in einem bestimmten Namespace sind. In diesem Beispiel werden nur Annotations geholt, die mit @nn\rest beginnen, z.B. @nn\rest\access ...

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...', 'nn\rest' );
\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...', ['nn\rest', 'whatever'] );
Copied!

| @return array

| ➜ Go to source code of AnnotationHelper::parse()

Methods 

AnnotationHelper::parse() 

\nn\t3::AnnotationHelper()->parse($rawAnnotation = '', $namespaces = []); 

Annotations parsen und ein Array mit dem "normalen" Kommentarblock und den einzelnen Annotations aus einem DocComment zurückgeben.

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...' );
Copied!

Nur Annotations holen, die in einem bestimmten Namespace sind. In diesem Beispiel werden nur Annotations geholt, die mit @nn\rest beginnen, z.B. @nn\rest\access ...

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...', 'nn\rest' );
\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...', ['nn\rest', 'whatever'] );
Copied!

| @return array

Source Code 

public static function parse ( $rawAnnotation = '', $namespaces = [] ) {
	if ($namespaces && !is_array($namespaces)) {
		$namespaces = [$namespaces];
	}
	$result = ['@' => []];
	if (preg_match_all( '/\n\s*\*\s*@([^\s]*)\s*([^\n]*)/im', $rawAnnotation, $annotations )) {
		foreach ($annotations[1] as $n=>$k) {
			if ($namespaces) {
				$found = false;
				foreach ($namespaces as $namespace) {
					if (strpos($k, $namespace) !== false) {
						$found = true;
						$k = ltrim(str_replace($namespace, '', $k), '\\');
						break;
					}
				}
				$rawAnnotation = str_replace($annotations[0][$n], '', $rawAnnotation);
				if (!$found) continue;
			}
			$result['@'][$k] = $annotations[2][$n];
		}
	}
	$result['comment'] = MarkdownHelper::parseComment( $rawAnnotation );
	return $result;
}
Copied!

DocumentationHelper 

\nn\t3::DocumentationHelper() 

Diverse Methoden zum Parsen von PHP-Quelltexten und Kommentaren im Quelltext (Annotations). Zielsetzung: Automatisierte Dokumentation aus den Kommentaren im PHP-Code erstellen.

Beispiele für die Verwendung inkl. Rendering des Templates

Im Controller mit Rendering per Fluid:

$path = \nn\t3::Environment()->extPath('myext') . 'Classes/Utilities/';
$doc = \Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( $path );
$this->view->assign('doc', $doc);
Copied!

Generieren der Typo3 / Sphinx ReST-Doku über ein eigenen Fluid-Template:

$path = \nn\t3::Environment()->extPath('myext') . 'Classes/Utilities/';
$doc = \Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( $path );

foreach ($doc as $className=>$infos) {
  $rendering = \nn\t3::Template()->render(
    'EXT:myext/Resources/Private/Backend/Templates/Documentation/ClassTemplate.html', [
      'infos' => $infos
    ]
  );

  $filename = $infos['fileName'] . '.rst';
  $file = \nn\t3::File()->absPath('EXT:myext/Documentation/Utilities/Classes/' . $filename);
  $result = file_put_contents( $file, $rendering );
}
Copied!

Overview of Methods 

\nn\t3::DocumentationHelper()->getClassNameFromFile($file); 

Klassen-Name als String inkl. vollem Namespace aus einer PHP-Datei holen. Gibt z.B. Nng\Classes\MyClass zurück.

\Nng\Nnhelpers\Helpers\DocumentationHelper::getClassNameFromFile( 'Classes/MyClass.php' );
Copied!

| @return string

| ➜ Go to source code of DocumentationHelper::getClassNameFromFile()

\nn\t3::DocumentationHelper()->getSourceCode($class, $method); 

Quelltext einer Methode holen.

Gibt den "rohen" PHP-Code der Methode einer Klasse zurück.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseClass( \Nng\Classes\MyClass::class, 'myMethodName' );
Copied!

| @return string

| ➜ Go to source code of DocumentationHelper::getSourceCode()

\nn\t3::DocumentationHelper()->parseClass($className = '', $returnMethods = true); 

Infos zu einer bestimmten Klasse holen.

Ähnelt parseFile() - allerdings muss hier der eigentliche Klassen-Name übergeben werden. Wenn man nur den Pfad zur PHP-Datei kennt, nutzt man parseFile().

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseClass( \Nng\Classes\MyClass::class );
Copied!

| @return array

| ➜ Go to source code of DocumentationHelper::parseClass()

\nn\t3::DocumentationHelper()->parseFile($path = '', $returnMethods = true); 

Alle Infos zu einer einzelnen PHP-Datei holen.

Parsed den Kommentar (Annotation) über der Klassen-Definition und optional auch alle Methoden der Klasse. Gibt ein Array zurück, bei der auch die Argumente / Parameter jeder Methode aufgeführt werden.

Markdown kann in den Annotations verwendet werden, das Markdown wird automatisch in HTML-Code umgewandelt.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFile( 'Path/Classes/MyClass.php' );
Copied!

| @return array

| ➜ Go to source code of DocumentationHelper::parseFile()

\nn\t3::DocumentationHelper()->parseFolder($path = '', $options = []); 

Einen Ordner (rekursiv) nach Klassen mit Annotations parsen. Gibt ein Array mit Informationen zu jeder Klasse und seinen Methoden zurück.

Die Annotations (Kommentare) über den Klassen-Methoden können in Markdown formatiert werden, sie werden automatisch in HTML mit passenden <pre> und <code> Tags umgewandelt.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'Path/To/Classes/' );
\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'EXT:myext/Classes/ViewHelpers/' );
\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'Path/Somewhere/', ['recursive'=>false, 'suffix'=>'php', 'parseMethods'=>false] );
Copied!

| @return array

| ➜ Go to source code of DocumentationHelper::parseFolder()

Methods 

DocumentationHelper::getClassNameFromFile() 

\nn\t3::DocumentationHelper()->getClassNameFromFile($file); 

Klassen-Name als String inkl. vollem Namespace aus einer PHP-Datei holen. Gibt z.B. Nng\Classes\MyClass zurück.

\Nng\Nnhelpers\Helpers\DocumentationHelper::getClassNameFromFile( 'Classes/MyClass.php' );
Copied!

| @return string

Source Code 

public static function getClassNameFromFile( $file )
{
	$file = \nn\t3::File()->absPath( $file );
	$fileStr = php_strip_whitespace($file);
	$tokens = @token_get_all($fileStr);
	$namespace = $class = '';
	for ($i = 0; $i<count($tokens); $i++) {
		if ($tokens[$i][0] === T_NAMESPACE) {
			for ($j=$i+1;$j<count($tokens); $j++) {
				if ($tokens[$j][0] === T_STRING || (PHP_VERSION_ID >= 80000 && ($tokens[$j][0] == T_NAME_QUALIFIED || $tokens[$j][0] == T_NAME_FULLY_QUALIFIED))) {
					$namespace .= '\\'.$tokens[$j][1];
				} else if ($tokens[$j] === '{' || $tokens[$j] === ';') {
					break;
				}
			}
		}
		if ($tokens[$i][0] === T_CLASS) {
			for ($j=$i+1;$j<count($tokens);$j++) {
				if ($tokens[$j] === '{') {
					$class = $tokens[$i+2][1] ?? null;
				}
			}
		}
		if ($class) break;
	}
	$className = ltrim( $namespace . '\\' . $class, '\\');
	return $className;
}
Copied!

DocumentationHelper::getSourceCode() 

\nn\t3::DocumentationHelper()->getSourceCode($class, $method); 

Quelltext einer Methode holen.

Gibt den "rohen" PHP-Code der Methode einer Klasse zurück.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseClass( \Nng\Classes\MyClass::class, 'myMethodName' );
Copied!

| @return string

Source Code 

public static function getSourceCode($class, $method)
{
	$func = new \ReflectionMethod($class, $method);
	$f = $func->getFileName();
	$start_line = $func->getStartLine() - 1;
	$end_line = $func->getEndLine();
	$cache = self::$sourceCodeCache[$f] ?? false;
	if (!$cache) {
		$source = file($f);
		$source = implode('', array_slice($source, 0, count($source)));
		$source = preg_split("/".PHP_EOL."/", $source);
		self::$sourceCodeCache[$f] = $source;
	}
	$source = self::$sourceCodeCache[$f];
	$body = "\n";
	for ($i=$start_line; $i<$end_line; $i++) {
		if ($source[$i] ?? false) {
			$body.="{$source[$i]}\n";
		}
	}
	$body = str_replace('	', "\t", $body);
	$body = str_replace("\n\t", "\n", $body);
	return $body;
}
Copied!

DocumentationHelper::parseClass() 

\nn\t3::DocumentationHelper()->parseClass($className = '', $returnMethods = true); 

Infos zu einer bestimmten Klasse holen.

Ähnelt parseFile() - allerdings muss hier der eigentliche Klassen-Name übergeben werden. Wenn man nur den Pfad zur PHP-Datei kennt, nutzt man parseFile().

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseClass( \Nng\Classes\MyClass::class );
Copied!

| @return array

Source Code 

public static function parseClass( $className = '', $returnMethods = true )
{
	if (!$className || !class_exists($className)) {
		return [];
	}
	$reflector = new \ReflectionClass( $className );
	$docComment = $reflector->getDocComment();
	$classComment = MarkdownHelper::parseComment( $docComment );
	$classInfo = [
		'className'		=> $className,
		'comment' 		=> $classComment,
		'rawComment'	=> $docComment,
		'methods'		=> [],
	];
	if (!$returnMethods) {
		return $classInfo;
	}
	// Durch alle Methoden der Klasse gehen
	foreach ($reflector->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
		if ($method->class == $reflector->getName()) {
			if (strpos($method->name, '__') === false) {
				$comment = MarkdownHelper::parseComment($method->getDocComment());
				$params = $method->getParameters();
				$paramInfo = [];
				$paramString = [];
				foreach ($params as $param) {
					$defaultValue = $param->isOptional() ? $param->getDefaultValue() : '';
					if (is_string($defaultValue)) $defaultValue = "'{$defaultValue}'";
					if ($defaultValue === false) $defaultValue = 'false';
					if ($defaultValue === true) $defaultValue = 'true';
					if (is_null($defaultValue)) $defaultValue = 'NULL';
					if ($defaultValue == 'Array' || is_array($defaultValue)) $defaultValue = '[]';
					$paramInfo[$param->getName()] = $defaultValue;
					$paramString[] = "\${$param->getName()}" . ($param->isOptional() ? " = {$defaultValue}" : '');
				}
				$classInfo['methods'][$method->name] = [
					'comment' 		=> $comment,
					'paramInfo'		=> $paramInfo,
					'paramString'	=> join(', ', $paramString),
					'sourceCode'	=> self::getSourceCode($method->class, $method->name),
				];
			}
		}
	}
	ksort($classInfo['methods']);
	return $classInfo;
}
Copied!

DocumentationHelper::parseFile() 

\nn\t3::DocumentationHelper()->parseFile($path = '', $returnMethods = true); 

Alle Infos zu einer einzelnen PHP-Datei holen.

Parsed den Kommentar (Annotation) über der Klassen-Definition und optional auch alle Methoden der Klasse. Gibt ein Array zurück, bei der auch die Argumente / Parameter jeder Methode aufgeführt werden.

Markdown kann in den Annotations verwendet werden, das Markdown wird automatisch in HTML-Code umgewandelt.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFile( 'Path/Classes/MyClass.php' );
Copied!

| @return array

Source Code 

public static function parseFile( $path = '', $returnMethods = true )
{
	$className = self::getClassNameFromFile( $path );
	$data = self::parseClass( $className, $returnMethods );
	$data = array_merge($data, [
		'path' 		=> $path,
		'fileName'	=> pathinfo( $path, PATHINFO_FILENAME ),
	]);
	return $data;
}
Copied!

DocumentationHelper::parseFolder() 

\nn\t3::DocumentationHelper()->parseFolder($path = '', $options = []); 

Einen Ordner (rekursiv) nach Klassen mit Annotations parsen. Gibt ein Array mit Informationen zu jeder Klasse und seinen Methoden zurück.

Die Annotations (Kommentare) über den Klassen-Methoden können in Markdown formatiert werden, sie werden automatisch in HTML mit passenden <pre> und <code> Tags umgewandelt.

\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'Path/To/Classes/' );
\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'EXT:myext/Classes/ViewHelpers/' );
\Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( 'Path/Somewhere/', ['recursive'=>false, 'suffix'=>'php', 'parseMethods'=>false] );
Copied!

| @return array

Source Code 

public static function parseFolder( $path = '', $options = [] )
{
	$options = array_merge([
		'recursive' 	=> true,
		'suffix'		=> 'php',
		'parseMethods'	=> true,
	], $options);
	$classList = [];
	$fileList = [];
	$suffix = $options['suffix'];
	$path = \nn\t3::File()->absPath($path);
	if ($options['recursive']) {
		$iterator = new \RecursiveIteratorIterator(
			new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS)
		);
		foreach ($iterator as $file) {
			if ($file->isFile() && $file->getExtension() === $suffix) {
				$fileList[] = $file->getPathname();
			}
		}
	} else {
		$iterator = new \DirectoryIterator($path);
		foreach ($iterator as $file) {
			if ($file->isFile() && $file->getExtension() === $suffix) {
				$fileList[] = $file->getPathname();
			}
		}
	}
	// Durch alle php-Dateien im Verzeichnis Classes/Utilities/ gehen
	foreach ($fileList as $path) {
		$classInfo = self::parseFile( $path, $options['parseMethods'] );
		$className = $classInfo['className'];
		$classList[$className] = $classInfo;
	}
	ksort($classList);
	return $classList;
}
Copied!

ExtConfTemplateHelper 

\nn\t3::ExtConfTemplateHelper() 

Erweiterung für das Formular des Extension-Managers.

Overview of Methods 

\nn\t3::ExtConfTemplateHelper()->textfield($conf = []); 

Mehrzeiliges Textfeld / Textarea im Extension Manager Konfigurator zeigen. Diese Zeile in ext_conf_template.txt der eigenen Extension nutzen:

# cat=basic; type=user[Nng\Nnhelpers\Helpers\ExtConfTemplateHelper->textfield]; label=Mein Label
meinFeldName =
Copied!

| @return string

| ➜ Go to source code of ExtConfTemplateHelper::textfield()

Methods 

ExtConfTemplateHelper::textfield() 

\nn\t3::ExtConfTemplateHelper()->textfield($conf = []); 

Mehrzeiliges Textfeld / Textarea im Extension Manager Konfigurator zeigen. Diese Zeile in ext_conf_template.txt der eigenen Extension nutzen:

# cat=basic; type=user[Nng\Nnhelpers\Helpers\ExtConfTemplateHelper->textfield]; label=Mein Label
meinFeldName =
Copied!

| @return string

Source Code 

public function textfield( $conf = [] ) {
	return "<textarea style=\"min-height:100px\" name=\"{$conf['fieldName']}\" class=\"form-control\">{$conf['fieldValue']}</textarea>";
}
Copied!

JsonHelper 

\nn\t3::JsonHelper() 

Das Script hilft beim Konvertieren und Parsen von JavaScript-Objekt-Strings in ein Array.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

Der Helper ermöglicht es, im TypoScript die JavaScript-Object-Schreibweise zu nutzen und über den {nnt3:parse.json()} ViewHelper in ein Array zu konvertieren. Das ist praktisch, wenn z.B. Slider-Konfigurationen oder andere JavaScript-Objekte im TypoScript definiert werden sollen, um sie später in JavaScript zu nutzen.

Anderes Anwendungsbeispiel: Man möchte die "normalen" JS-Syntax in einer .json-Datei nutzen, statt dem JSON-Syntax. Schauen wir uns ein Beispiel an. Dieser Text wurde in eine Textdatei geschrieben und soll per PHP geparsed werden:

// Inhalte einer Textdatei.
{
    beispiel: ['eins', 'zwei', 'drei']
}
Copied!

PHP würde bei diesem Beispiel mit json_decode() einen Fehler melden: Der String enthält Kommentare, Umbrüche und die Keys und Values sind nicht in doppelte Anführungszeichen eingeschlossen. Der JsonHelper bzw. der ViewHelper $jsonHelper->decode() kann es aber problemlos umwandeln.

So könnte man im TypoScript Setup ein JS-Object definieren:

// Inhalt im TS-Setup
my_conf.data (
  {
     dots: true,
     sizes: [1, 2, 3]
  }
)
Copied!

Die Mischung irritiert ein wenig: my_conf.data (...) öffnet im TypoScript einen Abschnitt für mehrzeiligen Code. Zwischen den (...) steht dann ein "normales" JavaScript-Object. Das lässt sich im Fluid-Template dann einfach als Array nutzen:

{nnt3:ts.setup(path:'my_conf.data')->f:variable(name:'myConfig')}
{myConfig->nnt3:parse.json()->f:debug()}
Copied!

Oder als data-Attribut an ein Element hängen, um es später per JavaScript zu parsen:

{nnt3:ts.setup(path:'my_conf.data')->f:variable(name:'myConfig')}
<div data-config="{myConfig->nnt3:parse.json()->nnt3:format.attrEncode()}">...</div>
Copied!

Dieses Script basiert überwiegend auf der Arbeit von https://bit.ly/3eZuNu2 und wurde von uns für PHP 7+ optimiert.Alles an Ruhm und Ehre bitte in diese Richtung.

Overview of Methods 

\nn\t3::JsonHelper()->decode($str, $useArray = true); 

Wandelt einen JS-Object-String in ein Array um.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

Die PHP-Funktion json_decode() funktioniert nur bei der JSON-Syntax: {"key":"value"}. Im JSON sind weder Zeilenumbrüche, noch Kommentare erlaubt. Mit dieser Funktion können auch Strings in der JavaScript-Schreibweise geparsed werden.

| @return array|string

| ➜ Go to source code of JsonHelper::decode()

\nn\t3::JsonHelper()->encode($var); 

Konvertiert eine Variable ins JSON Format. Relikt der ursprünglichen Klasse, vermutlich aus einer Zeit als es json_encode() noch nicht gab.

\Nng\Nnhelpers\Helpers\JsonHelper::encode(['a'=>1, 'b'=>2]);
Copied!

| @return string;

| ➜ Go to source code of JsonHelper::encode()

\nn\t3::JsonHelper()->removeCommentsAndDecode($str, $useArray = true); 

Entfernt Kommentare aus dem Code und parsed den String.

\Nng\Nnhelpers\Helpers\JsonHelper::removeCommentsAndDecode( "// Kommentar\n{title:'Test', cat:[2,3,4]}" )
Copied!

| @return array|string

| ➜ Go to source code of JsonHelper::removeCommentsAndDecode()

Methods 

JsonHelper::decode() 

\nn\t3::JsonHelper()->decode($str, $useArray = true); 

Wandelt einen JS-Object-String in ein Array um.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

Die PHP-Funktion json_decode() funktioniert nur bei der JSON-Syntax: {"key":"value"}. Im JSON sind weder Zeilenumbrüche, noch Kommentare erlaubt. Mit dieser Funktion können auch Strings in der JavaScript-Schreibweise geparsed werden.

| @return array|string

Source Code 

public static function decode($str, $useArray=true)
{
	$str = trim($str);
	if(function_exists('json_decode'))
	{
		$json = json_decode($str,$useArray);
		if($json !== null)
			return $json;
	}
	$str = self::reduceString($str);
	switch (strtolower($str)) {
		case 'true':
			return true;
		case 'false':
			return false;
		case 'null':
			return null;
		default:
			if (is_numeric($str)) {
				// Lookie-loo, it's a number
				// This would work on its own, but I'm trying to be
				// good about returning integers where appropriate:
				// return (float)$str;
				// Return float or int, as appropriate
				return ((float)$str == (integer)$str)
					? (integer)$str
					: (float)$str;
			} elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) {
				// STRINGS RETURNED IN UTF-8 FORMAT
				$delim = substr($str, 0, 1);
				$chrs = substr($str, 1, -1);
				$utf8 = '';
				$strlen_chrs = strlen($chrs);
				for ($c = 0; $c < $strlen_chrs; ++$c) {
					$substr_chrs_c_2 = substr($chrs, $c, 2);
					$ord_chrs_c = ord($chrs[$c]);
					switch (true) {
						case $substr_chrs_c_2 == '\b':
							$utf8 .= chr(0x08);
							++$c;
							break;
						case $substr_chrs_c_2 == '\t':
							$utf8 .= chr(0x09);
							++$c;
							break;
						case $substr_chrs_c_2 == '\n':
							$utf8 .= chr(0x0A);
							++$c;
							break;
						case $substr_chrs_c_2 == '\f':
							$utf8 .= chr(0x0C);
							++$c;
							break;
						case $substr_chrs_c_2 == '\r':
							$utf8 .= chr(0x0D);
							++$c;
							break;
						case $substr_chrs_c_2 == '\\"':
						case $substr_chrs_c_2 == '\\\'':
						case $substr_chrs_c_2 == '\\\\':
						case $substr_chrs_c_2 == '\\/':
							if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
							   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
								$utf8 .= $chrs[++$c];
							}
							break;
						case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
							// single, escaped unicode character
							$utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
								   . chr(hexdec(substr($chrs, ($c+4), 2)));
							$utf8 .= self::utf16beToUTF8($utf16);
							$c+=5;
							break;
						case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
							$utf8 .= $chrs[$c];
							break;
						case ($ord_chrs_c & 0xE0) == 0xC0:
							// characters U-00000080 - U-000007FF, mask 110XXXXX
							//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
							$utf8 .= substr($chrs, $c, 2);
							++$c;
							break;
						case ($ord_chrs_c & 0xF0) == 0xE0:
							// characters U-00000800 - U-0000FFFF, mask 1110XXXX
							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
							$utf8 .= substr($chrs, $c, 3);
							$c += 2;
							break;
						case ($ord_chrs_c & 0xF8) == 0xF0:
							// characters U-00010000 - U-001FFFFF, mask 11110XXX
							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
							$utf8 .= substr($chrs, $c, 4);
							$c += 3;
							break;
						case ($ord_chrs_c & 0xFC) == 0xF8:
							// characters U-00200000 - U-03FFFFFF, mask 111110XX
							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
							$utf8 .= substr($chrs, $c, 5);
							$c += 4;
							break;
						case ($ord_chrs_c & 0xFE) == 0xFC:
							// characters U-04000000 - U-7FFFFFFF, mask 1111110X
							// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
							$utf8 .= substr($chrs, $c, 6);
							$c += 5;
							break;
					}
				}
				return $utf8;
			} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
				// array, or object notation
				if ($str[0] == '[') {
					$stk = array(self::JSON_IN_ARR);
					$arr = array();
				} else {
					if ($useArray) {
						$stk = array(self::JSON_IN_OBJ);
						$obj = array();
					} else {
						$stk = array(self::JSON_IN_OBJ);
						$obj = new stdClass();
					}
				}
				$stk[] = array('what' => self::JSON_SLICE, 'where' => 0, 'delim' => false);
				$chrs = substr($str, 1, -1);
				$chrs = self::reduceString($chrs);
				if ($chrs == '') {
					if (reset($stk) == self::JSON_IN_ARR) {
						return $arr;
					} else {
						return $obj;
					}
				}
				//print("\nparsing [$chrs}\n");
				$strlen_chrs = strlen($chrs);
				for ($c = 0; $c <= $strlen_chrs; ++$c) {
					$top = end($stk);
					$substr_chrs_c_2 = substr($chrs, $c, 2);
					if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == self::JSON_SLICE))) {
						// found a comma that is not inside a string, array, etc.,
						// OR we've reached the end of the character list
						$slice = substr($chrs, $top['where'], ($c - $top['where']));
						$stk[] = array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false);
						//print("Found split at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
						if (reset($stk) == self::JSON_IN_ARR) {
							// we are in an array, so just push an element onto the stack
							$val = self::decode($slice,$useArray);
							if (is_string($val)) $val = html_entity_decode($val);
							$arr[] = $val;
						} elseif (reset($stk) == self::JSON_IN_OBJ) {
							// we are in an object, so figure
							// out the property name and set an
							// element in an associative array,
							// for now
							if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
								// "name":value pair
								$key = self::decode($parts[1],$useArray);
								$val = self::decode($parts[2],$useArray);
								if (is_string($val)) $val = html_entity_decode($val);
								if ($useArray) {
									$obj[$key] = $val;
								} else {
									$obj->$key = $val;
								}
							} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
								// name:value pair, where name is unquoted
								$key = $parts[1];
								$val = self::decode($parts[2],$useArray);
								if (is_string($val)) $val = html_entity_decode($val);
								if ($useArray) {
									$obj[$key] = $val;
								} else {
									$obj->$key = $val;
								}
							}
						}
					} elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != self::JSON_IN_STR)) {
						// found a quote, and we are not inside a string
						$stk[] = array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c]);
						//print("Found start of string at [$c]\n");
					} elseif (($chrs[$c] == $top['delim']) &&
							 ($top['what'] == self::JSON_IN_STR) &&
							 (($chrs[$c - 1] != "\\") ||
							 ($chrs[$c - 1] == "\\" && $chrs[$c - 2] == "\\"))) {
						// found a quote, we're in a string, and it's not escaped
						array_pop($stk);
						//print("Found end of string at [$c]: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
					} elseif (($chrs[$c] == '[') &&
							 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
						// found a left-bracket, and we are in an array, object, or slice
						$stk[] = array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false);
						//print("Found start of array at [$c]\n");
					} elseif (($chrs[$c] == ']') && ($top['what'] == self::JSON_IN_ARR)) {
						// found a right-bracket, and we're in an array
						array_pop($stk);
						//print("Found end of array at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
					} elseif (($chrs[$c] == '{') &&
							 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
						// found a left-brace, and we are in an array, object, or slice
						$stk[] = array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false);
						//print("Found start of object at [$c]\n");
					} elseif (($chrs[$c] == '}') && ($top['what'] == self::JSON_IN_OBJ)) {
						// found a right-brace, and we're in an object
						array_pop($stk);
						//print("Found end of object at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
					} elseif (($substr_chrs_c_2 == '/*') &&
							 in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
						// found a comment start, and we are in an array, object, or slice
						$stk[] = array('what' => self::JSON_IN_CMT, 'where' => $c, 'delim' => false);
						$c++;
						//print("Found start of comment at [$c]\n");
					} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) {
						// found a comment end, and we're in one now
						array_pop($stk);
						$c++;
						for ($i = $top['where']; $i <= $c; ++$i)
							$chrs = substr_replace($chrs, ' ', $i, 1);
						//print("Found end of comment at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
					}
				}
				if (reset($stk) == self::JSON_IN_ARR) {
					return $arr;
				} elseif (reset($stk) == self::JSON_IN_OBJ) {
					return $obj;
				}
			}
	}
}
Copied!

JsonHelper::encode() 

\nn\t3::JsonHelper()->encode($var); 

Konvertiert eine Variable ins JSON Format. Relikt der ursprünglichen Klasse, vermutlich aus einer Zeit als es json_encode() noch nicht gab.

\Nng\Nnhelpers\Helpers\JsonHelper::encode(['a'=>1, 'b'=>2]);
Copied!

| @return string;

Source Code 

public static function encode($var) {
	return json_encode( $var );
}
Copied!

JsonHelper::removeCommentsAndDecode() 

\nn\t3::JsonHelper()->removeCommentsAndDecode($str, $useArray = true); 

Entfernt Kommentare aus dem Code und parsed den String.

\Nng\Nnhelpers\Helpers\JsonHelper::removeCommentsAndDecode( "// Kommentar\n{title:'Test', cat:[2,3,4]}" )
Copied!

| @return array|string

Source Code 

public static function removeCommentsAndDecode($str, $useArray=true) {
	$str = preg_replace('/\'([^\']*)(\/\/)([^\']*)\'/', '\'\1\\/\\/\3\'', $str);
	$str = preg_replace('/"([^"]*)(\/\/)([^"]*)"/', '"\1\\/\\/\3"', $str);
	$str = (new \Ahc\Json\Comment)->strip($str);
	$str = str_replace("\\/\\/", '//', $str);
	return self::decode( $str, $useArray );
}
Copied!

MarkdownHelper 

\nn\t3::MarkdownHelper() 

Ein Wrapper zum Parsen von markdown und Übersetzung in HTML und umgekehrt.

Overview of Methods 

\nn\t3::MarkdownHelper()->parseComment($comment = '', $encode = true); 

Kommentar-String zu lesbarem HTML-String konvertieren Kommentare können Markdown verwenden. Entfernt '' und '' etc.

\Nng\Nnhelpers\Helpers\MarkdownHelper::parseComment( '...' );
Copied!

| @return string

| ➜ Go to source code of MarkdownHelper::parseComment()

\nn\t3::MarkdownHelper()->removeAsterisks($comment = ''); 

Entfernt die Kommentar-Sternchen in einem Text.

\Nng\Nnhelpers\Helpers\MarkdownHelper::removeAsterisks( '...' );
Copied!

| @return string

| ➜ Go to source code of MarkdownHelper::removeAsterisks()

\nn\t3::MarkdownHelper()->toHTML($str = ''); 

Einen Text, der markdown enthält in HTML umwandeln.

\Nng\Nnhelpers\Helpers\MarkdownHelper::toHTML( '...' );
Copied!

| @return string

| ➜ Go to source code of MarkdownHelper::toHTML()

Methods 

MarkdownHelper::parseComment() 

\nn\t3::MarkdownHelper()->parseComment($comment = '', $encode = true); 

Kommentar-String zu lesbarem HTML-String konvertieren Kommentare können Markdown verwenden. Entfernt '' und '' etc.

\Nng\Nnhelpers\Helpers\MarkdownHelper::parseComment( '...' );
Copied!

| @return string

Source Code 

public static function parseComment ( $comment = '', $encode = true ) {
	$comment = self::removeAsterisks( $comment );
	if (!$encode) return $comment;
	$comment = htmlspecialchars( $comment );
	return self::toHTML( $comment );
}
Copied!

MarkdownHelper::removeAsterisks() 

\nn\t3::MarkdownHelper()->removeAsterisks($comment = ''); 

Entfernt die Kommentar-Sternchen in einem Text.

\Nng\Nnhelpers\Helpers\MarkdownHelper::removeAsterisks( '...' );
Copied!

| @return string

Source Code 

public static function removeAsterisks( $comment = '' ) {
	// Öffnenden und schließenden Kommentar löschen
	$comment = trim(str_replace(['/**', '/*', '*/'], '', $comment));
	// in Zeilen-Array konvertieren
	$lines = \nn\t3::Arrays($comment)->trimExplode("\n");
	$isCode = false;
	foreach ($lines as $k=>$line) {
		// \nn\t3...; immer als Code formatieren
		//$line = preg_replace("/((.*)(t3:)(.*)(;))/", '`\1`', $line);
		$line = preg_replace("/((.*)(@param)([^\$]*)([\$a-zA-Z]*))(.*)/", '`\1`\6', $line);
		$line = preg_replace("/((.*)(@return)(.*))/", '`\1`', $line);
		// Leerzeichen nach '* ' entfernen
		$line = preg_replace("/(\*)(\s)(.*)/", '\3', $line);
		$line = preg_replace("/`([\s]*)/", '`', $line, 1);
		$line = str_replace('*', '', $line);
		if (!$isCode) {
			$line = trim($line);
		}
		if (strpos($line, '```') !== false) $isCode = !$isCode;
		$lines[$k] = $line;
	}
	$comment = trim(join("\n", $lines));
	return $comment;
}
Copied!

MarkdownHelper::toHTML() 

\nn\t3::MarkdownHelper()->toHTML($str = ''); 

Einen Text, der markdown enthält in HTML umwandeln.

\Nng\Nnhelpers\Helpers\MarkdownHelper::toHTML( '...' );
Copied!

| @return string

Source Code 

public static function toHTML( $str = '' ) {
	if (!class_exists(\Parsedown::class)) {
		\nn\t3::autoload();
	}
	$parsedown = new \Parsedown();
	$result = $parsedown->text( $str );
	$result = str_replace(['&amp;amp;', '&amp;gt;', '&amp;#039;', '&amp;quot;', '&amp;apos;', '&amp;lt;'], ['&amp;', '&gt;', '&apos;', '&quot;', "&apos;", '&lt;'], $result);
	$result = trim($result);
	if (!$result) return '';
	$dom = new \DOMDocument();
	$dom->loadXML( '<t>' . $result . '</t>', LIBXML_NOENT | LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING );
	if (!$dom) return $result;
	if ($pre = $dom->getElementsByTagName('pre'));
	if (!$pre) return $result;
	foreach ($pre as $el) {
		if ($code = $el->getElementsByTagName('code')) {
			foreach ($code as $codeEl) {
				$codeEl->setAttribute('class', 'language-php');
			}
		}
	}
	$html = $dom->saveHTML( $dom->getElementsByTagName('t')->nodeValue ?? null );
	return trim(str_replace(['<t>', '</t>'], '', $html));
}
Copied!

TranslationHelper 

\nn\t3::TranslationHelper() 

Übersetzungsmanagement per Deep-L.

Damit diese Funktion nutzbar ist, muss im Extension-Manager von nnhelpers ein Deep-L Api-Key hinterlegt werden. Der Key ist ist kostenfrei und erlaubt die Übersetzung von 500.000 Zeichen pro Monat.

// Übersetzer aktivieren
$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );

// Übersetzung per Deep-L erlauben
$translationHelper->setEnableApi( true );
// Zielsprache festlegen
$translationHelper->setTargetLanguage( 'EN' );

// Max. Anzahl der Übersetzungen erlauben (zwecks Debugging)
$translationHelper->setMaxTranslations( 2 );

// Pfad, in dem die l18n-Dateien gespeichert / gecached werden sollen
$translationHelper->setL18nFolderpath( 'EXT:nnhelpers/Resources/Private/Language/' );

// Übersetzung starten
$text = $translationHelper->translate('my.example.key', 'Das ist der Text, der übersetzt werden soll');
Copied!

Overview of Methods 

\nn\t3::TranslationHelper()->createKeyHash($param = ''); 

Erzeugt einen eindeutigen Hash aus dem Key, der zur Identifizierung eines Textes benötigt wird. Jeder Text hat in allen Sprachen den gleichen Key.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['mein', 'key', 'array'] );
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::createKeyHash()

\nn\t3::TranslationHelper()->createTextHash($text = ''); 

Erzeugt einen eindeutigen Hash / Checksum aus dem Text. Der übergebene Text ist immer die Basis-Sprache. Ändert sich der Text in der Basissprache, gibt die Methode eine andere Checksum zurück. Dadurch wird erkannt, wann ein Text neu übersetzt werden muss. Reine Änderungen an Whitespaces und Tags werden ignoriert.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['mein', 'key', 'array'] );
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::createTextHash()

\nn\t3::TranslationHelper()->getEnableApi(); 

Gibt zurück, ob die API aktiviert ist.

$translationHelper->getEnableApi(); // default: false
Copied!

| @return boolean

| ➜ Go to source code of TranslationHelper::getEnableApi()

\nn\t3::TranslationHelper()->getL18nFolderpath(); 

Gibt den aktuellen Ordner zurück, in dem die Übersetzungs-Dateien gecached werden. Default ist typo3conf/l10n/nnhelpers/

$translationHelper->getL18nFolderpath();
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getL18nFolderpath()

\nn\t3::TranslationHelper()->getL18nPath(); 

Absoluten Pfad zur l18n-Cache-Datei zurückgeben. Default ist typo3conf/l10n/nnhelpers/[LANG].autotranslated.json

$translationHelper->getL18nPath();
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getL18nPath()

\nn\t3::TranslationHelper()->getMaxTranslations(); 

Holt die maximale Anzahl an Übersetzungen, die pro Instanz gemacht werden sollen.

$translationHelper->getMaxTranslations(); // default: 0 = unendlich
Copied!

| @return integer

| ➜ Go to source code of TranslationHelper::getMaxTranslations()

\nn\t3::TranslationHelper()->getTargetLanguage(); 

Holt die Zielsprache für die Übersetzung

$translationHelper->getTargetLanguage(); // Default: EN
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getTargetLanguage()

\nn\t3::TranslationHelper()->loadL18nData(); 

Komplette Sprach-Datei laden.

$translationHelper->loadL18nData();
Copied!

| @return array

| ➜ Go to source code of TranslationHelper::loadL18nData()

\nn\t3::TranslationHelper()->saveL18nData($data = []); 

Komplette Sprach-Datei speichern

$translationHelper->saveL18nData( $data );
Copied!

| @return boolean

| ➜ Go to source code of TranslationHelper::saveL18nData()

\nn\t3::TranslationHelper()->setEnableApi($enableApi); 

Aktiviert / Deaktiviert die Übersetzung per Deep-L.

$translationHelper->setEnableApi( true ); // default: false
Copied!
@param boolean $enableApi
@return self

| ➜ Go to source code of TranslationHelper::setEnableApi()

\nn\t3::TranslationHelper()->setL18nFolderpath($l18nFolderpath); 

Setzt den aktuellen Ordner, in dem die Übersetzungs-Dateien gecached werden. Idee ist es, die übersetzten Texte für Backend-Module nur 1x zu übersetzen und dann in dem Extension-Ordner zu speichern. Von dort werden sie dann ins GIT deployed.

Default ist typo3conf/l10n/nnhelpers/

$translationHelper->setL18nFolderpath('EXT:myext/Resources/Private/Language/');
Copied!
@param string $l18nFolderpath Pfad zum Ordner mit den Übersetzungsdateien (JSON)
@return self

| ➜ Go to source code of TranslationHelper::setL18nFolderpath()

\nn\t3::TranslationHelper()->setMaxTranslations($maxTranslations); 

Setzt die maximale Anzahl an Übersetzungen, die pro Instanz gemacht werden sollen. Hilft beim Debuggen (damit das Deep-L Kontingent nicht durch Testings ausgeschöpft wird) und bei TimeOuts, wenn viele Texte übersetzt werden müssen.

$translationHelper->setMaxTranslations( 5 ); // Nach 5 Übersetzungen abbrechen
Copied!
@param $maxTranslations
@return self

| ➜ Go to source code of TranslationHelper::setMaxTranslations()

\nn\t3::TranslationHelper()->setTargetLanguage($targetLanguage); 

Setzt die Zielsprache für die Übersetzung

$translationHelper->setTargetLanguage( 'FR' );
Copied!
@param string $targetLanguage Zielsprache der Übersetzung
@return self

| ➜ Go to source code of TranslationHelper::setTargetLanguage()

\nn\t3::TranslationHelper()->translate($key, $text = ''); 

Übersetzen eines Textes.

$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );
$translationHelper->setEnableApi( true );
$translationHelper->setTargetLanguage( 'EN' );
$text = $translationHelper->translate('my.example.key', 'Das ist der Text, der übersetzt werden soll');
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::translate()

Methods 

TranslationHelper::createKeyHash() 

\nn\t3::TranslationHelper()->createKeyHash($param = ''); 

Erzeugt einen eindeutigen Hash aus dem Key, der zur Identifizierung eines Textes benötigt wird. Jeder Text hat in allen Sprachen den gleichen Key.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['mein', 'key', 'array'] );
Copied!

| @return string

Source Code 

public function createKeyHash( $param = '' ) {
	return md5(json_encode(['_'=>$param]));
}
Copied!

TranslationHelper::createTextHash() 

\nn\t3::TranslationHelper()->createTextHash($text = ''); 

Erzeugt einen eindeutigen Hash / Checksum aus dem Text. Der übergebene Text ist immer die Basis-Sprache. Ändert sich der Text in der Basissprache, gibt die Methode eine andere Checksum zurück. Dadurch wird erkannt, wann ein Text neu übersetzt werden muss. Reine Änderungen an Whitespaces und Tags werden ignoriert.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['mein', 'key', 'array'] );
Copied!

| @return string

Source Code 

public function createTextHash( $text = '' ) {
	$text = strtolower(preg_replace('/\s+/', '', strip_tags( $text )));
	return md5($text);
}
Copied!

TranslationHelper::getEnableApi() 

\nn\t3::TranslationHelper()->getEnableApi(); 

Gibt zurück, ob die API aktiviert ist.

$translationHelper->getEnableApi(); // default: false
Copied!

| @return boolean

Source Code 

public function getEnableApi() {
	return $this->enableApi;
}
Copied!

TranslationHelper::getL18nFolderpath() 

\nn\t3::TranslationHelper()->getL18nFolderpath(); 

Gibt den aktuellen Ordner zurück, in dem die Übersetzungs-Dateien gecached werden. Default ist typo3conf/l10n/nnhelpers/

$translationHelper->getL18nFolderpath();
Copied!

| @return string

Source Code 

public function getL18nFolderpath() {
	return $this->l18nFolderpath;
}
Copied!

TranslationHelper::getL18nPath() 

\nn\t3::TranslationHelper()->getL18nPath(); 

Absoluten Pfad zur l18n-Cache-Datei zurückgeben. Default ist typo3conf/l10n/nnhelpers/[LANG].autotranslated.json

$translationHelper->getL18nPath();
Copied!

| @return string

Source Code 

public function getL18nPath() {
	$path = rtrim($this->getL18nFolderpath(), '/').'/';
	$file = \nn\t3::File()->absPath( $path . strtolower($this->targetLanguage) . '.autotranslated.json' );
	return $file;
}
Copied!

TranslationHelper::getMaxTranslations() 

\nn\t3::TranslationHelper()->getMaxTranslations(); 

Holt die maximale Anzahl an Übersetzungen, die pro Instanz gemacht werden sollen.

$translationHelper->getMaxTranslations(); // default: 0 = unendlich
Copied!

| @return integer

Source Code 

public function getMaxTranslations() {
	return $this->maxTranslations;
}
Copied!

TranslationHelper::getTargetLanguage() 

\nn\t3::TranslationHelper()->getTargetLanguage(); 

Holt die Zielsprache für die Übersetzung

$translationHelper->getTargetLanguage(); // Default: EN
Copied!

| @return string

Source Code 

public function getTargetLanguage() {
	return $this->targetLanguage;
}
Copied!

TranslationHelper::loadL18nData() 

\nn\t3::TranslationHelper()->loadL18nData(); 

Komplette Sprach-Datei laden.

$translationHelper->loadL18nData();
Copied!

| @return array

Source Code 

public function loadL18nData() {
	if ($cache = $this->l18nCache) return $cache;
	$path = $this->getL18nPath();
	$data = json_decode( \nn\t3::File()->read($path), true ) ?: [];
	return $this->l18nCache = $data;
}
Copied!

TranslationHelper::saveL18nData() 

\nn\t3::TranslationHelper()->saveL18nData($data = []); 

Komplette Sprach-Datei speichern

$translationHelper->saveL18nData( $data );
Copied!

| @return boolean

Source Code 

public function saveL18nData( $data = [] ) {
	$path = $this->getL18nPath();
	$success = \nn\t3::File()->write($path, json_encode($data));
	if (!$success) {
		\nn\t3::Exception('l18n-Datei konnte nicht geschrieben werden: ' . $path);
	}
	$this->l18nCache = $data;
	return $path;
}
Copied!

TranslationHelper::setEnableApi() 

\nn\t3::TranslationHelper()->setEnableApi($enableApi); 

Aktiviert / Deaktiviert die Übersetzung per Deep-L.

$translationHelper->setEnableApi( true ); // default: false
Copied!
@param boolean $enableApi
@return self

Source Code 

public function setEnableApi($enableApi) {
	$this->enableApi = $enableApi;
	return $this;
}
Copied!

TranslationHelper::setL18nFolderpath() 

\nn\t3::TranslationHelper()->setL18nFolderpath($l18nFolderpath); 

Setzt den aktuellen Ordner, in dem die Übersetzungs-Dateien gecached werden. Idee ist es, die übersetzten Texte für Backend-Module nur 1x zu übersetzen und dann in dem Extension-Ordner zu speichern. Von dort werden sie dann ins GIT deployed.

Default ist typo3conf/l10n/nnhelpers/

$translationHelper->setL18nFolderpath('EXT:myext/Resources/Private/Language/');
Copied!
@param string $l18nFolderpath Pfad zum Ordner mit den Übersetzungsdateien (JSON)
@return self

Source Code 

public function setL18nFolderpath($l18nFolderpath) {
	$this->l18nFolderpath = $l18nFolderpath;
	return $this;
}
Copied!

TranslationHelper::setMaxTranslations() 

\nn\t3::TranslationHelper()->setMaxTranslations($maxTranslations); 

Setzt die maximale Anzahl an Übersetzungen, die pro Instanz gemacht werden sollen. Hilft beim Debuggen (damit das Deep-L Kontingent nicht durch Testings ausgeschöpft wird) und bei TimeOuts, wenn viele Texte übersetzt werden müssen.

$translationHelper->setMaxTranslations( 5 ); // Nach 5 Übersetzungen abbrechen
Copied!
@param $maxTranslations
@return self

Source Code 

public function setMaxTranslations($maxTranslations) {
	$this->maxTranslations = $maxTranslations;
	return $this;
}
Copied!

TranslationHelper::setTargetLanguage() 

\nn\t3::TranslationHelper()->setTargetLanguage($targetLanguage); 

Setzt die Zielsprache für die Übersetzung

$translationHelper->setTargetLanguage( 'FR' );
Copied!
@param string $targetLanguage Zielsprache der Übersetzung
@return self

Source Code 

public function setTargetLanguage($targetLanguage) {
	$this->targetLanguage = $targetLanguage;
	return $this;
}
Copied!

TranslationHelper::translate() 

\nn\t3::TranslationHelper()->translate($key, $text = ''); 

Übersetzen eines Textes.

$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );
$translationHelper->setEnableApi( true );
$translationHelper->setTargetLanguage( 'EN' );
$text = $translationHelper->translate('my.example.key', 'Das ist der Text, der übersetzt werden soll');
Copied!

| @return string

Source Code 

public function translate( $key, $text = '' ) {
	$keyHash = $this->createKeyHash( $key );
	$textHash = $this->createTextHash( $text );
	$l18nData = $this->loadL18nData();
	$translation = $l18nData[$keyHash] ?? ['_cs'=>false];
	$textChanged = $translation['_cs'] != $textHash;
	$autoTranslateEnabled = $this->enableApi && ($this->maxTranslations == 0 || $this->maxTranslations > $this->numTranslations );
	// Text wurde übersetzt und hat sich nicht geändert
	if (!$textChanged) {
		$str = $translation['text'];
		$str = str_replace('.</p>.', '.</p>', $str);
		return $str;
	}
	// Text wurde nicht übersetzt und Deep-L Übersetzung ist deaktiviert
	if (!$autoTranslateEnabled) {
		if ($translation['_cs'] !== false) {
			return "[Translation needs {$this->targetLanguage} update] " . $text;
		}
		return "[Translate to {$this->targetLanguage}] " . $text;
	}
	$this->numTranslations++;
	echo "Translating via Deep-L: {$this->numTranslations} / {$this->maxTranslations} [$keyHash] " . json_encode($key) . "\n";
	$result = \nn\t3::LL()->translate( $text, $this->targetLanguage );
	$l18nData[$keyHash] = [
		'_cs' => $textHash,
		'text' => $result,
	];
	$this->saveL18nData( $l18nData );
	return $result;
}
Copied!

TypoScriptHelper 

\nn\t3::TypoScriptHelper() 

Helper for TypoScript

$typoScriptHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TypoScriptHelper::class );
$typoScriptHelper->getTypoScript( 1 );
Copied!

All credits to this script go to Stoppeye on StackOverflow: https://stackoverflow.com/questions/77151557/typo3-templateservice-deprecation-how-to-get-plugin-typoscript-not-in-fe-cont

Overview of Methods 

\nn\t3::TypoScriptHelper()->getTypoScript($pageUid = NULL); 

Get complete TypoScript setup for a given page ID following TYPO3 13 approach.

$typoScriptHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TypoScriptHelper::class );

// get typoscript for current page
$typoScriptHelper->getTypoScript();

// get typoscript for page with uid 1
$typoScriptHelper->getTypoScript( 1 );
Copied!
@param int $pageUid Page UID to get TypoScript for
@return array Complete TypoScript setup with dot-syntax

| ➜ Go to source code of TypoScriptHelper::getTypoScript()

\nn\t3::TypoScriptHelper()->getTypoScriptObject($pageUid = NULL); 

Get the TypoScript setup as TypoScript object.

@param int $pageUid Page UID to get TypoScript for
@return \TYPO3\CMS\Core\TypoScript\FrontendTypoScript

| ➜ Go to source code of TypoScriptHelper::getTypoScriptObject()

Methods 

TypoScriptHelper::getTypoScript() 

\nn\t3::TypoScriptHelper()->getTypoScript($pageUid = NULL); 

Get complete TypoScript setup for a given page ID following TYPO3 13 approach.

$typoScriptHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TypoScriptHelper::class );

// get typoscript for current page
$typoScriptHelper->getTypoScript();

// get typoscript for page with uid 1
$typoScriptHelper->getTypoScript( 1 );
Copied!
@param int $pageUid Page UID to get TypoScript for
@return array Complete TypoScript setup with dot-syntax

Source Code 

public function getTypoScript(?int $pageUid = null): array
{
	$ts = $this->getTypoScriptObject($pageUid);
	$settings = [];
	if ($ts->hasPage() && $ts->hasSetup()) {
		$settings = $ts->getSetupTree()->toArray();
	}
	return $settings;
}
Copied!

TypoScriptHelper::getTypoScriptObject() 

\nn\t3::TypoScriptHelper()->getTypoScriptObject($pageUid = NULL); 

Get the TypoScript setup as TypoScript object.

@param int $pageUid Page UID to get TypoScript for
@return \TYPO3\CMS\Core\TypoScript\FrontendTypoScript

Source Code 

public function getTypoScriptObject(?int $pageUid = null): FrontendTypoScript
{
	if (!$pageUid) {
		$pageUid = \nn\t3::Page()->getPid();
	}
	// make sure, we don't get config from disabled TS templates in BE context
	$context = GeneralUtility::makeInstance(Context::class);
	$visibilityAspect = GeneralUtility::makeInstance(VisibilityAspect::class);
	$context->setAspect('visibility', $visibilityAspect);
	$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($pageUid);
	if (!$site) {
		throw new \Exception('Site not found for page ID ' . $pageUid);
	}
	$pageInformation = $this->getPageInformation($site, $pageUid);
	$isCachingAllowed = false;
	$conditionMatcherVariables = $this->prepareConditionMatcherVariables($site, $pageInformation);
	$frontendTypoScript = $this->frontendTypoScriptFactory->createSettingsAndSetupConditions(
		$site,
		$pageInformation->getSysTemplateRows(),
		$conditionMatcherVariables,
		$isCachingAllowed ? $this->typoScriptCache : null,
	);
	$ts = $this->frontendTypoScriptFactory->createSetupConfigOrFullSetup(
		true,  // $needsFullSetup -> USER_INT
		$frontendTypoScript,
		$site,
		$pageInformation->getSysTemplateRows(),
		$conditionMatcherVariables,
		'0',  // $type -> typeNum (default: 0; GET/POST param: type)
		$isCachingAllowed ? $this->typoScriptCache : null,
		null,  // $request
	);
	return $ts;
}
Copied!

ViewHelpers Index 

abstract 

Description 

<nnt3:abstract /> 

Dieser ViewHelper ist keine eigener ViewHelper, der in Fluid nutzbar ist.

Er dient als Basis-Klasse für Deine eigenen ViewHelper.

| $escapeOutput = false wird als Default gesetzt. Falls XSS-Angriffe bei Deinem ViewHelper ein Problem sein könnten, solltest dies überschreiben.

Nutze extend in Deinem eigenen ViewHelper, um ihn zu verwenden. Hier ein Beispiel-Boilerplate, mit allem, was Du zum Loslegen brauchst:

<?php
namespace My\Ext\ViewHelpers;

use Nng\Nnhelpers\ViewHelpers\AbstractViewHelper;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;

class ExampleViewHelper extends AbstractTagBasedViewHelper {

 public function initializeArguments() {
     parent::initializeArguments();
     $this->registerArgument('title', 'string', 'Infos', false);
 }

 public static function renderStatic( array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext ) {

     // Einfach `$title` statt `$arguments['title']` nutzen
     foreach ($arguments as $k=>$v) {
        ${$k} = $v;
     }

     // Rendert Inhalt zwischen dem ViewHelper-Tag
     if (!$title) $title = $renderChildrenClosure();

     // Beispiel, um an alle aktuellen Variable im Fluid-Template zu kommen
     // $templateVars = \nn\t3::Template()->getVariables( $renderingContext );

     return $title;
 }
}
Copied!

abstractTagBased 

Description 

<nnt3:abstractTagBased /> 

Dieser ViewHelper ist keine eigener ViewHelper, der in Fluid nutzbar ist. Er dient als Basis-Klasse für Deine eigenen, Tag-basierten ViewHelper.

Nutze extend in Deinem eigenen ViewHelper, um ihn zu verwenden. Hier ein Beispiel-Boilerplate, mit allem, was Du zum Loslegen brauchst:

<?php
namespace My\Ext\ViewHelpers;

use \Nng\Nnhelpers\ViewHelpers\AbstractTagBasedViewHelper;

class ExampleViewHelper extends AbstractTagBasedViewHelper {

 protected $tagName = 'div';

 public function initializeArguments() {
     parent::initializeArguments();
     $this->registerArgument('title', 'string', 'Infos', false);
 }
 public function render() {
     $args = ['item'];
     foreach ($args as $arg) ${$arg} = $this->arguments[$arg] ?: '';
     $content = $this->renderChildren();
     $this->tag->setContent($content);
     return $this->tag->render();
 }
}
Copied!

backendUser.get 

Description 

<nnt3:backendUser.get /> 

Frontend-User holen

Gibt ein Array mit den Daten des Backend-Users zurück, enthält auch die Einstellungen des Users.

{nnt3:backendUser.get(key:'uc.example')}
{nnt3:backendUser.get()->f:variable.set(name:'beUser')}
Copied!

color.convert 

Description 

<nnt3:color.convert /> 

Eine Farben konvertieren

{hex->nn:color.convert(to:'rgb')}
Copied!

content.column 

Description 

<nnt3:content.column /> 

Rendert die Inhalte einer Spalte (colPos) des Backend Layouts. Wird keine Seiten-ID über pid angegeben, verwendet er die aktuelle Seiten-ID.

{nnt3:content.column(colPos:110)}
Copied!

Mit slide werden die Inhaltselement der übergeordnete Seite geholt, falls auf der angegeben Seiten kein Inhaltselement in der Spalte existiert.

{nnt3:content.column(colPos:110, slide:1)}
Copied!

Mit pid kann der Spalten-Inhalt einer fremden Seite gerendert werden:

{nnt3:content.column(colPos:110, pid:99)}
Copied!

Slide funktioniert auch für fremde Seiten:

{nnt3:content.column(colPos:110, pid:99, slide:1)}
Copied!

| @return string

content.columnData 

Description 

<nnt3:content.columnData /> 

Lädt die rohen Daten einer Spalte (colPos) des Backend Layouts.

Es handelt sich hier um das rohe tt_content-data-Array einer Spalte (colPos) aus dem Backend-Layout. Per default werden auch die Relationen (FAL, assets, media...) geladen. Kann per relations:0 verhindert werden.

{nnt3:content.columnData(colPos:110)}
{nnt3:content.columnData(colPos:110, pid:99, relations:0)}
Copied!

| @return array

contentElement 

Description 

<nnt3:contentElement /> 

Ein Content-Element rendern

Der von uns wahrscheinlich meist genutzte ViewHelper.

Content-Element aus der Tabelle tt_content mit der uid: 123 rendern.

{nnt3:contentElement(uid:123)}
Copied!

Content-Element aus der Tabelle tt_content render, bei dem tt_content.content_uuid = 'footer' ist.

{nnt3:contentElement(uid:'footer', field:'content_uuid')}
Copied!

Variablen im gerenderten Content-Element ersetzen. Erlaubt es, im Backend ein Inhaltselement anzulegen, das mit Fluid-Variablen arbeitet – z.B. für ein Mail-Template, bei dem der Empfänger-Name im Text erscheinen soll.

{nnt3:contentElement(uid:123, data:'{greeting:\'Hallo!\'}')}
{nnt3:contentElement(uid:123, data:feUser.data)}
Copied!

Zum Rendern der Variablen muss nicht zwingend eine contentUid übergeben werden. Es kann auch direkt HTML-Code geparsed werden:

{data.bodytext->nnt3:contentElement(data:'{greeting:\'Hallo!\'}')}
Copied!

| @return string

die 

Description 

<nnt3:die /> 

Macht nichts, außer das Script zu beenden.

Damit kann während des Rendering-Prozesses von Fluid das Script abgebrochen werden. Praktisch, um z.B. Mail-Templates zu debuggen.

{nnt3:die()}
Copied!

| @return death

encrypt.hash 

Description 

<nnt3:encrypt.hash /> 

Generiert einen Hash aus einem String oder einer Zahl.

{secret->nnt3:encrypt.hash()}
{nnt3:encrypt(value:secret)}
Copied!

Hilfreich, falls z.B. eine Mail versendet werden soll mit Bestätigungs-Link.

Die UID des Datensatzes wird zusätzlich als Hash übergeben. Im Controller wird dann überprüft, ob aus der übergeben uid der übergeben hash generiert werden kann. Falls nicht, wurde die uid manipuliert.

<f:link.action action="validate" arguments="{uid:uid, checksum:'{uid->nnt3:encrypt.hash()}'}">
  ...
</f:link.action>
Copied!

| @return string

explode 

Description 

<nnt3:explode /> 

Macht aus einem String ein Array

{nnt3:explode(str:'1,2,3')}
{mystring->nnt3:explode()}
{mystring->nnt3:explode(delimiter:';')}
{mystring->nnt3:explode(trim:0)}
Copied!

| @return void

file.absPath 

Description 

<nnt3:file.absPath /> 

Absolute URL zu einer Datei holen.

{nnt3:file.absPath(file:'pfad/zum/bild.jpg')}
Copied!

| @return string

file.exists 

Description 

<nnt3:file.exists /> 

Prüft, ob eine Datei existiert.

{nnt3:file.exists(file:'pfad/zum/bild.jpg')}
Copied!
<f:if condition="!{nnt3:file.exists(file:'pfad/zum/bild.jpg')}">
  Wo ist das Bild hin?
</f:if>
Copied!

| @return boolean

file.include 

Description 

<nnt3:file.include /> 

Fügt den Inhalt einer Datei ein.

{nnt3:file.include(file:'pfad/zur/datei.html')}
Copied!

| @return string

flashMessages 

Description 

<nnt3:flashMessages /> 

Gibt eine Flash-Message aus.

Im Controller:

\nn\t3::Message()->OK('Titel', 'Infotext');
\nn\t3::Message()->setId('oben')->ERROR('Titel', 'Infotext');
Copied!

Im Fluid:

<nnt3:flashMessages />
<nnt3:flashMessages id='oben' />
Copied!

Die Core-Funktionen:

<f:flashMessages queueIdentifier='core.template.flashMessages' />
<f:flashMessages queueIdentifier='oben' />
Copied!

| @return string

format.attrEncode 

Description 

<nnt3:format.attrEncode /> 

Maskiert "kritische" Zeichen, damit sie als Attribut an einen HTML-Tag verwendet werden können.

<div data-example="{something->nnt3:format.attrEncode()}"> ... </div>
<a title="{title->nnt3:format.attrEncode()}"> ... </a>
Copied!

| @return string

format.code 

Description 

<nnt3:format.code /> 

Highlighted code-Abschnitte per PrismJS.

Der Code kann über download zum direkten Download verfügbar gemacht werden.

Die Datei wird dabei dynamisch per JS generiert und gestreamt – es enstehen keine zusätzlichen Dateien auf dem Server. nnhelpers nutzt diese Funktion, um die Boilerplates als Download anzubieten.

Mehr Infos unter: https://prismjs.com/

Build: https://bit.ly/3BLqmx0

<nnt3:format.code lang="css" download="rte.css">
  ... Markup ...
</nnt3:format.code>

<nnt3:format.code lang="none">
  ... Markup ...
</nnt3:format.code>
Copied!

| @return string

format.htmlToSphinx 

Description 

<nnt3:format.htmlToSphinx /> 

Konvertiert HTML-Tags zu Sphinx-Syntax für die TER Dokumentation.

{annotation->f:format.raw()->nnt3:format.htmlToSphinx()}
Copied!

Aus folgendem Code ...

<nnt3:format.htmlToSphinx>
  <p>Das ist eine Beschreibung dieser Methode</p>
  <pre><code>$a = 99;</code></pre>
</nnt3:format.htmlToSphinx>
Copied!

wird das hier gerendert:

Das ist eine Beschreibung dieser Methode

.. code-block:: php

   $a = 99;
Copied!

| @return string

format.indentCode 

Description 

<nnt3:format.indentCode /> 

Fügt eine Einrückung (Indentation) zu jeder Zeile eines Code-Blocks hinzu. Wird für die Sphinx-Dokumentation verwendet, um Code innerhalb von .. code-block:: korrekt einzurücken.

{sourceCode->nnt3:format.indentCode(spaces: 3)}
Copied!

| @return string

format.jsonEncode 

Description 

<nnt3:format.jsonEncode /> 

Wandelt ein Array oder Object ins JSON-Format um.

{some.object->nnt3:format.jsonEncode()}
Copied!

| @return string

format.replace 

Description 

<nnt3:format.replace /> 

Text in einem String suchen und ersetzen.

{nnt3:format.replace(str:'alles schön im Juli.', from:'Juli', to:'Mai')}
{varname->nnt3:format.replace(from:'Juli', to:'Mai')}
Copied!

| @return string

frontendUser.get 

Description 

<nnt3:frontendUser.get /> 

Frontend-User holen

Gibt ein Array mit den Daten des Frontend-Users zurück, z.B. um Seiten, Mails oder Inhalte zu personalisieren.

{nnt3:frontendUser.get(key:'first_name')}
{nnt3:frontendUser.get()->f:variable.set(name:'feUser')}
Copied!

image 

Description 

<nnt3:image /> 

Vereinfacht die Verwendung des ImageViewhelpers.

Wirft keinen Fehler, falls kein image oder src übergeben wurde. Erlaubt auch die Übergabe eines Arrays, zieht sich einfach das erste Bild.

// tt_content.image ist eigentlich ein Array. Es wird einfach das erste Bild gerendert!
{nnt3:image(image:data.image)}

// wirft keinen Fehler (falls der Redakteur kein Bild hochgeladen hat!)
{nnt3:image(image:'')}
Copied!

page.data 

Description 

<nnt3:page.data /> 

Vereinfacht den Zugriff auf Daten aus der Tabelle pages.

{nnt3:page.data()}
{nnt3:page.data(key:'nnp_contact', slide:1)}
{nnt3:page.data(key:'backend_layout_next_level', slide:1, override:'backend_layout')}
Copied!

Wichtig, damit slide funktioniert: Falls die Tabelle pages um ein eigenes Feld erweitert wurde, muss das Feld vorher in der ext_localconf.php registriert werden.

\nn\t3::Registry()->rootLineFields(['logo']);
Copied!

page.title 

Description 

<nnt3:page.title /> 

Aktuelle Page-Title setzen.

Andert das <title>-Tag der aktuellen Seite.

Funktioniert nicht, wenn EXT:advancedtitle aktiviert ist!

{nnt3:page.title(title:'Seitentitel')}
{entry.title->nnt3:page.title()}
Copied!

pagination.paginate 

Description 

<nnt3:pagination.paginate /> 

Ersatz für den f:widget.paginate ViewHelper, der in TYPO3 12 entfernt wurde. DICKES DANKE an https://www.in2code.de/ für den Blog-Beitrag!

Partial für den Paginator in eigene Extension einbinden

plugin.tx_myext_plugin {
partialRootPaths {
 10 = EXT:nnhelpers/Resources/Private/Partials/
}
}
Copied!

Im Fluid-Template:

<nnt3:pagination.paginate objects="{allItemsFromQuery}" as="items" paginator="paginator" itemsPerPage="{settings.numItemsPerPage}">
<!-- Items render -->
<f:for each="{items}" as="item">
 ...
</f:for>
<!-- Pagination rendern aus nnhelpers -->
<f:render partial="Pagination" arguments="{paginator:paginator}" />
</nnt3>
Copied!

| @return string

pagination.uri 

Description 

<nnt3:pagination.uri /> 

UriViewHelper

parse.code 

Description 

<nnt3:parse.code /> 

Ensures HTML entities inside <code> blocks are properly encoded.

This is useful when displaying code examples that may contain HTML tags which should be shown as readable code, not rendered as HTML.

{item.comment->nnt3:parse.code()->f:format.raw()}
Copied!

| @return string

parse.flexForm 

Description 

<nnt3:parse.flexForm /> 

Parsed ein FlexForm (XML) und macht daraus ein Array.

Praktisch, falls man einen rohen Datensatz der Tabelle tt_content vor sich hat und an einen Wert aus dem FlexForm in pi_flexform braucht.

{row.pi_flexform->nnt3:parse.flexForm()->f:debug()}
Copied!

| @return array

parse.json 

Description 

<nnt3:parse.json /> 

Wandelt ein normales JavaScript-Object, dass als String übergeben wird in ein Array um. Erlaubt es, Konfigurationen für Slider und andere JS-Bibliotheken im TypoScript anzulegen und später per JS zu parsen.

Siehe JsonHelper für Beispiele.

{myConfig->nnt3:parse.json()->f:debug()}
Copied!
<div data-config="{myConfig->nnt3:parse.json()->nnt3:format.attrEncode()}">
  ...
</div>
Copied!

| @return mixed

parse.markdown 

Description 

<nnt3:parse.markdown /> 

Wandelt einen String mit Markdown in HTML um.

{myMarkdownCode->nnt3:parse.markdown()}
Copied!

| @return mixed

translate 

Description 

<nnt3:translate /> 

Einen Text übersetzen, inkl. optionaler Übersetzung über Deep-L.

Siehe auch Doku zu TranslationHelper für die Einbindung über PHP oder einen Controller.

// Übersetzung über locallang.xlf
{mytext->nnt3:translate(id:'LLL:EXT:nnaddress/Resources/Private/Language/locallang_db.xlf:my-ll-id')}
{mytext->nnt3:translate(id:'my-ll-id', extensionName:'nnaddress')}
Copied!
// Übersetzung per Deep-L
{nnt3:translate(id:'my-ll-id', text:'Der Text', extensionName:'nnaddress', enableApi:1, translate:1, targetLang:'EN', maxTranslations:2)}
{mytext->nnt3:translate(id:'my-ll-id', extensionName:'nnaddress', enableApi:1, translate:1, targetLang:'EN', maxTranslations:2)}
{mytext->nnt3:translate(id:'my-ll-id', enableApi:1, translate:1, targetLang:'EN', cacheFolder:'EXT:nnsite/path/to/somewhere/')}
{mytext->nnt3:translate(id:'my-ll-id', enableApi:1, translate:1, targetLang:'EN', cacheFolder:'typo3conf/l10n/demo/')}
Copied!
// Einen Block im Fluid-Template übersetzen
<nnt3:translate id="text-id-or-cObj-uid" enableApi="1" translate="1" targetLang="EN">
  <p>Ich werde automatisch übersetzt, inkl. aller <b>HTML</b>-Tags!</p>
</nnt3:translate>
Copied!

ts.constants 

Description 

<nnt3:ts.constants /> 

Wert aus den TypoScript-Constants holen.

Einfacher und direkter Zugriff aus dem Fluid-Template heraus - unabhängig von der Extension, die das Template rendert.

{nnt3:ts.constants(path:'pfad.zur.constant')}
{nnt3:ts.constants(path:'pfad.zur', key:'constant')}
{nnt3:ts.constants(path:'pfad.{dynamicKey}.whatever')}
Copied!

| @return mixed

ts.extConf 

Description 

<nnt3:ts.extConf /> 

Konfiguration für eine Extension aus dem Extension-Manager holen.

{nnt3:ts.extConf(path:'nnfiletransfer.pathLogo')}
{nnt3:ts.extConf(path:'nnfiletransfer', key:'pathLogo')}
Copied!

| @return mixed

ts.page 

Description 

<nnt3:ts.page /> 

Wert aus der PageTSconfig holen.

Einfacher und direkter Zugriff aus dem Fluid-Template heraus - unabhängig von der Extension, die das Template rendert.

{nnt3:ts.page(path:'pfad.zum.page.config')}
{nnt3:ts.page(path:'pfad.zum.page', key:'config')}
{nnt3:ts.page(path:'pfad.zum.page.{dynamicKey}.whatever')}
Copied!

| @return mixed

ts.setup 

Description 

<nnt3:ts.setup /> 

Wert aus dem TypoScript-Setup holen.

Einfacher und direkter Zugriff aus dem Fluid-Template heraus - unabhängig von der Extension, die das Template rendert.

{nnt3:ts.setup(path:'pfad.zum.typoscript.setup')}
{nnt3:ts.setup(path:'pfad.zum.typoscript', key:'setup')}
{nnt3:ts.setup(path:'pfad.zum.typoscript.{dynamicKey}.whatever')}
Copied!

| @return mixed

uniqid 

Description 

<nnt3:uniqid /> 

Gibt eine eindeutige, einmalige ID zurück.

Hilfreich z.B. für eindeutige IDs oder Klassen-Namen in Fluid-Templates.

{nnt3:uniqid()}
Copied!
<div id="box-{nnt3:uniqid()}"> ... </div>
Copied!

| @return string

uri.image 

Description 

<nnt3:uri.image /> 

Vereinfacht die Verwendung des Uri.ImageViewhelpers.

Wirft keinen Fehler, falls kein image oder src übergeben wurde. Erlaubt auch die Übergabe eines Arrays, zieht sich einfach das erste Bild.

// tt_content.image ist eigentlich ein Array. Es wird einfach das erste Bild gerendert!
{nnt3:uri.image(image:data.image)}

// wirft keinen Fehler (falls der Redakteur kein Bild hochgeladen hat!)
{nnt3:uri.image(image:'')}
Copied!

uri.page 

Description 

<nnt3:uri.page /> 

Erzeugt ein URL zu einer Seite im Frontend. Entspricht fast exakt dem Typo3 ViewHelper {f:uri.page()} - kann allerdings auch in einem Kontext verwendet werden, bei dem kein Frontend (TSFE) existiert, z.B. im Template eines Backend-Moduls oder in Mail-Templates eines Scheduler-Jobs.

{nnt3:uri.page(pageUid:1, additionalParams:'...')}
Copied!

video.embedUrl 

Description 

<nnt3:video.embedUrl /> 

Konvertiert eine youTube-URL in die watch-Variante, z.B. für die Einbindung in ein iFrame.

{my.videourl->nnt3:video.embedUrl()}
Copied!
<iframe src="{my.videourl->nnt3:video.embedUrl()}"></iframe>
Copied!

widget.accordion 

Description 

<nnt3:widget.accordion /> 

Widget zur Darstellung eines Akkordeons.

Wird in nnhelpers massenhaft in den Templates des Backend-Moduls genutzt.

<nnt3:widget.accordion title="Titel" icon="fas fa-plus" class="nice-thing">
  ...
</nnt3:widget.accordion>
Copied!
<nnt3:widget.accordion template="EXT:myext/path/to/template.html" title="Titel" icon="fas fa-plus" class="nice-thing">
  ...
</nnt3:widget.accordion>
Copied!
{nnt3:widget.accordion(title:'Titel', content:'...' icon:'fas fa-plus', class:'nice-thing')}
Copied!

| @return string

Use Cases & Examples 

Debugging 

Du denkst vielleicht: Die Typo3 DebuggerUtility ist großartig. Ja, ist sie.

Aber: Hast Du jemals versucht, einen QueryBuilder zu debuggen, weil Du mit dem "Old School" Blick auf ein SQL-Statement besser verstehst, was genau bei Deiner Datenbankabfrage schief geht? Hast Du Dich dann gewundert, dass Du keine Paramter siehst, sondern nur ? an den entscheidenden Stellen? Wie lange hast Du gegoogelt, um eine Antwort zu finden und Dich dann wieder einmal gefragt: "Muss das so kompliziert sein?"

Ist es Dir schon mal passiert, dass Du ein debug() im Code vergessen hast und am nächsten Morgen einfach nicht mehr wusstest, wo Du diesen debug hingeschrieben hast? Wäre es nicht schön, einfach die Zeilennummer und das Script direkt sehen zu können, die das debug getriggert hat?

Wenn Du auch sonst keine einzige anderer Methode aus nnhelpers anfassen wirst: Hier ist die eine Zeile, nach der Du süchtig werden wirst:

\nn\t3::debug( $whatever );
Copied!

Extensions entwickeln 

Wenn man Jahre lang Extensions für Typo3 entwickelt, freut man sich über vieles. Aber man wundert sich auch oft.

Eine davon: Seit einigen Versionen, kann man Icons für das Backend (z.B. für ein Backend-Modul) nicht mehr als Pfad zum svg oder jpg angeben. Stattdessen geht man den Umweg über die IconRegistry und registriert das Icon in der ext_tables.php.

Mag Sinn haben. Aber es wird ja noch komplizierter. Abhängig vom Dateityp muss man zunächst den passenden IconProvider dazu instanziieren. Für ein svg landet man so bei einigen Zeilen Code – vom SvgIconProvider bis zum IconRegistry.

Das ist eine Menge Hirnschmalz dafür, dass doch eigentlich das Suffix .svg sagen sollte, um welchen Dateityp es sich handelt.

Wir finden, Helpers könnte uns diese Denkarbeit abnehmen:

\nn\t3::Registry()->icon('my-icon-identifier', 'EXT:myext/Resources/Public/Icons/wizicon.svg');
Copied!

TCAaaalbträume 

Noch einer unserer Lieblinge: Im TCA ein Feld für eine FAL Relation definieren. Erinnerst Du Dich an die 28 Zeilen code, um einen Dateiupload im Backend zu ermöglichen? Hast Du gemerkt, dass sich die Struktur gerne von Version zu Version ändert – und musstest Du durch alle TCAs gehen und die Anpassungen nachziehen?

Hier ist ein magischer Einzeiler für Dein nächstes FAL:

'falprofileimage' => [
   'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage'),
],
Copied!

Ach, Du vermisst die Optionen? Kein Problem:

'falprofileimage' => [
   'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage', ['maxitems'=>1, 'fileExtensions'=>'jpg']),
],
Copied!

Und natürlich gibt es noch viele, weitere Einzeiler, z.B. für die Definition eines Texteditors (ckeditor).

Das beste daran: Wenn das Core-Team sich entscheidet, von ckeditor Abschied zu nehmen (so wie sie es - zum Glück - vor einigen Jahren mit der rtehtmlarea getan haben), dann wird das nicht mehr Dein Problem sein. Lass es das Problem von nnhelpers sein.

'mytextfield' => [
   'config' => \nn\t3::TCA()->getRteTCAConfig(),
],
Copied!

Wir wäre es mit einem Farbwähler?

'mycolor' => [
   'config' => \nn\t3::TCA()->getColorPickerTCAConfig(),
],
Copied!

Ein FlexForm in ein TCA-Feld einschleusen 

Lass uns durchdrehen. Schon mal darüber nachgedacht, ein externes FlexForm in ein TCA-Feld einzuschleusen? Im Grunde macht Typo3 das ja bei jedem Plugin. Und DCE definiert über FlexForms den gesamten Inhalt des DCE-Elementes.

Nicht träumen. Coden. Und – klar – natürlich mal wieder mit einem einzigen Einzeiler.

'myoptions' => [
   'config' => \nn\t3::TCA()->insertFlexForm('FILE:EXT:path/to/yourFlexForm.xml');
],
Copied!

Klingt vielleicht verrückt, aber tatsächlich nutzen wir diese Methode ständig – vor allem im Kontext mit der besten Extension, die je für Typo3 erfunden wurde: Mask (EXT:mask).

Im folgenden Beispiel hatten wir ca. 30 Slider-Optionen für Übergänge, Dauer, Breakpoints / Responsivität und vieles mehr. Jede Option sollte in dem Mask-Element vom Redakteur auswählbar sein. Mit den Standard-Feldern von EXT:mask hätten wir die Datenbank-Tabelle tt_content um 30 Felder erweitern müssen. Felder, an die keine andere Logik gebunden ist – keine Indizierung, Sortierung oder Suche. So ein Fall schreit förmlich nach einem FlexForm statt einzelnen Datenbank-Feldern.

Mask selbst erlaubt (noch) kein FlexForm. Aber, was viele nicht wissen: Felder lassen sich in der Configuration/TCA/Overrides/tt_content.php seiner eigenen Extension einfach neu konfigurieren. (Achtung, Stolperfalle: Die eigene Extension muss eine Dependency zu mask in der ext_emconf.php definiert haben!)

Das ganze sieht dann so aus:

if ($_GET['route'] != '/module/tools/MaskMask') {
   if ($GLOBALS['TCA']['tt_content']['columns']['tx_mask_slideropt']) {
      $GLOBALS['TCA']['tt_content']['columns']['tx_mask_slideropt']['config'] = \nn\t3::TCA()->insertFlexForm('FILE:EXT:myext/Configuration/FlexForm/customFlexForm.xml');
   }
}
Copied!

FlexForm pimpen 

In einem Plugin (FlexForm) möchte man häufig dem Redakteur die Möglichkeit bieten, zwischen verschiendenen Layouts, Farben oder Designs zu wählen. Dazu nutzt man üblicherweise eine select / selectSingle Definition mit allen Optionen.

Praktischer finde ich es persönlich, wenn sich die Optionen, die im Dropdown erscheinen, per TypoScript-Setup oder PageTSconfig definieren lassen. Pro "Ast" im Seitenbaum können so unterschiedliche Optionen zur Verfügung gestellt werden. Außerdem finde ich es "praktischer" nicht jedesmal, wenn eine Option dazukommt, im XML des FlexForms zu hantieren.

Hier ist ein schöner, kleiner Helfer dazu:

<config>
   <type>select</type>
   <renderType>selectSingle</renderType>
   <items type="array"></items>
   <itemsProcFunc>nn\t3\Flexform->insertOptions</itemsProcFunc>
   <typoscriptPath>plugin.tx_extname.settings.colors</typoscriptPath>
   <!-- Alternativ: Load options from the PageTSConfig: -->
   <pageconfigPath>tx_extname.colors</pageconfigPath>
   <insertEmpty>1</insertEmpty>
</config>
Copied!

Stimmt – und dann ist da noch die Sache mit der Länderauswahl im FlexForm. Warum auch hier komplizierter werden, als unbedingt nötig?

<config>
   <type>select</type>
   <renderType>selectSingle</renderType>
   <items type="array"></items>
   <itemsProcFunc>nn\t3\Flexform->insertCountries</itemsProcFunc>
   <insertEmpty>1</insertEmpty>
</config>
Copied!

Mails senden 

Großartig. Typo3 hat sich gerade von SwiftMailer verabschiedet. Erinnerst Du Dich? Das hatten wir vor ein paar Jahren schon mal – als Typo3 den Schritt ZU SwiftMailer gemacht hat. Blöd, wenn man mail in 562 Extensions genutzt hat.

Ach, und: Sorry, nein. Wir haben vor dem letzten großen Typo3 Update nicht Stunden damit verbracht, uns durch alle breaking changes zu wühlen. Wenn wir ehrlich sind, läuft ein Update auf eine neue LTS immer so ab: Helm auf, anschnallen und auf den ersten Knall warten. Google wird uns schon irgendwie aus der Unfallstelle rausschneiden.

Gut zu wissen, dass sich ab sofort ein paar Dinge **nie wieder*+ ändern werden.

\nn\t3::Mail()->send([
   'html'	=> $html,
   'fromEmail'	=> 'me@somewhere.de',
   'toEmail'	=> 'you@faraway.de',
   'subject'	=> 'Nice'
]);
Copied!

Angst vor Outlook? Nichts mehr zu befürchten. Der Mailhelper hat einen kleinen, weitere Gehilfen am Start: Emogrifier. Der lässt sich auch mit einer Option abschalten – aber wozu... er beantwortet vielleicht eine Frage, die Du noch gar nicht gestellt hattest.

Und wie sieht es mit Dateianhängen aus?

\nn\t3::Mail()->send([
   ...
   'attachments' => ['path/to/file.jpg', 'path/to/other.pdf']
]);
Copied!

| Schön – aber hattest Du nicht letztes Mal das Problem, dass Du die Anhänge dynamisch während des Rendering Deines Mail-Templates einbinden wolltest? Kopf zerbrochen? Wie wäre es hiermit gewesen? Ein data-embed="1" in Deinem Template und Dein neuer, bester Freund macht die Denkarbeit für Dich.

<img data-embed="1" src="path/to/image.jpg" />
{f:image(image:fal, maxWidth:200, data:'{embed:1}')}

<a href="attach/this/file.pdf" data-embed="1">Download</a>
{f:link.typolink(parameter:file, data:'{embed:1}')}
Copied!

Fluid rendern 

In dem Beispiel oben haben wir noch gar nicht über den StandaloneView zum Rendern von Templates gesprochen. Klar, macht nnhelpers Dir auch hier das Leben leichter:

\nn\t3::Template()->render( 'path/to/template.html', $vars );
Copied!

Da war noch die Sache mit den partialRootPaths, layoutRootPaths etc. Aber mal ehrlich: Ist man denn nicht (fast) immer in einer Extension, die auch die Templates dazu im Standard-Template-Ordner dieser Extension hat?

\nn\t3::Template()->render( 'Templatename', $vars, 'myext' );
Copied!

Der Extension-Key genügt – nnhelpers übernimmt das Nachschauen, was Du in Deiner Extension unter plugin.tx_myext.view... definiert hast.

Aber dann kann es natürlich auch sein, dass Du partialRootPaths doch selbst festlegen möchtest. Geht natürlich auch:

\nn\t3::Template()->render( 'Templatename', $vars, [
   'templateRootPaths' => ['EXT:myext/Resource/Somewhere/Templates/', ...],
   'layoutRootPaths' => ['EXT:myext/Resource/Somewhere/Layouts/', ...],
]);
Copied!

Die Beispiel zeigen, was nnhelpers besonders macht. Nicht strict sondern smart ist hier der Ansatz. Wenn Du einfach das tust, was Du intuitiv tun würdest, dann kannst Du relativ sicher sein: Genau so haben wir bei der Entwicklung von nnhelpers auch gedacht.

Daten von einer Extension migrieren 

Wir haben kürzlich ein großes Projekt von Typo3 7 LTS auf Typo3 10 LTS aktualisiert. Das Projekt hatte Calendar Base (EXT:cal) im Einsatz und stolze 5.000 Kalendereinträge. Leider wurde EXT:cal (noch) nicht für Typo3 10 aktualisiert, so dass wir uns entschlossen, auf unsere eigene Kalendererweiterung nncalendar umzusteigen (die in ein paar Wochen im TER veröffentlicht wird).

Wir standen vor drei großen Herausforderungen:

  • Es war unmöglich, EXT:cal in Typo3 10 zu aktivieren - folglich gab es keine einfache Möglichkeit, auf die Datenbank-Tabellen von Calendar Base zuzugreifen oder "schöne" Modelle mit Gettern und Settern zu erstellen
  • Calendar Base hatte in Version 7 noch eine eigene Kategorisierung und verwendete noch keine sys_category.
  • Es gab tonnenweise Bilder im Ordner uploads/pics/, die in FAL-Bilder umgewandelt und an das neue EntryModel von nncalendar angehängt werden mussten

Das ist das destillerte Ergebnis:

// Holt alle Datensätze von EXT:cal. Die Ext muss dazu nicht aktiviert sein!
$calData = \nn\t3::Db()->statement( "SELECT * FROM tx_cal_event WHERE deleted = 0");

// Das neue Repo für die Kalender-Einträge
$calendarRepository = \nn\t3::injectClass(\Nng\Nncalendar\Domain\Repository\EntryRepository::class);

// NnCalendar-Modelle aus den rohen array-Daten erzeugen!
foreach ($calData as $row) {

   // [...] hier gab es noch ein paar Zeilen Code, um Datum etc. zu parsen.

   $entry = \nn\t3::Convert($row)->toModel( \Nng\Nncalendar\Domain\Model\Entry::class );
   $calendarRepository->add( $entry );
}

\nn\t3::Db()->persistAll();
Copied!

Auch die neuen SysCategories zu setzen war so einfach:

$row['category'] = [1, 4, 3];
$entry = \nn\t3::Convert($row)->toModel( \Nng\Nncalendar\Domain\Model\Entry::class );
Copied!

nnhelpers erkennt automatisch, dass das Entry-Model eine Relation zu den SysCategories im Feld category hat und erzeugt die ObjectStorage mit den SysCategories automatisch.

Bei den Bildern wurde es auch nicht komplizierter:

// e.g. $oldPath = 'uploads/pics/image.jpg' - $newPath = 'fileadmin/calendar/image.jpg'
\nn\t3::File()->copy( $oldPath, $newPath );

$row['falImage'] = $newPath;
$entry = \nn\t3::Convert($row)->toModel( \Nng\Nncalendar\Domain\Model\Entry::class );
Copied!

Auch hier erkennt nnhelpers automatisch, dass die Property falImage ein FAL or eine ObjectStorage im Entry-Model möchte und erzeugt die sys_file und sys_file_reference automatisch.

Fein. Und was machst Du jetzt den Rest des Tages?

Database operations 

Ich kann mich nicht erinnern, wie oft wir einfach nur ein direktes und unkompliziertes Update, Löschen oder Einfügen von einzelnen Datensätzen in einer Datenbanktabelle durchführen wollten.

Doctrine ist eine der genialsten Kreationen der vergangenen Jahre, aber es gibt Anwendungsfälle, bei denen man einfach einfach bleiben möchte. Und was ist einfacher, als ein Einzeiler – der im Hintergrund daraus eine "ganz normale" Doctrine Query baut.

Hier ist ein kleiner Auszug aus den nn\t3::Db()-Methoden, die uns jeden Tag Zeit sparen:

Daten des Frontend-User mit uid = 12 laden:

$feUser = \nn\t3::Db()->findByUid('fe_user', 12);
Copied!

Enable-Felder ignorieren (hidden, start_time etc.)

$feUser = \nn\t3::Db()->findByUid('fe_user', 12, true);
Copied!

Alle Datensätze der Tabelle tx_news_domain_model_news laden:

$news = \nn\t3::Db()->findAll('tx_news_domain_model_news');
Copied!

Alle Frontend-User laden, die Donny heißen:

$feUser = \nn\t3::Db()->findByValues('fe_users', ['first_name'=>'Donny']);
Copied!

Den ersten Frontend-User laden, der Peter heißt:

$feUser = \nn\t3::Db()->findOneByValues('fe_users', ['first_name'=>'Peter']);
Copied!

Die storagePid für ein Repository ignorieren:

$myRepo = \nn\t3::injectClass( MyRepo::class );
\nn\t3::Db()->ignoreEnableFields( $myRepo );
Copied!

Ignoriere the storagePid and das hidden-Flag für ein Repository

$myRepo = \nn\t3::injectClass( MyRepo::class );
\nn\t3::Db()->ignoreEnableFields( $myRepo, true, true );
Copied!

Side-by-Side 

Du glaubst noch immer nicht, dass diese kleine Extension Deinen Typo3-Alltag auf den Kopf stellen könnte?

Werfen wir einen Blick auf einige klassische Aufgaben. Die linke Spalte wirst Du gut kennen: So arbeitest Du bisher. Rechts daneben siehst Du die Lösung mit nnhelpers. Vergleiche nicht nur die Anzahl der Code-Zeilen, die für das Lösen der Aufgabe erforderlich sind - sondern auch den geistigen Energieaufwand, den man braucht, um sich die Schritte, Methoden und Parameter zu merken.

Achten auch darauf, wie sich das z.B. Grundkonzept beim Erstellen von Links im Backend-Kontext von Version 8 zu 9 verändert hat. Ja, die Situation hat sich deutlich verbessert. Aber denke mal an die Zeit, die Du wieder gebraucht hättest, diese Lösung zu finden und sie in allen Deinen Extensions zu aktualisieren!

Dann sieh Dir den nnhelpers-Einzeiler auf der rechten Seite an. Siehst Du den Unterschied im Aufbau von Links im Frontend- oder Backend-Kontext? Und wie steht es mit dem Sprung von Version 8 LTS zu 9 LTS?

Ich denke, Du verstehst, um was es geht.

Ein TypoScript-Setup außerhalb des Controllers erhalten 

Aufgabe: Du möchtest den Wert für demo.path aus den TypoScript-Settings eines Plugins holen, aber leider bist Du nicht in einem Kontext, bei dem $this->settings vorhanden ist. Vielleicht bist Du in einem Repository – oder ViewHelper.

Standard Typo3

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;

$objectManager = GeneralUtility::makeInstance( ObjectManager::class );
$configurationManager = $objectManager->get( ConfigurationManager::class );
$settings = $configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, null, 'tx_my_ext');
$value = $settings['demo']['path'] ?? '';
Copied!

MIT nnhelpers

$value = \nn\t3::Settings()->get('my_ext_table', 'demo.path');
Copied!

Einen Datensatz aus der Datenbank lesen 

Aufgabe: Eine "rohe" Zeile aus der Datenbank lesen anhand seiner uid.

Standard Typo3

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

$queryBuilder = GeneralUtility::makeInstance( ConnectionPool::class )
   ->getQueryBuilderForTable( 'my_ext_table' )
   ->select('*')
   ->from( 'my_ext_table' );
$queryBuilder->andWhere(
   $queryBuilder->expr()->eq( 'uid', $queryBuilder->createNamedParameter( 99 ))
);
$row = $queryBuilder->executeQuery()->fetchAllAssociative();
Copied!

MIT nnhelpers

\nn\t3::Db()->findByUid('my_ext_table', 99);
Copied!

Alle Zeilen in der Datenbank holen 

Aufgabe: Alle Daten einer Tabelle aus der Datenbank lesen, aber die Flags für hidden sowie die start_time und end_time ignorieren. Diese Anwendung hat man häufig, wenn man extrem viele Datensätze möglichst performant und ohne Model braucht, z.B. für einen Eport nach Excel.

Standard Typo3

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\Query\Restriction;

$queryBuilder = GeneralUtility::makeInstance( ConnectionPool::class )
   ->getQueryBuilderForTable( 'my_ext_table' )
   ->select('*')
   ->from( 'my_ext_table' );
$restrictions = $queryBuilder->getRestrictions();				
$restrictions->removeByType( StartTimeRestriction::class );
$restrictions->removeByType( EndTimeRestriction::class );
$restrictions->removeByType( HiddenRestriction::class );

$rows = $queryBuilder->executeQuery()->fetchAllAssociative();
Copied!

MIT nnhelpers

\nn\t3::Db()->findAll('my_ext_table', true);
Copied!

Screenshots 

Viele, zeitsparende Helferlein 

nnhelpers Backend Module

Praktische Suchfunktion 

nnhelpers Backend Module

Quelltext direkt im Backend einsehen 

nnhelpers Backend Module

One-Click Download der Vorlagen 

nnhelpers Backend Module

Automatisches Namespacing 

nnhelpers Backend Module

Change log 

Version 1.0.0 

First public release after many years of development and improvement.

Bekannte Probleme 

Leider massenhafte Problem in Verbindung mit der großen, roten Warnung auf dieser Seite

Helpers für WordPress 

Wir haben eine Vision. 

Was wäre, wenn es eine ähnliche Sammlung an "Helfern" für andere Content-Management-Systeme gäbe? Wenn die Methoden sogar (fast) deckungsgleich wären? Wenn man als Entwickler zwischen Joomla, WordPress, Drupal, NodeJS und TYPO3 einfach "springen" könnte, ohne sich immer wieder in andere Konzepte und Core-APIs einzuarbeiten.

Das ist die Idee hinter nnhelpers – mit dem langfristigen Ziel, sogar einen Großteil des Codes zwischen unterschiedlichen CMS wiederverwendbar zu machen. Klar: Das ist ein Traum und er ist mit Hürden verbunden. Aber allein zu wissen: Es gibt \nn\t3::debug() oder \nn\t3::Db()->findAll() oder \nn\t3::Environment()->getBaseUrl() – und dieser Befehl ist Framework-übergreifend gleich wäre schon eine große Hilfe. Egal, ob man nnhelpers dann wirklich nutzen will – oder einfach nur als "Spickzettel" verwendet, um zu sehen, wie die Funktion im Detail innerhalb des jeweiligen Systems implementiert wird.

Wir haben in 2022 einen Startpunkt gesetzt und angefangen, wphelpers ins Leben zu rufen: Eine Spiegelung von nnhelpers für WordPress!

nng/wphelpers auf packagist | WpHelpers im GIT auf bitbucket.org

TYPO3Fluid als Rendering Engine in WordPress nutzen 

Was war einer unserer ersten Schritte und Methoden der wphelpers? Eine vernünftige Template-Engine an den Start bringen. WordPress setzt ja bekanntlich auf PHP-Templating – aus Sicht eines Fluid- oder Twig-verwöhnten Entwicklers eher eine anachronistische Vollkatastrophe.

Mit wphelpers kann man jetzt innerhalb seines WordPress-Plugins jetzt diese schöne Zeile nutzen:

\nn\wp::Template()->render('EXT:my_wp_plugin/path/to/template.php', ['demo'=>123]);
Copied!

... und damit ein Fluid-Template rendern! Dank der Community, die Fluid als Standalone Version bereit gestellt hat. Und da Fluid immer noch eine der besten Template-Engines ist – warum nicht WordPress damit "upgraden". Damit sind schon mal alle Templates der TYPO3-Extensions in WordPress wiederverwendbar.

Und die Performance? WordPress argumentiert immer, dass nichts performanter als ein PHP-Template ist. Aber wer Fluid kennt, der weiß, dass alle Templates (wie auch bei Smarty etc.) in reinen PHP-Code "übersetzt" und gecached werden. Es wird also faktisch kaum einen Unterschied in der Performance geben.

Let's do it! 

Wenn es dort draußen noch andere Teams gibt, die sich in den Paralleluniversen zwischen TYPO3, WordPress etc. bewegen und diese Idee interessant finden: Was haltet ihr davon? Lust, mit einzusteigen? Lust eine Methode auf nnhelpers in ein anderes System zu übersetzen? Let's start the revolution ;)

Wir freuen uns auf Euer Feedback!

Sitemap