99° Helpers for TYPO3 

Extension key

nnhelpers

Package name

nng/nnhelpers

Version

2.0.4

Language

en

Author

99°

License

This document is published under the Creative Commons BY 4.0 license.

Rendered

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


A comprehensive collection of helper utilities for TYPO3 extension development.

Table of Contents

Introduction 

What does it do? 

Let it (nn)help you, whenever things seem to get more compliated that they should be.

Let's look at a few examples: 

Let's say you have built an upload form. The user can upload an image in the frontend. You would like to have the image as FAL on a model.

Sounds like an everyday task, doesn't it? So: Let's ask Google. After countless variations of search phrases, you land on a promising doc at docs.typo3.org.

You work your way through many lines of information and end up with this statement: Not our business. Take care of it yourself, or steal it from Helmut. You then spend then the next 30 minutes with lovely Helmut. Enjoying beautiful source codes. And searching desperately for the little snippet you need for your project.

I don't know how long it took you to solve this task the first time. For us it was about four hours. We were in Typo3 version 6 at that time. When the 7 LTS was released, we searched again because some things changed in the core. When version 8 LTS was released, it was again almost 2 hours. And then the adaption had to be done over and over again for ALL our extensions that implemented a file upload from the frontend context.

This is a nightmare and time that seems kind of pointless. I prefer to spend this time - without batting an eye - with my choleric mother-in-law.

How would we solve this task today?

We would ask nnhelpers for help.
So let's switch to the backend module of nnhelpers and have a look:

nnhelpers Backend Module

The backend module shows all methods nicely grouped by topics.

What were we looking for?
Right. Something related to FAL.
So let's use the search function or scroll down to the FAL section.

nnhelpers Backend Module

Every method has detailed examples and use-cases.

setInModel() sounds pretty much like the thing we're looking for.
Lets look at an the examples.

Now wait, are you really telling me, all I need is this f..g line of code?
WTF? No ObjectManager->get(), no @inject? Just a no-brainer ONELINER?

And the best part is: This onliner won't ever change.
Not for Typo3 Version 7. Not for Typo3 11. We promise.

\nn\t3::Fal()->setInModel( $model, 'fieldname', 'path/to/image.jpg' );
Copied!
Well, what if the user uploads multiple images?
Sure, I could use a foreach. But wait... there's more!

\nn\t3::Fal()->setInModel( $model, 'fieldname', ['image-1.jpg', 'image-2.jpg'] );
Copied!
Yeah, nice. But this is cheating.
My app is more complex. The user can set a title and description for the image.
Ehm. Wait a minute.

\nn\t3::Fal()->setInModel( $member, 'fieldname', ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'] );
Copied!
HA! Got you. You are mixing things up here.
Now the user can't upload multiple files with titles and descriptions.
But damn, what is this?

\nn\t3::Fal()->setInModel( $member, 'fieldname', [
   ['publicUrl'=>'01.jpg', 'title'=>'Titel', 'description'=>'...'],
   ['publicUrl'=>'02.jpg', 'title'=>'Titel', 'description'=>'...'],
]);
Copied!
Yeah, but that is breaking the rules I learned at the university!! This is ugly!!
Right. But if it is simple, we simply don't care.
This is a line of code you can remember. And if not: next time you will know, where to find it.

You still don't like it?
Fine, then have a look at the source code and steal, what you need to build it by yourself. No need to leave the backend and dive into the source code of nnhelpers. It's all here where it should be.

nnhelpers Backend Module

Every method has detailed examples and use-cases.

Ok, it's your decision. ;)

Got it? Stop thinking, start coding. 

Installation 

Nothing really special about the installation. Simply do, what you always do to get the extension up and running.

No need to add any TypoScript Templates.

You love the Extension Manager? 

Press the Retrieve/Update button and search for the extension key nnhelpers and import the extension from the repository. Start coding. Have fun.

Nothing beats handwork? 

You can always get current version from https://extensions.typo3.org/extension/nnhelpers/. Download the t3x or zip version. Upload the file afterwards in the Extension Manager.

composer is your friend? 

In case you are in a composer mode installation of typo3, you can require the latest release from packagist with

composer require nng/nnhelpers
Copied!

Want to git it? 

You can get the latest version from bitbucket.org by using the git command:

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

Defining dependencies 

If you want to use nnhelpers in your own extension, make sure to define the dependeny in your ext_emconf.php and composer.json:

This goes in the ext_emconf.php of your extension:

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

And this is the part for the composer.json of your extension:

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

Helpers Index 

Arrays 

\nn\t3::Arrays() 

Various methods for working with arrays such as merging, cleaning or removing empty values. Methods to use a value of an associative array as a key.

Overview of Methods 

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

Returns the first element of the array, without array_shift()

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

| @return array

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

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

Split a string â or array â at the separator, remove non-numeric and remove empty elements

\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); 

Use a field in the array as the key of the array, e.g. to get a list, whose key is always the UID of the associative array:

Example:

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

| @return array

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

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

Merge an associative array recursively with another array.

$addKeys => if false, only keys that also exist in $arr1 are overwritten
$includeEmptyValues => if true, empty values are also included in $arr1
$enableUnsetFeature => if true, __UNSET can be used as a value in $arr2 to delete a value in $arr1
$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); 

Reduce / distill associative array to specific elements:

\nn\t3::Arrays( $objArr )->key('uid')->pluck('title'); // ['1'=>'title A', '2'=>'title B']
\nn\t3::Arrays( $objArr )->key('uid')->pluck(['title', 'bodytext']); // ['1'=>['title'=>'Title A', 'bodytext'=>'Content'], '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(); 

Remove empty values from an array.

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

| @return array

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

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

Returns this array object as a "normal" array.

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

| @return array

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

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

Split a string â or array â at the separator, remove empty elements Works with strings and 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(); 

Returns the first element of the array, without 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 = ','); 

Split a string â or array â at the separator, remove non-numeric and remove empty elements

\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); 

Use a field in the array as the key of the array, e.g. to get a list, whose key is always the UID of the associative array:

Example:

$arr = [['uid'=>'1', 'title'=>'Title A'], ['uid'=>'2', 'title'=>'Title B']];
\nn\t3::Arrays($arr)->key('uid'); // ['1'=>['uid'=>'1', 'title'=>'Title A'], '2'=>['uid'=>'2', 'title'=>'Title B']]
\nn\t3::Arrays($arr)->key('uid', 'title'); // ['1'=>'Title A', '2'=>'Title 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(); 

Merge an associative array recursively with another array.

$addKeys => if false, only keys that also exist in $arr1 are overwritten
$includeEmptyValues => if true, empty values are also included in $arr1
$enableUnsetFeature => if true, __UNSET can be used as a value in $arr2 to delete a value in $arr1
$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); 

Reduce / distill associative array to specific elements:

\nn\t3::Arrays( $objArr )->key('uid')->pluck('title'); // ['1'=>'title A', '2'=>'title B']
\nn\t3::Arrays( $objArr )->key('uid')->pluck(['title', 'bodytext']); // ['1'=>['title'=>'Title A', 'bodytext'=>'Content'], '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(); 

Remove empty values from an array.

$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(); 

Returns this array object as a "normal" array.

\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); 

Split a string â or array â at the separator, remove empty elements Works with strings and 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() 

Methods to check in the frontend whether a user is logged into the Typo3 backend and has admin rights, for example. Methods to start a backend user if it does not exist (e.g. during a scheduler job).

Overview of Methods 

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

Gets the current backend user. Corresponds to $GLOBALS['BE_USER'] in previous Typo3 versions.

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

| @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication

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

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

Get the cookie name of the backend user cookie. Usually be_typo_user, unless it has been changed in the LocalConfiguration.

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

return string

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

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

Retrieves user-specific settings for the currently logged in backend user. See \nn\t3::BackendUser()->updateSettings() to save the data.

\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(); 

Checks whether the BE user is an admin. Earlier: $GLOBALS['TSFE']->beUserLogin

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

| @return bool

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

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

Checks whether a BE user is logged in. Example: Only show certain content in the frontend if the user is logged in in the backend. Previously: $GLOBALS['TSFE']->beUserLogin

// Check after complete initialization of the front/backend
\nn\t3::BackendUser()->isLoggedIn();

// Check using the JWT, e.g. in an eID script before authentication
\nn\t3::BackendUser()->isLoggedIn( $request );
Copied!
@param ServerRequest $request
@return bool

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

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

Start (fake) backend user. Solves the problem that, for example, certain functions from the scheduler such as log() are not possible if there is no active BE user.

\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 = []); 

Saves user-specific settings for the currently logged in backend user. These settings are also available again for the user after logout/login. See \nn\t3::BackendUser()->getSettings('myext') to read the data.

\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(); 

Gets the current backend user. Corresponds to $GLOBALS['BE_USER'] in previous Typo3 versions.

\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(); 

Get the cookie name of the backend user cookie. Usually be_typo_user, unless it has been changed in the LocalConfiguration.

\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); 

Retrieves user-specific settings for the currently logged in backend user. See \nn\t3::BackendUser()->updateSettings() to save the data.

\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(); 

Checks whether the BE user is an admin. Earlier: $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); 

Checks whether a BE user is logged in. Example: Only show certain content in the frontend if the user is logged in in the backend. Previously: $GLOBALS['TSFE']->beUserLogin

// Check after complete initialization of the front/backend
\nn\t3::BackendUser()->isLoggedIn();

// Check using the JWT, e.g. in an eID script before authentication
\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(); 

Start (fake) backend user. Solves the problem that, for example, certain functions from the scheduler such as log() are not possible if there is no active BE user.

\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 = []); 

Saves user-specific settings for the currently logged in backend user. These settings are also available again for the user after logout/login. See \nn\t3::BackendUser()->getSettings('myext') to read the data.

\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() 

Methods for reading and writing to the Typo3 cache. Uses the Typo3 caching framework, see EXT:nnhelpers/ext_localconf.php for details

Overview of Methods 

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

Deletes caches. If an identifier is specified, only the caches of the specific identifier are deleted identifier are deleted â otherwise ALL caches of all extensions and pages.

RAM caches CachingFramework caches that were set via \nn\t3::Cache()->set() File caches that were set via \nn\t3::Cache()->write()

// delete ALL caches â also the caches of other extensions, pages etc.
\nn\t3::Cache()->clear();

// Delete only the caches with a specific identifier
\nn\t3::Cache()->clear('nnhelpers');
Copied!
@param string $identifier
@return void

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

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

Deletes the page cache. Alias to \nn\t3::Page()->clearCache()

\nn\t3::Cache()->clearPageCache( 17 ); // Delete page cache for pid=17
\nn\t3::Cache()->clearPageCache(); // clear cache of ALL pages
Copied!
@param mixed $pid pid of the page whose cache is to be cleared or leave empty for all pages
@return void

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

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

Reads the content of the Typo3 cache using an identifier. The identifier is any string or array that uniquely identifies the cache.

\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 or array to identify the cache
@param mixed $useRamCache temporary cache in $GLOBALS instead of caching framework

| @return mixed

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

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

Converts transferred cache identifiers into a usable string. Can also process an array as identifier.

@param mixed $indentifier
@return string

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

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

Read static file cache.

Reads the PHP file that was written via \nn\t3::Cache()->write().

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

The PHP file is an executable PHP script with the return command It stores the cache content in an array.

...];
Copied!

| @return string|array

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

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

Writes an entry to the Typo3 cache. The identifier is an arbitrary string or an array that uniquely identifies the cache.

// Classic application in the controller: Get and set cache
if ($cache = \nn\t3::Cache()->get('myid')) return $cache;
...
$cache = $this->view->render();
return \nn\t3::Cache()->set('myid', $cache);
Copied!
// Use RAM cache? Set TRUE as the third parameter
\nn\t3::Cache()->set('myid', $dataToCache, true);

// Set the duration of the cache to 60 minutes
\nn\t3::Cache()->set('myid', $dataToCache, 3600);

// An array can also be specified as the key
\nn\t3::Cache()->set(['pid'=>1, 'uid'=>'7'], $html);
Copied!
@param mixed $indentifier String or array to identify the cache
@param mixed $data Data to be written to the cache. (string or array)
@param mixed $useRamCache true: temporary cache in $GLOBALS instead of caching framework.
integer: How many seconds to cache?

| @return mixed

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

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

Write static file cache.

Writes a PHP file that can be loaded via $cache = require('...').

Based on many core functions and extensions (e.g. mask), which place static PHP files into the file system in order to better cache performance-intensive processes such as class paths, annotation parsing etc. better. Deliberately do not use the core functions in order to avoid any overhead and and to ensure the greatest possible compatibility with core updates.

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

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

The example above generates a PHP file with this content:

['a'=>1, 'b'=>2]];
Copied!

| @return string|array

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

Methods 

Cache::clear() 

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

Deletes caches. If an identifier is specified, only the caches of the specific identifier are deleted identifier are deleted â otherwise ALL caches of all extensions and pages.

RAM caches CachingFramework caches that were set via \nn\t3::Cache()->set() File caches that were set via \nn\t3::Cache()->write()

// delete ALL caches â also the caches of other extensions, pages etc.
\nn\t3::Cache()->clear();

// Delete only the caches with a specific identifier
\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); 

Deletes the page cache. Alias to \nn\t3::Page()->clearCache()

\nn\t3::Cache()->clearPageCache( 17 ); // Delete page cache for pid=17
\nn\t3::Cache()->clearPageCache(); // clear cache of ALL pages
Copied!
@param mixed $pid pid of the page whose cache is to be cleared or leave empty for all pages
@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); 

Reads the content of the Typo3 cache using an identifier. The identifier is any string or array that uniquely identifies the cache.

\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 or array to identify the cache
@param mixed $useRamCache temporary cache in $GLOBALS instead of 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); 

Converts transferred cache identifiers into a usable string. Can also process an array as identifier.

@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); 

Read static file cache.

Reads the PHP file that was written via \nn\t3::Cache()->write().

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

The PHP file is an executable PHP script with the return command It stores the cache content in an array.

...];
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); 

Writes an entry to the Typo3 cache. The identifier is an arbitrary string or an array that uniquely identifies the cache.

// Classic application in the controller: Get and set cache
if ($cache = \nn\t3::Cache()->get('myid')) return $cache;
...
$cache = $this->view->render();
return \nn\t3::Cache()->set('myid', $cache);
Copied!
// Use RAM cache? Set TRUE as the third parameter
\nn\t3::Cache()->set('myid', $dataToCache, true);

// Set the duration of the cache to 60 minutes
\nn\t3::Cache()->set('myid', $dataToCache, 3600);

// An array can also be specified as the key
\nn\t3::Cache()->set(['pid'=>1, 'uid'=>'7'], $html);
Copied!
@param mixed $indentifier String or array to identify the cache
@param mixed $data Data to be written to the cache. (string or array)
@param mixed $useRamCache true: temporary cache in $GLOBALS instead of caching framework.
integer: How many seconds to cache?

| @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); 

Write static file cache.

Writes a PHP file that can be loaded via $cache = require('...').

Based on many core functions and extensions (e.g. mask), which place static PHP files into the file system in order to better cache performance-intensive processes such as class paths, annotation parsing etc. better. Deliberately do not use the core functions in order to avoid any overhead and and to ensure the greatest possible compatibility with core updates.

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

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

The example above generates a PHP file with this content:

['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() 

Read and render content elements and content of a backend column(colPos)

Overview of Methods 

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

Loads relations(media, assets, ...) to a tt_content data array If EXT:mask is installed, the corresponding method from mask is used.

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

| @return array

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

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

Loads the content for a specific column(colPos) and page. If no pageUid is specified, it uses the current page. With slide, the content element of the parent page is fetched if no content element exists in the column on the specified page.

Get content of colPos = 110 from the current page:

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

Get content of colPos = 110 from the current page. If there is no content in the column on the current page, use the content from the parent page:

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

Get the content of colPos = 110 from the page with id 99:

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

Get content of colPos = 110 from the page with id 99. If there is no content in the column on page 99, use the content from the parent page of page 99:

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

Also available as ViewHelper:

{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); 

Loads the "raw" tt_content data of a specific column(colPos).

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

Also available as ViewHelper. | relations is set to TRUE by default in the ViewHelper

{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'); 

Loads the data of a tt_content element as a simple array:

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

Loading relations(media, assets, ...)

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

Translations / Localization:

Do NOT automatically translate element if a different language has been set

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

Get element in a DIFFERENT language than set in the frontend. Takes into account the fallback chain of the language that was set in the site config

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

Get element with its own fallback chain. Completely ignores the chain, that was defined in the site config.

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

Use your own field for recognition

\nn\t3::Content()->get( 'footer', true, true, 'content_uuid' );
Copied!
@param int|string $ttContentUid Content-Uid in the table tt_content (or string with a key)
@param bool $getRelations Also get relations / FAL?
@param bool $localize Translate the entry?
@param string $localize Translate the entry?
@param string $field If field other than uid is to be used
@return array

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

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

Get multiple content elements (from tt_content).

The data records are localized automatically - except $localize is set to false is set to false. See \nn\t3::Content()->get() for more $localize options.

Based on a list of UIDs:

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

Based on filter criteria:

\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 or constraints for querying the data
@param bool $getRelations Also get relations / FAL?
@param bool $localize Translate the entry?
@return array

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

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

Localize / translate data.

Examples:

Translate data using the current language of the frontend.

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

Get data in a DIFFERENT language than the one set in the frontend. Takes into account the fallback chain of the language that was set in the site config

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

Get data with own fallback chain. Completely ignores the chain, that was defined in the site config.

\nn\t3::Content()->localize( 'tt_content', $data, [3, 2, 0] );
Copied!
@param string $table Database table
@param array $data Array with the data of the default language (languageUid = 0)
@param mixed $localize Specification of how to translate. Boolean, uid or array with uids
@return array

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

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

Renders a tt_content element as HTML

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

Also available as ViewHelper:

{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 = []); 

Loads relations(media, assets, ...) to a tt_content data array If EXT:mask is installed, the corresponding method from mask is used.

\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); 

Loads the content for a specific column(colPos) and page. If no pageUid is specified, it uses the current page. With slide, the content element of the parent page is fetched if no content element exists in the column on the specified page.

Get content of colPos = 110 from the current page:

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

Get content of colPos = 110 from the current page. If there is no content in the column on the current page, use the content from the parent page:

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

Get the content of colPos = 110 from the page with id 99:

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

Get content of colPos = 110 from the page with id 99. If there is no content in the column on page 99, use the content from the parent page of page 99:

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

Also available as ViewHelper:

{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); 

Loads the "raw" tt_content data of a specific column(colPos).

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

Also available as ViewHelper. | relations is set to TRUE by default in the ViewHelper

{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'); 

Loads the data of a tt_content element as a simple array:

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

Loading relations(media, assets, ...)

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

Translations / Localization:

Do NOT automatically translate element if a different language has been set

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

Get element in a DIFFERENT language than set in the frontend. Takes into account the fallback chain of the language that was set in the site config

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

Get element with its own fallback chain. Completely ignores the chain, that was defined in the site config.

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

Use your own field for recognition

\nn\t3::Content()->get( 'footer', true, true, 'content_uuid' );
Copied!
@param int|string $ttContentUid Content-Uid in the table tt_content (or string with a key)
@param bool $getRelations Also get relations / FAL?
@param bool $localize Translate the entry?
@param string $localize Translate the entry?
@param string $field If field other than uid is to be used
@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); 

Get multiple content elements (from tt_content).

The data records are localized automatically - except $localize is set to false is set to false. See \nn\t3::Content()->get() for more $localize options.

Based on a list of UIDs:

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

Based on filter criteria:

\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 or constraints for querying the data
@param bool $getRelations Also get relations / FAL?
@param bool $localize Translate the entry?
@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); 

Localize / translate data.

Examples:

Translate data using the current language of the frontend.

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

Get data in a DIFFERENT language than the one set in the frontend. Takes into account the fallback chain of the language that was set in the site config

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

Get data with own fallback chain. Completely ignores the chain, that was defined in the site config.

\nn\t3::Content()->localize( 'tt_content', $data, [3, 2, 0] );
Copied!
@param string $table Database table
@param array $data Array with the data of the default language (languageUid = 0)
@param mixed $localize Specification of how to translate. Boolean, uid or array with 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); 

Renders a tt_content element as HTML

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

Also available as ViewHelper:

{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() 

Converting arrays to models, models to JSONs, arrays to ObjectStorages, hex colors to RGB and much more that somehow has to do with converting things. has to do with converting things.

Overview of Methods 

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

Converts a model into an array Alias to nnt3::Obj()->toArray();

For memory problems due to recursion: Specify max depth!

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

| @return array

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

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

Converts a human-readable specification of bytes/megabytes into a byte integer. Extremely tolerant when it comes to spaces, upper/lower case and commas instead of periods.

\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!

For the reverse path (bytes to human-readable notation such as 1024 -> 1kb) there is a practical there is a practical Fluid ViewHelper in the core:

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

| @return integer

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

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

Converts a \TYPO3\CMS\Core\Resource\FileReference (or its uid) to a \TYPO3\CMS\Extbase\Domain\Model\FileReference

\nn\t3::Convert( $input )->toFileReference() => \TYPO3\CMS\Extbase\Domain\Model\FileReference
Copied!
@param $input Can be \TYPO3\CMS\Core\Resource\FileReference or uid thereof
@return \TYPO3\CMS\Extbase\Domain\Model\FileReference

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

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

Converts (normalizes) a string to 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); 

Converts a model into a JSON

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

| @return array

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

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

Converts a language ID (e.g. '0', '1') into the two-character language abbreviation (e.g. 'de', 'en')

// Language 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); 

Converts a two-character language abbreviation (e.g. 'de', 'en') into the language ID (e.g. '0', '1')

// Language 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); 

Converts an array into a model.

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

Can also automatically generate FileReferences. In this example, a new model of the type \Nng\Model\Name is created and then then persisted in the database. The falMedia field is an ObjectStorage with FileReferences. The FileReferences are created automatically!

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

Example: Create a news model from an array:

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

Hint To update an existing model with data from an array, there is the method there is the method $updatedModel = \nn\t3::Obj( $prevModel )->merge( $data );

| @return mixed

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

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

Converts something into an 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(); 

Converts a color value to another number format

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

| @return string

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

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

Converts a list into an ObjectStorage with SysCategory

Not yet implemented!
Copied!

| @return ObjectStorage

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

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

Converts (normalizes) a string to 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); 

Converts a model into an array Alias to nnt3::Obj()->toArray();

For memory problems due to recursion: Specify max depth!

\nn\t3::Convert($model)->toArray(2);
\nn\t3::Convert($model)->toArray(); => ['uid'=>1, 'title'=>'Example', ...]
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(); 

Converts a human-readable specification of bytes/megabytes into a byte integer. Extremely tolerant when it comes to spaces, upper/lower case and commas instead of periods.

\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!

For the reverse path (bytes to human-readable notation such as 1024 -> 1kb) there is a practical there is a practical Fluid ViewHelper in the 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(); 

Converts a \TYPO3\CMS\Core\Resource\FileReference (or its uid) to a \TYPO3\CMS\Extbase\Domain\Model\FileReference

\nn\t3::Convert( $input )->toFileReference() => \TYPO3\CMS\Extbase\Domain\Model\FileReference
Copied!
@param $input Can be \TYPO3\CMS\Core\Resource\FileReference or uid thereof
@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(); 

Converts (normalizes) a string to 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); 

Converts a model into a JSON

\nn\t3::Convert($model)->toJson() => ['uid'=>1, 'title'=>'Example', ...]
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); 

Converts a language ID (e.g. '0', '1') into the two-character language abbreviation (e.g. 'de', 'en')

// Language 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); 

Converts a two-character language abbreviation (e.g. 'de', 'en') into the language ID (e.g. '0', '1')

// Language 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); 

Converts an array into a model.

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

Can also automatically generate FileReferences. In this example, a new model of the type \Nng\Model\Name is created and then then persisted in the database. The falMedia field is an ObjectStorage with FileReferences. The FileReferences are created automatically!

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

Example: Create a news model from an array:

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

Hint To update an existing model with data from an array, there is the method there is the method $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); 

Converts something into an 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(); 

Converts a color value to another number format

\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(); 

Converts a list into an ObjectStorage with SysCategory

Not yet implemented!
Copied!

| @return ObjectStorage

Source Code 

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

Convert::toUTF8() 

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

Converts (normalizes) a string to 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() 

Methods for setting a cookie.

Since TYPO3 12, cookies cannot simply be set via $_COOKIE[] Instead, they must be set in the Psr\Http\Message\ResponseInterface.

Overview of Methods 

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

Create a cookie - but do not send it to the client yet. The cookie is only set in the middleware, see: | \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); 

Adds all saved cookies to the PSR-7 response. Is called by \Nng\Nnhelpers\Middleware\ModifyResponse.

// Example in a 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); 

Create an instance of the Symfony cookie

$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(); 

Returns all cookies that are waiting to be set in the middleware to be set in the response.

$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); 

Create a cookie - but do not send it to the client yet. The cookie is only set in the middleware, see: | \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); 

Adds all saved cookies to the PSR-7 response. Is called by \Nng\Nnhelpers\Middleware\ModifyResponse.

// Example in a 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); 

Create an instance of the Symfony cookie

$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(); 

Returns all cookies that are waiting to be set in the middleware to be set in the response.

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

| @return array

Source Code 

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

Db 

\nn\t3::Db() 

Simplify access to the most frequently used database operations for writing, reading and deleting.

Overview of Methods 

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

Debug of the QueryBuilder statement.

Outputs the complete, compiled query as a readable string, as it is later executed in the database executed later in the database e.g. SELECT FROM fe_users WHERE ...

// Output statement directly in the browser
\nn\t3::Db()->debug( $query );

// Return statement as a string, do not output automatically
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); 

Delete database entry. Small and fine. Either a table name and the UID can be transferred - or a model.

Delete a data record by table name and uid or any constraint:

// Deletion based on the uid
\nn\t3::Db()->delete('table', $uid);

// Delete based on a custom field
\nn\t3::Db()->delete('table', ['uid_local'=>$uid]);

// Delete entry completely and irrevocably (do not just remove via flag deleted = 1)
\nn\t3::Db()->delete('table', $uid, true);
Copied!

Delete a data record 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); 

The GDPR version of deletion.

Radical removal of all traces of a data set including the physical SysFiles, linked to the model. To be used with caution, as no relations are checked for the model to be deleted.

\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 = ''); 

Only keep elements in key/val array whose keys also exist in TCA for certain table

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

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

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

Retrieves ALL entries from a database table.

The data is returned as an array - this is (unfortunately) still the absolute most performant way to fetch many data records from a table, since no DataMapper has to parse the individual rows.

// Get all data records. "hidden" is taken into account.
\nn\t3::Db()->findAll('fe_users');

// Also fetch data records that are "hidden"
\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); 

Finds an entry based on the UID. Also works if the frontend has not yet been initialized, e.g. while AuthentificationService is running or in the 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); 

Finds entries using multiple 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 = []); 

Finds ALL entries based on a desired field value. Also works if the frontend has not yet been initialized.

// 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); 

Finds ALL entries that contain a value from the $values array in the $column column. Also works if the frontend has not yet been initialized. Alias to \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); 

Reverse of \nn\t3::Db()->findIn():

Finds ALL entries that do NOT contain a value from the $values array in the $column column. Also works if the frontend has not yet been initialized.

// 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 = []); 

Finds ONE entry based on desired field values.

// 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); 

"Repairs" the SysFileReferences for models that have a property that only referencea FileReferenceinstead of an ObjectStorage instead of a FileReference. At the moment, it is unclear why TYPO3 has included these persists them in the table sys_file_reference, but empties the field tablenames field â or does not set uid_foreign. With an `ObjectStorage the problem does not occur.`

// must happen directly after persisting the model
\nn\t3::Db()->fixFileReferencesForModel( $model );
Copied!

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

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

Get one or more domain models/entities using a uid A single $uid or a list of $uids can be passed.

Returns the "real" model/object including all relations, analogous to a query via the repository.

// Get a single model by its uid
$model = \nn\t3::Db()->get( 1, \Nng\MyExt\Domain\Model\Name::class );

// Get an array of models based on their uids
$modelArray = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Model\Name::class );

// Also returns hidden models
$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); 

Get a table column (TCA) for a specific table

\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 = ''); 

Get localized label of a specific TCA field

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

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

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

Get all table columns (TCA) for specific table

// Get fields based on the TCA array
\nn\t3::Db()->getColumns( 'tablename' );

// Determine fields via the SchemaManager
\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); 

Get fields of a table by a specific type

\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(); 

Get a "raw" connection to the database. Only useful in really exceptional cases.

$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 = ''); 

Get delete column for specific table.

This column is used as a flag for deleted data records. Normally: deleted = 1

@param string $table
@return string

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

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

Get QueryBuilder for a table

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

Example:

$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); 

Get an instance of the repository for a model (or a model class name).

\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); 

Get table name for a model (or a model class name). Alias to \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); 

Removes default constraints for StoragePID, hidden and/or deleted for a query or repository.

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

Example for a 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!

If this is not enough or too complicated, see:

\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 = []); 

Insert database entry. Simple and foolproof. Either the table name and an array can be transferred - or a domain model.

Inserting a new data set via table name and data array:

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

Insert a new model. The repository is determined automatically. The model is persisted directly.

$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 = []); 

Insert several lines into database.

use TYPO3\CMS\Core\Database\Connection;

$data = [
    ['title' => 'One', 'tstamp'=>123],
    ['title' => 'Two', '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 = []); 

Set sorting for a repository or a query.

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

// asc and desc can be used as synonyms
$ordering = ['title' => 'asc'];
$ordering = ['title' => 'desc'];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!

Can also be used to sort by a list of values (e.g. uids). An array is passed for the value of the individual orderings:

$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(); 

Persist all.

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

| @return void

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

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

A replacement for the mysqli_real_escape_string() method.

Should only be used in an emergency for low-level queries. It is better to use preparedStatements.

Only works with SQL, not with 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 = []); 

Create database entry OR update an existing data record.

Decides independently whether the entry should be added to the database via UPDATE or INSERT or whether an existing data record needs to be updated. The data is persisted directly!

Example for transferring a table name and an array:

// no uid transferred? Then INSERT a new data set
\nn\t3::Db()->save('table', ['bodytext'=>'...']);

// pass uid? Then UPDATE existing data
\nn\t3::Db()->save('table', ['uid'=>123, 'bodytext'=>'...']);
Copied!

Example for transferring a domain model:

// new model? Is inserted via $repo->add()
$model = new \My\Nice\Model();
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );

// existing model? Is updated via $repo->update()
$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); 

Add constraint for sys_file_reference to a QueryBuilder. Restricts the results to whether there is a FAL relation.

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

// Only fetch datasets that have at least one SysFileReference for falfield
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield' );

// ... that do NOT have a SysFileReference for falfield
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', false );

// ... which have EXACTLY 2 SysFileReferences
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2 );

// ... that have 2 or less (less than or equal) SysFileReferences
\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'); 

Restrict constraint to records that are NOT in one of the specified categories. Opposite and alias to \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); 

Add constraint for sys_category / sys_category_record_mm to a QueryBuilder. Restricts the results to the specified 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 = []); 

Sorts the results of a query according to an array and a specific field. Solves the problem that an ->in() query does not return the results in the order of the passed IDs. Example: | $query->matching($query->in('uid', [3,1,2])); does not necessarily come return in the order [3,1,2].

$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 = []); 

Send a "raw" query to the database. Closer to the database is not possible. You are responsible for everything yourself. Injections are only opposed by your (hopefully sufficient :) intelligence.

Helps, for example, with queries of tables that are not part of the Typo3 installation and therefore could not be reached via the normal QueryBuilder.

// ALWAYS escape variables via!
$keyword = \nn\t3::Db()->quote('search term');
$rows = \nn\t3::Db()->statement( "SELECT FROM tt_news WHERE bodytext LIKE '%{$keyword}%'");

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

// Types can be passed (this is determined automatically for arrays)
$rows = \nn\t3::Db()->statement( 'SELECT FROM tt_news WHERE uid IN (:uids)', ['uids'=>[1,2,3]], ['uids'=>Connection::PARAM_INT_ARRAY] );
Copied!

With a SELECT statement, the rows from the database are returned as an array. For all other statements (e.g. UPDATE or DELETE), the number of affected rows is returned.

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

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

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

Does a specific DB table exist?

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

| @return boolean

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

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

Empty database table. Deletes all entries in the specified table and resets the auto-increment value to 0.

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

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

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

Restore deleted database entry. To do this, the flag for "deleted" is set to 0 again.

\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); 

Update database entry. Quick and easy. The update can be done either by table name and data array. Or you can pass a model.

Examples:

// 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!

With true instead of a $uid ALL records of the table are updated.

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

Instead of a table name, a simple model can also be passed. The repository is determined automatically and the model is persisted directly.

$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 of the QueryBuilder statement.

Outputs the complete, compiled query as a readable string, as it is later executed in the database executed later in the database e.g. SELECT FROM fe_users WHERE ...

// Output statement directly in the browser
\nn\t3::Db()->debug( $query );

// Return statement as a string, do not output automatically
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); 

Delete database entry. Small and fine. Either a table name and the UID can be transferred - or a model.

Delete a data record by table name and uid or any constraint:

// Deletion based on the uid
\nn\t3::Db()->delete('table', $uid);

// Delete based on a custom field
\nn\t3::Db()->delete('table', ['uid_local'=>$uid]);

// Delete entry completely and irrevocably (do not just remove via flag deleted = 1)
\nn\t3::Db()->delete('table', $uid, true);
Copied!

Delete a data record 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); 

The GDPR version of deletion.

Radical removal of all traces of a data set including the physical SysFiles, linked to the model. To be used with caution, as no relations are checked for the model to be deleted.

\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 = ''); 

Only keep elements in key/val array whose keys also exist in TCA for certain table

@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); 

Retrieves ALL entries from a database table.

The data is returned as an array - this is (unfortunately) still the absolute most performant way to fetch many data records from a table, since no DataMapper has to parse the individual rows.

// Get all data records. "hidden" is taken into account.
\nn\t3::Db()->findAll('fe_users');

// Also fetch data records that are "hidden"
\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); 

Finds an entry based on the UID. Also works if the frontend has not yet been initialized, e.g. while AuthentificationService is running or in the 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); 

Finds entries using multiple 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 = []); 

Finds ALL entries based on a desired field value. Also works if the frontend has not yet been initialized.

// 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); 

Finds ALL entries that contain a value from the $values array in the $column column. Also works if the frontend has not yet been initialized. Alias to \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); 

Reverse of \nn\t3::Db()->findIn():

Finds ALL entries that do NOT contain a value from the $values array in the $column column. Also works if the frontend has not yet been initialized.

// 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 = []); 

Finds ONE entry based on desired field values.

// 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); 

"Repairs" the SysFileReferences for models that have a property that only referencea FileReferenceinstead of an ObjectStorage instead of a FileReference. At the moment, it is unclear why TYPO3 has included these persists them in the table sys_file_reference, but empties the field tablenames field â or does not set uid_foreign. With an `ObjectStorage the problem does not occur.`

// must happen directly after persisting the model
\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); 

Get one or more domain models/entities using a uid A single $uid or a list of $uids can be passed.

Returns the "real" model/object including all relations, analogous to a query via the repository.

// Get a single model by its uid
$model = \nn\t3::Db()->get( 1, \Nng\MyExt\Domain\Model\Name::class );

// Get an array of models based on their uids
$modelArray = \nn\t3::Db()->get( [1,2,3], \Nng\MyExt\Domain\Model\Model\Name::class );

// Also returns hidden models
$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); 

Get a table column (TCA) for a specific table

\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 = ''); 

Get localized label of a specific TCA field

@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); 

Get all table columns (TCA) for specific table

// Get fields based on the TCA array
\nn\t3::Db()->getColumns( 'tablename' );

// Determine fields via the SchemaManager
\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); 

Get fields of a table by a specific type

\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(); 

Get a "raw" connection to the database. Only useful in really exceptional cases.

$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 = ''); 

Get delete column for specific table.

This column is used as a flag for deleted data records. Normally: 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 = ''); 

Get QueryBuilder for a table

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

Example:

$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); 

Get an instance of the repository for a model (or a model class name).

\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); 

Get table name for a model (or a model class name). Alias to \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); 

Removes default constraints for StoragePID, hidden and/or deleted for a query or repository.

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

Example for a 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!

If this is not enough or too complicated, see:

\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 = []); 

Insert database entry. Simple and foolproof. Either the table name and an array can be transferred - or a domain model.

Inserting a new data set via table name and data array:

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

Insert a new model. The repository is determined automatically. The model is persisted directly.

$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 = []); 

Insert several lines into database.

use TYPO3\CMS\Core\Database\Connection;

$data = [
    ['title' => 'One', 'tstamp'=>123],
    ['title' => 'Two', '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 = []); 

Set sorting for a repository or a query.

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

// asc and desc can be used as synonyms
$ordering = ['title' => 'asc'];
$ordering = ['title' => 'desc'];
\nn\t3::Db()->orderBy( $queryOrRepository, $ordering );
Copied!

Can also be used to sort by a list of values (e.g. uids). An array is passed for the value of the individual orderings:

$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(); 

Persist all.

\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 = ''); 

A replacement for the mysqli_real_escape_string() method.

Should only be used in an emergency for low-level queries. It is better to use preparedStatements.

Only works with SQL, not with 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 = []); 

Create database entry OR update an existing data record.

Decides independently whether the entry should be added to the database via UPDATE or INSERT or whether an existing data record needs to be updated. The data is persisted directly!

Example for transferring a table name and an array:

// no uid transferred? Then INSERT a new data set
\nn\t3::Db()->save('table', ['bodytext'=>'...']);

// pass uid? Then UPDATE existing data
\nn\t3::Db()->save('table', ['uid'=>123, 'bodytext'=>'...']);
Copied!

Example for transferring a domain model:

// new model? Is inserted via $repo->add()
$model = new \My\Nice\Model();
$model->setBodytext('...');
$persistedModel = \nn\t3::Db()->save( $model );

// existing model? Is updated via $repo->update()
$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); 

Add constraint for sys_file_reference to a QueryBuilder. Restricts the results to whether there is a FAL relation.

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

// Only fetch datasets that have at least one SysFileReference for falfield
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield' );

// ... that do NOT have a SysFileReference for falfield
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', false );

// ... which have EXACTLY 2 SysFileReferences
\nn\t3::Db()->setFalConstraint( $queryBuilder, 'tx_myext_tablename', 'falfield', 2 );

// ... that have 2 or less (less than or equal) SysFileReferences
\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'); 

Restrict constraint to records that are NOT in one of the specified categories. Opposite and alias to \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); 

Add constraint for sys_category / sys_category_record_mm to a QueryBuilder. Restricts the results to the specified 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 = []); 

Sorts the results of a query according to an array and a specific field. Solves the problem that an ->in() query does not return the results in the order of the passed IDs. Example: | $query->matching($query->in('uid', [3,1,2])); does not necessarily come return in the order [3,1,2].

$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 = []); 

Send a "raw" query to the database. Closer to the database is not possible. You are responsible for everything yourself. Injections are only opposed by your (hopefully sufficient :) intelligence.

Helps, for example, with queries of tables that are not part of the Typo3 installation and therefore could not be reached via the normal QueryBuilder.

// ALWAYS escape variables via!
$keyword = \nn\t3::Db()->quote('search term');
$rows = \nn\t3::Db()->statement( "SELECT FROM tt_news WHERE bodytext LIKE '%{$keyword}%'");

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

// Types can be passed (this is determined automatically for arrays)
$rows = \nn\t3::Db()->statement( 'SELECT FROM tt_news WHERE uid IN (:uids)', ['uids'=>[1,2,3]], ['uids'=>Connection::PARAM_INT_ARRAY] );
Copied!

With a SELECT statement, the rows from the database are returned as an array. For all other statements (e.g. UPDATE or DELETE), the number of affected rows is returned.

@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 = ''); 

Does a specific DB table exist?

$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 = ''); 

Empty database table. Deletes all entries in the specified table and resets the auto-increment value to 0.

\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 = []); 

Restore deleted database entry. To do this, the flag for "deleted" is set to 0 again.

\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); 

Update database entry. Quick and easy. The update can be done either by table name and data array. Or you can pass a model.

Examples:

// 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!

With true instead of a $uid ALL records of the table are updated.

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

Instead of a table name, a simple model can also be passed. The repository is determined automatically and the model is persisted directly.

$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() 

Manipulating DOM and XML. Still a work in progress :)

Overview of Methods 

\nn\t3::Dom()->absPrefix($html, $attributes = [], $baseUrl = ''); 

Replaces links and paths to images etc. in the source text with an absolute URL e.g. for the dispatch of mails | @return string

| ➜ Go to source code of Dom::absPrefix()

Methods 

Dom::absPrefix() 

\nn\t3::Dom()->absPrefix($html, $attributes = [], $baseUrl = ''); 

Replaces links and paths to images etc. in the source text with an absolute URL e.g. for the dispatch of 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() 

Encrypting and hashing passwords

Overview of Methods 

\nn\t3::Encrypt()->checkPassword($password = '', $passwordHash = NULL); 

Checks whether the hash of a password and a password match. Application: Password hash of a fe_user in the database with the submitted password compare.

\nn\t3::Encrypt()->checkPassword('99grad', '$1$wtnFi81H$mco6DrrtdeqiziRJyisdK1.');
Copied!

| @return boolean

| ➜ Go to source code of Encrypt::checkPassword()

\nn\t3::Encrypt()->createJwtSignature($header = [], $payload = []); 

Generate a signature for a JWT (Json Web Token). The signature is later transmitted by the user as part of the token.

$signature = \nn\t3::Encrypt()->createJwtSignature(['alg'=>'HS256', 'type'=>'JWT'], ['test'=>123]);
Copied!
@param array $header
@param array $payload
@return string

| ➜ Go to source code of Encrypt::createJwtSignature()

\nn\t3::Encrypt()->decode($data = ''); 

Decrypts a string or an array. To encrypt the data, \nn\t3::Encrypt()->encode() can be used. See \nn\t3::Encrypt()->encode() for a complete example.

\nn\t3::Encrypt()->decode( '...' );
Copied!

| @return string

| ➜ Go to source code of Encrypt::decode()

\nn\t3::Encrypt()->encode($data = ''); 

Encrypts a string or an array.

In contrast to \nn\t3::Encrypt()->hash(), an encrypted value can be decrypted again using \nn\t3::Encrypt()->decode() can be decrypted again. This method is therefore not suitable for storing sensitive data such as passwords in a database. Nevertheless, the level of protection is relatively high, as even identical data encrypted with encrypted with the same salting key look different.

A salting key is generated for the encryption and stored in the nnhelpers Extension Manager. This key is unique for each installation. If it is changed, data that has already been encrypted cannot be be decrypted again.

\nn\t3::Encrypt()->encode( 'mySecretSomething' );
\nn\t3::Encrypt()->encode( ['some'=>'secret'] );
Copied!

Complete example with encryption and decryption:

$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'); 

Returns the class name of the current hash algorithm of an encrypted password, e.g. to know at fe_user how the password was encrypted in the DB.

\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(); 

Retrieves the Enryption / Salting Key from the extension configuration for nnhelpers If no key has been set in the Extension Manager, it is generated automatically and saved in the LocalConfiguration.php.

\nn\t3::Encrypt()->getSaltingKey();
Copied!

| @return string

| ➜ Go to source code of Encrypt::getSaltingKey()

\nn\t3::Encrypt()->hash($string = ''); 

Simple hashing, e.g. when checking a uid against a hash.

\nn\t3::Encrypt()->hash( $uid );
Copied!

Also exists as a ViewHelper:

{something->nnt3:encrypt.hash()}
Copied!

| @return string

| ➜ Go to source code of Encrypt::hash()

\nn\t3::Encrypt()->hashNeedsUpdate($passwordHash = '', $loginType = 'FE'); 

Checks whether the hash needs to be updated because it does not correspond to the current encryption algorithm. When updating Typo3 to a new LTS, the hashing algorithm of the passwords in the database is also often is improved. This method checks whether the transferred hash is still up-to-date or needs to be updated.

Returns true if an update is required.

\nn\t3::Encrypt()->hashNeedsUpdate('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.'); // true
Copied!

An automatic update of the password could look like this in a manual FE user authentication service:

$uid = $user['uid']; // uid of the FE user
$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); 

Get session hash for fe_sessions.ses_id Corresponds to the value that is stored for the fe_typo_user cookie in the database.

In TYPO3 < v10 an unchanged value is returned here. As of TYPO3 v10, the session ID is stored in the cookie fe_typo_user is no longer stored directly in the database, but hashed. See: TYPO3\CMS\Core\Session\Backend\DatabaseSessionBackend->hash().

\nn\t3::Encrypt()->hashSessionId( $sessionIdFromCookie );
Copied!

Example:

$cookie = $_COOKIE['fe_typo_user'];
$hash = \nn\t3::Encrypt()->hashSessionId( $cookie );
$sessionFromDatabase = \nn\t3::Db()->findOneByValues('fe_sessions', ['ses_id'=>$hash]);
Copied!

Used by, among others: \nn\t3::FrontendUserAuthentication()->loginBySessionId().

| @return string

| ➜ Go to source code of Encrypt::hashSessionId()

\nn\t3::Encrypt()->jwt($payload = []); 

Create a JWT (Json Web Token), sign it and return it base64-encoded.

Do not forget: A JWT is "forgery-proof" because the signature hash can only be generated with can only be generated with the correct key/salt - but all data in the JWT can be read by anyone can be viewed through base64_decode(). A JWT is by no means suitable for storing sensitive data such as passwords or logins!

\nn\t3::Encrypt()->jwt(['test'=>123]);
Copied!
@param array $payload
@return string

| ➜ Go to source code of Encrypt::jwt()

\nn\t3::Encrypt()->parseJwt($token = ''); 

Parse a JWT (Json Web Token) and check the signature. If the signature is valid (and therefore the payload has not been manipulated), the payload is returned. If the signature is invalid, FALSE is returned.

\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 of a password according to the Typo3 principle. Application: Overwriting the password of a fe_user in the database

\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); 

Checks whether the hash of a password and a password match. Application: Password hash of a fe_user in the database with the submitted password compare.

\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 = []); 

Generate a signature for a JWT (Json Web Token). The signature is later transmitted by the user as part of the token.

$signature = \nn\t3::Encrypt()->createJwtSignature(['alg'=>'HS256', 'type'=>'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 = ''); 

Decrypts a string or an array. To encrypt the data, \nn\t3::Encrypt()->encode() can be used. See \nn\t3::Encrypt()->encode() for a complete example.

\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 = ''); 

Encrypts a string or an array.

In contrast to \nn\t3::Encrypt()->hash(), an encrypted value can be decrypted again using \nn\t3::Encrypt()->decode() can be decrypted again. This method is therefore not suitable for storing sensitive data such as passwords in a database. Nevertheless, the level of protection is relatively high, as even identical data encrypted with encrypted with the same salting key look different.

A salting key is generated for the encryption and stored in the nnhelpers Extension Manager. This key is unique for each installation. If it is changed, data that has already been encrypted cannot be be decrypted again.

\nn\t3::Encrypt()->encode( 'mySecretSomething' );
\nn\t3::Encrypt()->encode( ['some'=>'secret'] );
Copied!

Complete example with encryption and decryption:

$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'); 

Returns the class name of the current hash algorithm of an encrypted password, e.g. to know at fe_user how the password was encrypted in the DB.

\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(); 

Retrieves the Enryption / Salting Key from the extension configuration for nnhelpers If no key has been set in the Extension Manager, it is generated automatically and saved in the LocalConfiguration.php.

\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 = ''); 

Simple hashing, e.g. when checking a uid against a hash.

\nn\t3::Encrypt()->hash( $uid );
Copied!

Also exists as a 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'); 

Checks whether the hash needs to be updated because it does not correspond to the current encryption algorithm. When updating Typo3 to a new LTS, the hashing algorithm of the passwords in the database is also often is improved. This method checks whether the transferred hash is still up-to-date or needs to be updated.

Returns true if an update is required.

\nn\t3::Encrypt()->hashNeedsUpdate('$P$CIz84Y3r6.0HX3saRwYg0ff5M0a4X1.'); // true
Copied!

An automatic update of the password could look like this in a manual FE user authentication service:

$uid = $user['uid']; // uid of the FE user
$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); 

Get session hash for fe_sessions.ses_id Corresponds to the value that is stored for the fe_typo_user cookie in the database.

In TYPO3 < v10 an unchanged value is returned here. As of TYPO3 v10, the session ID is stored in the cookie fe_typo_user is no longer stored directly in the database, but hashed. See: TYPO3\CMS\Core\Session\Backend\DatabaseSessionBackend->hash().

\nn\t3::Encrypt()->hashSessionId( $sessionIdFromCookie );
Copied!

Example:

$cookie = $_COOKIE['fe_typo_user'];
$hash = \nn\t3::Encrypt()->hashSessionId( $cookie );
$sessionFromDatabase = \nn\t3::Db()->findOneByValues('fe_sessions', ['ses_id'=>$hash]);
Copied!

Used by, among others: \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 = []); 

Create a JWT (Json Web Token), sign it and return it base64-encoded.

Do not forget: A JWT is "forgery-proof" because the signature hash can only be generated with can only be generated with the correct key/salt - but all data in the JWT can be read by anyone can be viewed through base64_decode(). A JWT is by no means suitable for storing sensitive data such as passwords or logins!

\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 = ''); 

Parse a JWT (Json Web Token) and check the signature. If the signature is valid (and therefore the payload has not been manipulated), the payload is returned. If the signature is invalid, FALSE is returned.

\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 of a password according to the Typo3 principle. Application: Overwriting the password of a fe_user in the database

\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() 

Everything you need to know about the application's environment. From the user's language ID and the baseUrl to the question of which extensions are running.

Overview of Methods 

\nn\t3::Environment()->extLoaded($extName = ''); 

Check whether extension is loaded.

\nn\t3::Environment()->extLoaded('news');
Copied!

| ➜ Go to source code of Environment::extLoaded()

\nn\t3::Environment()->extPath($extName = ''); 

Get the absolute path to an extension e.g. /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 = ''); 

Get the relative path (from the current script) to an extension e.g. ../typo3conf/ext/nnsite/

\nn\t3::Environment()->extRelPath('extname');
Copied!

| @return string

| ➜ Go to source code of Environment::extRelPath()

\nn\t3::Environment()->getBaseURL(); 

Returns the baseUrl(config.baseURL), incl. http(s) protocol e.g. https://www.webseite.de/

\nn\t3::Environment()->getBaseURL();
Copied!

| @return string

| ➜ Go to source code of Environment::getBaseURL()

\nn\t3::Environment()->getCookieDomain($loginType = 'FE'); 

Get the cookie domain e.g. 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'); 

Get all countries available in the system

\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'); 

A country from the static_countriestable using its country code (e.g. DE)

\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'); 

Returns the default language (Default Language). In TYPO3, this is always the language with ID 0 The languages must be defined in the YAML site configuration.

// '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(); 

Get the domain e.g. www.webseite.de

\nn\t3::Environment()->getDomain();
Copied!

| @return string

| ➜ Go to source code of Environment::getDomain()

\nn\t3::Environment()->getExtConf($ext = 'nnhelpers', $param = ''); 

Get configuration from ext_conf_template.txt (backend, extension configuration)

\nn\t3::Environment()->getExtConf('nnhelpers', 'varname');
Copied!

Also exists as 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(); 

Get the current language (as a number) of the frontend.

\nn\t3::Environment()->getLanguage();
Copied!

| @return int

| ➜ Go to source code of Environment::getLanguage()

\nn\t3::Environment()->getLanguageFallbackChain($langUid = true); 

Returns a list of the languages that should be used if, for example e.g. a page or element does not exist in the desired language.

Important: The fallback chain contains in the first place the current or in $langUid transferred language.

// Use settings for current language (see Site-Config YAML)
\nn\t3::Environment()->getLanguageFallbackChain(); // --> e.g. [0] or [1,0]

// Get settings for a specific language
\nn\t3::Environment()->getLanguageFallbackChain( 1 );
// --> [1,0] - if fallback was defined in Site-Config and the fallbackMode is set to "fallback"
// --> [1] - if there is no fallback or the fallbackMode is set to "strict"
Copied!
@param string|boolean $returnKey
@return string|array

| ➜ Go to source code of Environment::getLanguageFallbackChain()

\nn\t3::Environment()->getLanguageKey(); 

Get the current language (as abbreviation like "de") in the frontend

\nn\t3::Environment()->getLanguageKey();
Copied!

| @return string

| ➜ Go to source code of Environment::getLanguageKey()

\nn\t3::Environment()->getLanguages($key = 'languageId', $value = NULL); 

Returns a list of all defined languages. The languages must be defined in the YAML site configuration.

// [['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!

There are also helpers for converting language IDs into language abbreviations and vice versa:

// --> 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 = ''); 

Get configuration from LocalConfiguration.php

\nn\t3::Environment()->getLocalConf('FE.cookieName');
Copied!

| @return string

| ➜ Go to source code of Environment::getLocalConf()

\nn\t3::Environment()->getPathSite(); 

Get the absolute path to the Typo3 root directory. e.g. /var/www/website/

\nn\t3::Environment()->getPathSite()
Copied!

Formerly: PATH_site

| ➜ Go to source code of Environment::getPathSite()

\nn\t3::Environment()->getPostMaxSize(); 

Return maximum upload size for files from the frontend. This specification is the value that was defined in php.ini and, if necessary was overwritten via the .htaccess.

\nn\t3::Environment()->getPostMaxSize(); // e.g. '1048576' for 1MB
Copied!

| @return integer

| ➜ Go to source code of Environment::getPostMaxSize()

\nn\t3::Environment()->getPsr4Prefixes(); 

Return list of PSR4 prefixes.

This is an array with all folders that must be parsed by class when autoloading / bootstrapping TYPO3 have to be parsed. In a TYPO3 extension, this is the Classes folder by default. The list is generated by Composer/TYPO3.

An array is returned. Key is Vendor\Namespace\, Value is an array with paths to the folders, which are searched recursively for classes. It does not matter whether TYPO3 is running in composer mode or not.

\nn\t3::Environment()->getPsr4Prefixes();
Copied!

Example for return:

[
    'Nng\Nnhelpers\' => ['/path/to/composer/../../public/typo3conf/ext/nnhelpers/Classes', ...],
    'Nng\Nnrestapi\' => ['/path/to/composer/../../public/typo3conf/ext/nnrestapi/Classes', ...]
]
Copied!

| @return array

| ➜ Go to source code of Environment::getPsr4Prefixes()

\nn\t3::Environment()->getRelPathSite(); 

Get the relative path to the Typo3 root directory. e.g. ../

\nn\t3::Environment()->getRelPathSite()
Copied!

| @return string

| ➜ Go to source code of Environment::getRelPathSite()

\nn\t3::Environment()->getRequest(); 

Fetches the current request. Workaround for special cases - and in the event that the core team does not implement this option itself in the future.

$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); 

Get the current site object. This object can be used to access the configuration from the site YAML file from TYPO3 9 onwards, for example.

In the context of a MiddleWare, the site may not yet be parsed / loaded. In this case, the $request from the MiddleWare can be passed to determine the site.

See also \nn\t3::Settings()->getSiteConfig() to read the site configuration.

\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); 

Generates a virtual frontend request that can be used in any context. Also initializes the frontend TypoScript object and all relevant objects.

$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(); 

Get the absolute path to the /var directory of Typo3.

This directory stores temporary cache files. Depending on the version of Typo3 and installation type (Composer or Non-Composer mode) this directory can be found in different locations.

// /full/path/to/typo3temp/var/
$path = \nn\t3::Environment()->getVarPath();
Copied!

| ➜ Go to source code of Environment::getVarPath()

\nn\t3::Environment()->isBackend(); 

Check whether we are in the backend context

\nn\t3::Environment()->isBackend();
Copied!

| @return bool

| ➜ Go to source code of Environment::isBackend()

\nn\t3::Environment()->isFrontend(); 

Check whether we are in the frontend context

\nn\t3::Environment()->isFrontend();
Copied!

| @return bool

| ➜ Go to source code of Environment::isFrontend()

\nn\t3::Environment()->isHttps(); 

Returns true if the page is accessed via HTTPS.

$isHttps = \nn\t3::Environment()->isHttps();
Copied!

| @return boolean

| ➜ Go to source code of Environment::isHttps()

\nn\t3::Environment()->isLocalhost(); 

Checks whether installation is running on local server

\nn\t3::Environment()->isLocalhost()
Copied!

| @return boolean

| ➜ Go to source code of Environment::isLocalhost()

\nn\t3::Environment()->setLanguage($languageId = 0); 

Set the current language.

Helpful if we need the language in a context where it has not been initialized, e.g. in a initialized, e.g. in a MiddleWare or CLI.

\nn\t3::Environment()->setLanguage(0);
Copied!
@param int $languageId
@return self

| ➜ Go to source code of Environment::setLanguage()

\nn\t3::Environment()->setRequest($request); 

Sets the current request. Is set in the RequestParser middleware

\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(); 

Get the version of Typo3, as an integer, e.g. "8" Alias to \nn\t3::t3Version()

\nn\t3::Environment()->t3Version();

if (\nn\t3::t3Version() >= 8) {
    // only for >= Typo3 8 LTS
}
Copied!

| @return int

| ➜ Go to source code of Environment::t3Version()

Methods 

Environment::extLoaded() 

\nn\t3::Environment()->extLoaded($extName = ''); 

Check whether extension is loaded.

\nn\t3::Environment()->extLoaded('news');
Copied!

Source Code 

public function extLoaded ( $extName = '' ) {
	return ExtensionManagementUtility::isLoaded( $extName );
}
Copied!

Environment::extPath() 

\nn\t3::Environment()->extPath($extName = ''); 

Get the absolute path to an extension e.g. /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 = ''); 

Get the relative path (from the current script) to an extension e.g. ../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(); 

Returns the baseUrl(config.baseURL), incl. http(s) protocol e.g. 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'); 

Get the cookie domain e.g. 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'); 

Get all countries available in the system

\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'); 

A country from the static_countriestable using its country code (e.g. DE)

\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'); 

Returns the default language (Default Language). In TYPO3, this is always the language with ID 0 The languages must be defined in the YAML site configuration.

// '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(); 

Get the domain e.g. 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 = ''); 

Get configuration from ext_conf_template.txt (backend, extension configuration)

\nn\t3::Environment()->getExtConf('nnhelpers', 'varname');
Copied!

Also exists as 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(); 

Get the current language (as a number) of the frontend.

\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); 

Returns a list of the languages that should be used if, for example e.g. a page or element does not exist in the desired language.

Important: The fallback chain contains in the first place the current or in $langUid transferred language.

// Use settings for current language (see Site-Config YAML)
\nn\t3::Environment()->getLanguageFallbackChain(); // --> e.g. [0] or [1,0]

// Get settings for a specific language
\nn\t3::Environment()->getLanguageFallbackChain( 1 );
// --> [1,0] - if fallback was defined in Site-Config and the fallbackMode is set to "fallback"
// --> [1] - if there is no fallback or the fallbackMode is set to "strict"
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(); 

Get the current language (as abbreviation like "de") in the frontend

\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); 

Returns a list of all defined languages. The languages must be defined in the YAML site configuration.

// [['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!

There are also helpers for converting language IDs into language abbreviations and vice versa:

// --> 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 = ''); 

Get configuration from LocalConfiguration.php

\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(); 

Get the absolute path to the Typo3 root directory. e.g. /var/www/website/

\nn\t3::Environment()->getPathSite()
Copied!

Formerly: PATH_site

Source Code 

public function getPathSite () {
	return \TYPO3\CMS\Core\Core\Environment::getPublicPath().'/';
}
Copied!

Environment::getPostMaxSize() 

\nn\t3::Environment()->getPostMaxSize(); 

Return maximum upload size for files from the frontend. This specification is the value that was defined in php.ini and, if necessary was overwritten via the .htaccess.

\nn\t3::Environment()->getPostMaxSize(); // e.g. '1048576' for 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(); 

Return list of PSR4 prefixes.

This is an array with all folders that must be parsed by class when autoloading / bootstrapping TYPO3 have to be parsed. In a TYPO3 extension, this is the Classes folder by default. The list is generated by Composer/TYPO3.

An array is returned. Key is Vendor\Namespace\, Value is an array with paths to the folders, which are searched recursively for classes. It does not matter whether TYPO3 is running in composer mode or not.

\nn\t3::Environment()->getPsr4Prefixes();
Copied!

Example for return:

[
    'Nng\Nnhelpers\' => ['/path/to/composer/../../public/typo3conf/ext/nnhelpers/Classes', ...],
    'Nng\Nnrestapi\' => ['/path/to/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(); 

Get the relative path to the Typo3 root directory. e.g. ../

\nn\t3::Environment()->getRelPathSite()
Copied!

| @return string

Source Code 

public function getRelPathSite () {
	return \nn\t3::File()->relPath();
}
Copied!

Environment::getRequest() 

\nn\t3::Environment()->getRequest(); 

Fetches the current request. Workaround for special cases - and in the event that the core team does not implement this option itself in the future.

$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); 

Get the current site object. This object can be used to access the configuration from the site YAML file from TYPO3 9 onwards, for example.

In the context of a MiddleWare, the site may not yet be parsed / loaded. In this case, the $request from the MiddleWare can be passed to determine the site.

See also \nn\t3::Settings()->getSiteConfig() to read the site configuration.

\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); 

Generates a virtual frontend request that can be used in any context. Also initializes the frontend TypoScript object and all relevant objects.

$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(); 

Get the absolute path to the /var directory of Typo3.

This directory stores temporary cache files. Depending on the version of Typo3 and installation type (Composer or Non-Composer mode) this directory can be found in different locations.

// /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(); 

Check whether we are in the backend context

\nn\t3::Environment()->isBackend();
Copied!

| @return bool

Source Code 

public function isBackend () {
	return !$this->isFrontend();
}
Copied!

Environment::isFrontend() 

\nn\t3::Environment()->isFrontend(); 

Check whether we are in the frontend context

\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(); 

Returns true if the page is accessed via HTTPS.

$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(); 

Checks whether installation is running on local server

\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); 

Set the current language.

Helpful if we need the language in a context where it has not been initialized, e.g. in a initialized, e.g. in a MiddleWare or 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); 

Sets the current request. Is set in the RequestParser middleware

\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(); 

Get the version of Typo3, as an integer, e.g. "8" Alias to \nn\t3::t3Version()

\nn\t3::Environment()->t3Version();

if (\nn\t3::t3Version() >= 8) {
    // only for >= Typo3 8 LTS
}
Copied!

| @return int

Source Code 

public function t3Version () {
	return \nn\t3::t3Version();
}
Copied!

Errors 

\nn\t3::Errors() 

Output errors and exceptions

Overview of Methods 

\nn\t3::Errors()->Error($message, $code = NULL); 

Throw an error with backtrace

\nn\t3::Errors()->Error('Damn', 1234);
Copied!

Is an alias to:

\nn\t3::Error('Damn', 1234);
Copied!

| @return void

| ➜ Go to source code of Errors::Error()

\nn\t3::Errors()->Exception($message, $code = NULL); 

Throw a Typo3 exception with backtrace

\nn\t3::Errors()->Exception('Damn', 1234);
Copied!

Is an alias to:

\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); 

Throw an error with backtrace

\nn\t3::Errors()->Error('Damn', 1234);
Copied!

Is an alias to:

\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); 

Throw a Typo3 exception with backtrace

\nn\t3::Errors()->Exception('Damn', 1234);
Copied!

Is an alias to:

\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() 

Methods for creating sysFile and sysFileReference entries.

Cheat sheet:

\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); 

Convert a file to a FileReference object and to the Property or ObjectStorage of a model. See also: \nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet ); with the array of multiple images can be attached to an ObjectStorage.

\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'=>'Title...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference|array

| ➜ Go to source code of Fal::attach()

\nn\t3::Fal()->clearCache($filenameOrSysFile = ''); 

Deletes the cache for the image sizes of a FAL including the converted images If, for example, the f:image-ViewHelper is used, all calculated image sizes are are saved in the sys_file_processedfile table. If the original image changes, an image from the cache may still be accessed.

\nn\t3::Fal()->clearCache( 'fileadmin/file.jpg' );
\nn\t3::Fal()->clearCache( $fileReference );
\nn\t3::Fal()->clearCache( $falFile );
Copied!
@param $filenameOrSysFile FAL or path (string) to the file
@return void

| ➜ Go to source code of Fal::clearCache()

\nn\t3::Fal()->createFalFile($storageConfig, $srcFile, $keepSrcFile = false, $forceCreateNew = false); 

Creates a File (FAL) object (sys_file)

nnt3::Fal()->createFalFile( $storageConfig, $srcFile, $keepSrcFile, $forceCreateNew );

@param string $storageConfig Path/folder in which the FAL file is to be saved (e.g. 'fileadmin/projectdata/')
@param string $srcFile Source file to be converted to FAL (e.g. 'uploads/tx_nnfesubmit/example.jpg') Can also be URL to YouTube/Vimeo video (e.g. https://www. youtube.com/watch?v=7Bb5jXhwnRY)
@param boolean $keepSrcFile Copy source file only, do not move?
@param boolean $forceCreateNew Should a new file always be created? If not, it may return an existing file object

| @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); 

Convert a file to a FileReference object and prepare it for attach() to an existing model and field / property. The FileReference is not automatically attached to the model. To set the FAL directly in the model, the helper | \nn\t3::Fal()->attach( $model, $field, $itemData ) can be used.

\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'=>'Title...'] );
Copied!

| @return \TYPO3\CMS\Extbase\Domain\Model\FileReference

| ➜ Go to source code of Fal::createForModel()

\nn\t3::Fal()->createSysFile($file, $autoCreateStorage = true); 

Creates new entry in sys_file Searches all sys_file_storage entries to see whether the path to the $file already exists as storage. If not, a new storage is created.

\nn\t3::Fal()->createSysFile( 'fileadmin/image.jpg' );
\nn\t3::Fal()->createSysFile( '/var/www/mysite/fileadmin/image.jpg' );
Copied!

| @return false|\TYPO3\CMS\Core\Resource\File

| ➜ Go to source code of Fal::createSysFile()

\nn\t3::Fal()->deleteForModel($model, $field = NULL); 

Deletes the physical files for a model (or a single field of the field of the model) from the server.

// Delete ALL files of the entire model
\nn\t3::Fal()->deleteForModel( $model );

// Delete ALL files from the "images" field
\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 = ''); 

Deletes all physical thumbnail files that were generated for an image incl. the data records in the sys_file_processedfile table.

The original image, which was passed as the $path argument, is not deleted. The whole process forces the thumbnails for an image to be regenerated if, for example, the source image has changed but the file name has remained the same.

Another use case: Cleaning up files on the server, e.g. because sensitive, personal data is to be data including all generated thumbnails should be deleted.

\nn\t3::Fal()->deleteProcessedImages( 'fileadmin/path/example.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); 

Deletes a SysFile (data record from table sys_file) and all associated SysFileReferences. A radical way to completely remove an image from the Typo3 indexing.

The physical file is not deleted from the server! See \nn\t3::File()->unlink() to delete the physical file. See \nn\t3::Fal()->detach( $model, $field ); to delete from a model.

\nn\t3::Fal()->deleteSysFile( 1201 );
\nn\t3::Fal()->deleteSysFile( 'fileadmin/path/to/image.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); 

Deletes a SysFileReference. See also \nn\t3::Fal()->detach( $model, $field ); for deleting from a 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); 

Empties an ObjectStorage in a model or removes a single individual object from the model or an ObjectStorage. In the example, image can be an ObjectStorage or a single FileReference:

\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 = []); 

Checks whether a SysFileReference to the same SysFile already exists for a data record

\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); 

Creates a sys_file_reference from a 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 = []); 

Creates a FileRefence object (table: sys_file_reference) and links it to a data set. Example: Uploaded JPG is to be attached to tt_news dataset as FAL

Parameters:

key Description: src

| src Path to the source file (can also be http link to YouTube video)

| dest Path to the destination folder (optional if file is to be moved/copied)

| table Target table to which the FileReference is to be assigned (e.g. tx_myext_domain_model_entry)

| title title

| description description

| link link

| crop crop

| table Target table to which the FileReference is to be assigned (e.g. tx_myext_domain_model_entry)

| sorting (int) Sorting

| field Column name of the target table to which the FileReference is to be assigned (e.g. image)

| uid (int) uid of the data record in the target table(tx_myext_domain_model_entry.uid)

| pid (int) pid of the data record in the target table

| cruser_id cruser_id of the data record in the target table

| copy Do not move src file but copy it (default: true)

| forceNew Force new file in target folder (otherwise it is checked whether file already exists) default: false

| single Ensure that the same FileReference is only linked once per data record (default: true)

Example:

$fal = \nn\t3::Fal()->fromFile([
    'src' => 'fileadmin/test/image.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); 

Retrieves a 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 = ''); 

Retrieves a SysFile from the CombinedIdentifier notation ('1:/uploads/example.txt'). If file does not exist, FALSE is returned.

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier( '1:/uploads/example.txt' );
Copied!
@param string $file Combined Identifier ('1:/uploads/example.txt')
@return File|boolean

| ➜ Go to source code of Fal::getFileObjectFromCombinedIdentifier()

\nn\t3::Fal()->getFilePath($falReference); 

Get the URL to a FileReference or a FalFile. Alias to \nn\t3::File()->getPublicUrl().

\nn\t3::Fal()->getFilePath( $fileReference ); // results in e.g. '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); 

Retrieves a SysFileReference based on the uid Alias to \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); 

Retrieves / converts to a TYPO3CMSCoreResourceFileReference object (sys_file_reference) "Smart" variant of \TYPO3\CMS\Extbase\Service\ImageService->getImage()

\nn\t3::Fal()->getImage( 1 );
\nn\t3::Fal()->getImage( 'path/to/image.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 = []); 

Calculates an image via maxWidth, maxHeight, cropVariant etc. Returns URI to the image as a string. Helpful for calculating thumbnails in the backend. Alias to \nn\t3::File()->process()

\nn\t3::File()->process( 'fileadmin/images/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/images/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 = []); 

Replaces a FileReference or ObjectStorage in a model with images. Typical use case: A FAL image is to be changed via an upload form in the frontend. be able to be changed.

For each image, the system checks whether a FileReference already exists in the model. Existing FileReferences are not overwritten, otherwise any captions or cropping instructions would be lost!

Attention! The model is automatically persisted!

$newModel = new \My\Extension\Domain\Model\Example();
\nn\t3::Fal()->setInModel( $newModel, 'falslideshow', 'path/to/file.jpg' );
echo $newModel->getUid(); // Model has been persisted!
Copied!

Example with a simple FileReference in the model:

$imageToSet = 'fileadmin/images/portrait.jpg';
\nn\t3::Fal()->setInModel( $member, 'falprofileimage', $imageToSet );

\nn\t3::Fal()->setInModel( $member, 'falprofileimage', ['publicUrl'=>'01.jpg', 'title'=>'Title', 'description'=>'...'] );
Copied!

Example with a single SysFile:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'image', $file );
Copied!

Example with a single SysFile that is to be stored in an ObjectStorage:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'images', [$file] );
Copied!

Example with an ObjectStorage in the model:

$imagesToSet = ['fileadmin/images/01.jpg', 'fileadmin/images/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!

Example with videos:

$videosToSet = ['https://www.youtube.com/watch?v=GwlU_wsT20Q', ...];
\nn\t3::Fal()->setInModel( $member, 'videos', $videosToSet );
Copied!
@param mixed $model The model that is to be changed
@param string $fieldName Property (field name) of the ObjectStorage or FileReference
@param mixed $imagesToAdd String / array with images

| @return mixed

| ➜ Go to source code of Fal::setInModel()

\nn\t3::Fal()->toArray($fileReference = NULL); 

Convert a FileReference into an array. Contains publicUrl, title, alternative, crop etc. of the FileReference. Alias to \nn\t3::Obj()->toArray( $fileReference );

\nn\t3::Fal()->toArray( $fileReference ); // results in ['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 the information in sys_file_metadata and sys_file

\nn\t3::Fal()->updateMetaData( 'fileadmin/file.jpg' );
\nn\t3::Fal()->updateMetaData( $fileReference );
\nn\t3::Fal()->updateMetaData( $falFile );
Copied!
@param $filenameOrSysFile FAL or path (string) to the file
@param $data Array with data to be updated. If empty, image data is read automatically
@return void

| ➜ Go to source code of Fal::updateMetaData()

Methods 

Fal::attach() 

\nn\t3::Fal()->attach($model, $field, $itemData = NULL); 

Convert a file to a FileReference object and to the Property or ObjectStorage of a model. See also: \nn\t3::Fal()->setInModel( $member, 'falslideshow', $imagesToSet ); with the array of multiple images can be attached to an ObjectStorage.

\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'=>'Title...'] );
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 = ''); 

Deletes the cache for the image sizes of a FAL including the converted images If, for example, the f:image-ViewHelper is used, all calculated image sizes are are saved in the sys_file_processedfile table. If the original image changes, an image from the cache may still be accessed.

\nn\t3::Fal()->clearCache( 'fileadmin/file.jpg' );
\nn\t3::Fal()->clearCache( $fileReference );
\nn\t3::Fal()->clearCache( $falFile );
Copied!
@param $filenameOrSysFile FAL or path (string) to the file
@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); 

Creates a File (FAL) object (sys_file)

nnt3::Fal()->createFalFile( $storageConfig, $srcFile, $keepSrcFile, $forceCreateNew );

@param string $storageConfig Path/folder in which the FAL file is to be saved (e.g. 'fileadmin/projectdata/')
@param string $srcFile Source file to be converted to FAL (e.g. 'uploads/tx_nnfesubmit/example.jpg') Can also be URL to YouTube/Vimeo video (e.g. https://www. youtube.com/watch?v=7Bb5jXhwnRY)
@param boolean $keepSrcFile Copy source file only, do not move?
@param boolean $forceCreateNew Should a new file always be created? If not, it may return an existing file object

| @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); 

Convert a file to a FileReference object and prepare it for attach() to an existing model and field / property. The FileReference is not automatically attached to the model. To set the FAL directly in the model, the helper | \nn\t3::Fal()->attach( $model, $field, $itemData ) can be used.

\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'=>'Title...'] );
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); 

Creates new entry in sys_file Searches all sys_file_storage entries to see whether the path to the $file already exists as storage. If not, a new storage is created.

\nn\t3::Fal()->createSysFile( 'fileadmin/image.jpg' );
\nn\t3::Fal()->createSysFile( '/var/www/mysite/fileadmin/image.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); 

Deletes the physical files for a model (or a single field of the field of the model) from the server.

// Delete ALL files of the entire model
\nn\t3::Fal()->deleteForModel( $model );

// Delete ALL files from the "images" field
\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 = ''); 

Deletes all physical thumbnail files that were generated for an image incl. the data records in the sys_file_processedfile table.

The original image, which was passed as the $path argument, is not deleted. The whole process forces the thumbnails for an image to be regenerated if, for example, the source image has changed but the file name has remained the same.

Another use case: Cleaning up files on the server, e.g. because sensitive, personal data is to be data including all generated thumbnails should be deleted.

\nn\t3::Fal()->deleteProcessedImages( 'fileadmin/path/example.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); 

Deletes a SysFile (data record from table sys_file) and all associated SysFileReferences. A radical way to completely remove an image from the Typo3 indexing.

The physical file is not deleted from the server! See \nn\t3::File()->unlink() to delete the physical file. See \nn\t3::Fal()->detach( $model, $field ); to delete from a model.

\nn\t3::Fal()->deleteSysFile( 1201 );
\nn\t3::Fal()->deleteSysFile( 'fileadmin/path/to/image.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); 

Deletes a SysFileReference. See also \nn\t3::Fal()->detach( $model, $field ); for deleting from a 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); 

Empties an ObjectStorage in a model or removes a single individual object from the model or an ObjectStorage. In the example, image can be an ObjectStorage or a single FileReference:

\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 = []); 

Checks whether a SysFileReference to the same SysFile already exists for a data record

\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); 

Creates a sys_file_reference from a 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 = []); 

Creates a FileRefence object (table: sys_file_reference) and links it to a data set. Example: Uploaded JPG is to be attached to tt_news dataset as FAL

Parameters:

key Description: src

| src Path to the source file (can also be http link to YouTube video)

| dest Path to the destination folder (optional if file is to be moved/copied)

| table Target table to which the FileReference is to be assigned (e.g. tx_myext_domain_model_entry)

| title title

| description description

| link link

| crop crop

| table Target table to which the FileReference is to be assigned (e.g. tx_myext_domain_model_entry)

| sorting (int) Sorting

| field Column name of the target table to which the FileReference is to be assigned (e.g. image)

| uid (int) uid of the data record in the target table(tx_myext_domain_model_entry.uid)

| pid (int) pid of the data record in the target table

| cruser_id cruser_id of the data record in the target table

| copy Do not move src file but copy it (default: true)

| forceNew Force new file in target folder (otherwise it is checked whether file already exists) default: false

| single Ensure that the same FileReference is only linked once per data record (default: true)

Example:

$fal = \nn\t3::Fal()->fromFile([
    'src' => 'fileadmin/test/image.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); 

Retrieves a 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 = ''); 

Retrieves a SysFile from the CombinedIdentifier notation ('1:/uploads/example.txt'). If file does not exist, FALSE is returned.

\nn\t3::Fal()->getFileObjectFromCombinedIdentifier( '1:/uploads/example.txt' );
Copied!
@param string $file Combined Identifier ('1:/uploads/example.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); 

Get the URL to a FileReference or a FalFile. Alias to \nn\t3::File()->getPublicUrl().

\nn\t3::Fal()->getFilePath( $fileReference ); // results in e.g. '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); 

Retrieves a SysFileReference based on the uid Alias to \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); 

Retrieves / converts to a TYPO3CMSCoreResourceFileReference object (sys_file_reference) "Smart" variant of \TYPO3\CMS\Extbase\Service\ImageService->getImage()

\nn\t3::Fal()->getImage( 1 );
\nn\t3::Fal()->getImage( 'path/to/image.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 = []); 

Calculates an image via maxWidth, maxHeight, cropVariant etc. Returns URI to the image as a string. Helpful for calculating thumbnails in the backend. Alias to \nn\t3::File()->process()

\nn\t3::File()->process( 'fileadmin/images/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/images/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 = []); 

Replaces a FileReference or ObjectStorage in a model with images. Typical use case: A FAL image is to be changed via an upload form in the frontend. be able to be changed.

For each image, the system checks whether a FileReference already exists in the model. Existing FileReferences are not overwritten, otherwise any captions or cropping instructions would be lost!

Attention! The model is automatically persisted!

$newModel = new \My\Extension\Domain\Model\Example();
\nn\t3::Fal()->setInModel( $newModel, 'falslideshow', 'path/to/file.jpg' );
echo $newModel->getUid(); // Model has been persisted!
Copied!

Example with a simple FileReference in the model:

$imageToSet = 'fileadmin/images/portrait.jpg';
\nn\t3::Fal()->setInModel( $member, 'falprofileimage', $imageToSet );

\nn\t3::Fal()->setInModel( $member, 'falprofileimage', ['publicUrl'=>'01.jpg', 'title'=>'Title', 'description'=>'...'] );
Copied!

Example with a single SysFile:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'image', $file );
Copied!

Example with a single SysFile that is to be stored in an ObjectStorage:

$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier('1:/foo.jpg');
\nn\t3::Fal()->setInModel( $member, 'images', [$file] );
Copied!

Example with an ObjectStorage in the model:

$imagesToSet = ['fileadmin/images/01.jpg', 'fileadmin/images/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!

Example with videos:

$videosToSet = ['https://www.youtube.com/watch?v=GwlU_wsT20Q', ...];
\nn\t3::Fal()->setInModel( $member, 'videos', $videosToSet );
Copied!
@param mixed $model The model that is to be changed
@param string $fieldName Property (field name) of the ObjectStorage or FileReference
@param mixed $imagesToAdd String / array with images

| @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); 

Convert a FileReference into an array. Contains publicUrl, title, alternative, crop etc. of the FileReference. Alias to \nn\t3::Obj()->toArray( $fileReference );

\nn\t3::Fal()->toArray( $fileReference ); // results in ['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 the information in sys_file_metadata and sys_file

\nn\t3::Fal()->updateMetaData( 'fileadmin/file.jpg' );
\nn\t3::Fal()->updateMetaData( $fileReference );
\nn\t3::Fal()->updateMetaData( $falFile );
Copied!
@param $filenameOrSysFile FAL or path (string) to the file
@param $data Array with data to be updated. If empty, image data is read automatically
@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() 

Methods relating to the file system: Reading, writing, copying, moving and cleaning up files.

Overview of Methods 

\nn\t3::File()->absUrl($file = NULL); 

Generate absolute URL to a file. Returns the complete path to the file including https://.../.

// => https://www.myweb.de/fileadmin/bild.jpg
\nn\t3::File()->absUrl( 'fileadmin/image.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); 

Specifies path to file / folder WITH absolute path

Example:

\nn\t3::File()->addPathSite('fileadmin/test.jpg');
 // ==> returns var/www/website/fileadmin/test.jpg
Copied!

| @return string

| ➜ Go to source code of File::addPathSite()

\nn\t3::File()->addSuffix($filename = NULL, $newSuffix = ''); 

Replaces the suffix for a file name.

\nn\t3::File()->addSuffix('image', 'jpg'); // => image.jpg
\nn\t3::File()->addSuffix('image.png', 'jpg'); // => image.jpg
\nn\t3::File()->addSuffix('path/to/image.png', 'jpg'); // => path/to/image.jpg
Copied!

| @return string

| ➜ Go to source code of File::addSuffix()

\nn\t3::File()->cleanFilename($filename = ''); 

Cleans a file name

$clean = \nn\t3::File()->cleanFilename('fileadmin/noe_so_not.jpg'); // 'fileadmin/noe_so_not.jpg'
Copied!

| @return string

| ➜ Go to source code of File::cleanFilename()

\nn\t3::File()->copy($src = NULL, $dest = NULL, $renameIfFileExists = true); 

Copies a file. Returns false if the file could not be copied. Returns (new) file name if copying was successful.

$filename = \nn\t3::File()->copy('fileadmin/image.jpg', 'fileadmin/image-copy.jpg');
Copied!
@param string $src Path to the source file
@param string $dest Path to the destination file
@param boolean $renameIfFileExists Rename file if a file with the same name already exists at the destination location
@return string|boolean

| ➜ Go to source code of File::copy()

\nn\t3::File()->createFolder($path = NULL); 

Create a folder in fileadmin/ To create a folder outside the fileadmin, use the method \nn\t3::File()->mkdir().

\nn\t3::File()->createFolder('tests');
Copied!

| @return boolean

| ➜ Go to source code of File::createFolder()

\nn\t3::File()->download($files = NULL, $filename = NULL); 

Download a single file or a zipped archive.

Download as ZIP requires the PHP extension gmp. If extension is not available, the .tar variant is used. On Mac, the function is always used due to security warnings from the Finder, the function always uses 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!

If an array is passed, a tar/zip download is started. By passing an associative array with file name as key and path in the archive as value the file and folder structure in the zip archive can be determined.

\nn\t3::File()->download( ['fileadmin/test-1.pdf', 'fileadmin/test-2.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'one.pdf', 'fileadmin/test-2.pdf'=>'two.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'zip-folder-1/one.pdf', 'fileadmin/test-2.pdf'=>'zip-folder-2/two.pdf'], 'archive.zip' );
Copied!
@param mixed $files String or array of the files to be loaded
@param mixed $filename Optional: Overwrite file name during download
@return void

| ➜ Go to source code of File::download()

\nn\t3::File()->exists($src = NULL); 

Checks whether a file exists. Returns the absolute path to the file.

\nn\t3::File()->exists('fileadmin/image.jpg');
Copied!

Also exists as ViewHelper:

{nnt3:file.exists(file:'path/to/image.jpg')}
Copied!

| @return string|boolean

| ➜ Go to source code of File::exists()

\nn\t3::File()->extractExifData($filename = ''); 

Save EXIF data for file in JSON.

\nn\t3::File()->extractExifData( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::extractExifData()

\nn\t3::File()->getData($file = ''); 

Get image info + EXIF data for file. Also searches for JSON file that may have been generated after processImage()

| @return array

| ➜ Go to source code of File::getData()

\nn\t3::File()->getExifData($filename = ''); 

Get ALL EXIF data for file.

\nn\t3::File()->getExif( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getExifData()

\nn\t3::File()->getFolder($file); 

Returns the folder to a file

Example:

\nn\t3::File()->getFolder('fileadmin/test/example.txt');
// ==> returns 'fileadmin/test/'
Copied!

| @return string

| ➜ Go to source code of File::getFolder()

\nn\t3::File()->getImageData($filename = ''); 

Get EXIF image data for file.

\nn\t3::File()->getImageData( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getImageData()

\nn\t3::File()->getImageSize($filename = ''); 

get imagesize for file.

\nn\t3::File()->getImageSize( 'yellowstone.jpg' );
Copied!

| @return array

| ➜ Go to source code of File::getImageSize()

\nn\t3::File()->getLocationData($filename = ''); 

Get EXIF GEO data for file. Address data is determined automatically if possible

\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); 

Returns the path of a file using a file name and the storage. Example:

\nn\t3::File()->getPath('media/image.jpg', $storage);
// ==> returns '/var/www/.../fileadmin/media/image.jpg'
\nn\t3::File()->getPath('fileadmin/media/image.jpg');
// ==> returns '/var/www/.../fileadmin/media/image.jpg'
Copied!

| @return string

| ➜ Go to source code of File::getPath()

\nn\t3::File()->getPublicUrl($obj = NULL, $absolute = false); 

Gets path to the file, relative to the Typo3 installation directory (PATH_site). Can handle all types of objects.

\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); 

Returns the relative path of a file to the specified storage.

Example:

\nn\t3::File()->getRelativePathInStorage('fileadmin/media/image.jpg', $storage);
// ==> returns 'media/image.jpg'
Copied!

| @return string

| ➜ Go to source code of File::getRelativePathInStorage()

\nn\t3::File()->getStorage($file, $createIfNotExists = false); 

Finds a matching sys_file_storage for a file or folder path. To do this, searches through all sys_file_storage entries and compares whether the basePath of the storage matches the path of the file.

\nn\t3::File()->getStorage('fileadmin/test/example.txt');
\nn\t3::File()->getStorage( $falFile );
\nn\t3::File()->getStorage( $sysFileReference );
// returns ResourceStorage with basePath "fileadmin/"
Copied!

| @return ResourceStorage

| ➜ Go to source code of File::getStorage()

\nn\t3::File()->isAllowed($filename = NULL); 

Specifies whether the file type is allowed

\nn\t3::File()->isForbidden('image.jpg'); => returns 'true'
\nn\t3::File()->isForbidden('hack.php'); => returns 'false'
Copied!

| @return boolean

| ➜ Go to source code of File::isAllowed()

\nn\t3::File()->isConvertableToImage($filename = NULL); 

Specifies whether the file can be converted to an image

\nn\t3::File()->isConvertableToImage('image.jpg'); => returns true
\nn\t3::File()->isConvertableToImage('text.ppt'); => returns false
Copied!

| @return boolean

| ➜ Go to source code of File::isConvertableToImage()

\nn\t3::File()->isExternalVideo($url = NULL); 

Indicates whether it is a video on YouTube / Vimeo. If yes, an array with embedding information is returned.

\nn\t3::File()->isExternalVideo('http://...');
Copied!

| @return array|boolean

| ➜ Go to source code of File::isExternalVideo()

\nn\t3::File()->isFolder($file); 

Returns whether the specified path is a folder

Example:

\nn\t3::File()->isFolder('fileadmin'); // => returns true
Copied!

| @return boolean

| ➜ Go to source code of File::isFolder()

\nn\t3::File()->isForbidden($filename = NULL, $allowed = []); 

Indicates whether the file type is prohibited

\nn\t3::File()->isForbidden('image.jpg'); => returns 'false'
\nn\t3::File()->isForbidden('image.xyz', ['xyz']); => returns 'false'
\nn\t3::File()->isForbidden('hack.php'); => returns 'true'
\nn\t3::File()->isForbidden('.htaccess'); => returns 'true'
Copied!
@param string $filename
@param array $allowed
@return boolean

| ➜ Go to source code of File::isForbidden()

\nn\t3::File()->isImage($filename = NULL); 

Indicates whether the file is in an image

\nn\t3::File()->isImage('image.jpg'); => returns true
\nn\t3::File()->isImage('text.ppt'); => returns false
Copied!

| @return boolean

| ➜ Go to source code of File::isImage()

\nn\t3::File()->isVideo($filename = NULL); 

Indicates whether the file is a video

\nn\t3::File()->isVideo('path/to/video.mp4'); => returns true
Copied!

| @return boolean

| ➜ Go to source code of File::isVideo()

\nn\t3::File()->mkdir($path = ''); 

Create a folder

\nn\t3::File()->mkdir( 'fileadmin/my/folder/' );
\nn\t3::File()->mkdir( '1:/my/folder/' );
Copied!

| @return boolean

| ➜ Go to source code of File::mkdir()

\nn\t3::File()->move($src = NULL, $dest = NULL); 

Moves a file

\nn\t3::File()->move('fileadmin/image.jpg', 'fileadmin/image-copy.jpg');
Copied!

| @return boolean

| ➜ Go to source code of File::move()

\nn\t3::File()->moveUploadedFile($src = NULL, $dest = NULL); 

Move an upload file to the target directory.

Can be the absolute path to the tmp file of the upload â or a TYPO3\CMS\Core\Http\UploadedFile, which can be retrieved in the controller via $this->request->getUploadedFiles().

\nn\t3::File()->moveUploadedFile('/tmp/xjauGSaudsha', 'fileadmin/image-copy.jpg');
\nn\t3::File()->moveUploadedFile( $fileObj, 'fileadmin/image-copy.jpg');
Copied!

| @return string

| ➜ Go to source code of File::moveUploadedFile()

\nn\t3::File()->normalizePath($path); 

Resolves ../../ specifications in path. Works with both existing paths (via realpath) and non-existing paths. non-existing paths.

\nn\t3::File()->normalizePath( 'fileadmin/test/../image.jpg' ); => fileadmin/image.jpg
Copied!

| @return string

| ➜ Go to source code of File::normalizePath()

\nn\t3::File()->process($fileObj = '', $processing = [], $returnProcessedImage = false); 

Calculates an image via maxWidth, maxHeight etc. Simple version of \nn\t3::File()->processImage() Can be used if only the generation of reduced images is required without taking into account corrections to camera alignment etc.

Since the crop settings are stored in FileReference and not File,
cropVariant only works when a FileReference is passed.
\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/images/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!

With the parameter $returnProcessedImage = true, not the file path to the new image but the processedImage object is returned.

\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 = []); 

Can be called directly after upload_copy_move(). Corrects the orientation of the image, which may have been saved in EXIF data. Simply use the method \nn\t3::File()->process() for the maxWidth statement.

Instructions for $processing:

| correctOrientation => Correct rotation (e.g. because photo was uploaded from smartphone)

| @return string

| ➜ Go to source code of File::processImage()

\nn\t3::File()->read($src = NULL); 

Retrieves the content of a file

\nn\t3::File()->read('fileadmin/text.txt');
Copied!

| @return string|boolean

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

\nn\t3::File()->relPath($path = ''); 

relative path (from the current script) to a file / directory. If no path is specified, the Typo3 root directory is returned.

\nn\t3::File()->relPath( $file ); => ../fileadmin/image.jpg
\nn\t3::File()->relPath(); => ../
Copied!

| @return string

| ➜ Go to source code of File::relPath()

\nn\t3::File()->resolvePathPrefixes($file = NULL, $absolute = false); 

EXT: Resolve prefix to relative path specification

\nn\t3::File()->resolvePathPrefixes('EXT:extname'); => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/'); => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/image.jpg'); => /typo3conf/ext/extname/image.jpg
\nn\t3::File()->resolvePathPrefixes('1:/uploads/image.jpg', true); => /var/www/website/fileadmin/uploads/image.jpg
Copied!

| @return string

| ➜ Go to source code of File::resolvePathPrefixes()

\nn\t3::File()->sendDownloadHeader($filename = '', $filesize = NULL); 

Send PHP header for download. If the file physically exists, the filesize is determined automatically.

\nn\t3::File()->sendDownloadHeader( 'download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'path/to/file/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); 

Returns the file size of a file in bytes If file does not exist, 0 is returned.

\nn\t3::File()->size('fileadmin/image.jpg');
Copied!

| @return integer

| ➜ Go to source code of File::size()

\nn\t3::File()->stripBaseUrl($file); 

Removes the URL if it corresponds to the current domain

Example:

\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); 

Specifies the path to the file / folder WITHOUT an absolute path. Optionally, a prefix can be specified.

Example:

\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); 

Returns the suffix of the file

\nn\t3::File()->suffix('image.jpg'); => returns 'jpg'
Copied!

| @return string

| ➜ Go to source code of File::suffix()

\nn\t3::File()->suffixForMimeType($mime = ''); 

Returns the suffix for a specific mime type / content type. Very reduced version - only a few types covered. Extensive version: https://bit.ly/3B9KrNA

\nn\t3::File()->suffixForMimeType('image/jpeg'); => returns 'jpg'
Copied!

| @return string

| ➜ Go to source code of File::suffixForMimeType()

\nn\t3::File()->type($filename = NULL); 

Returns the type of file based on the file suffix

\nn\t3::File()->type('image.jpg'); => returns 'image'
\nn\t3::File()->type('text.doc'); => returns 'document'
Copied!

| @return string

| ➜ Go to source code of File::type()

\nn\t3::File()->uniqueFilename($filename = ''); 

Creates a unique file name for the file if there is already a file with an identical name already exists in the target directory already exists in the target directory.

$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); 

Create a folder and/or file. Also creates the folders if they do not exist.

\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); 

Generate absolute URL to a file. Returns the complete path to the file including https://.../.

// => https://www.myweb.de/fileadmin/bild.jpg
\nn\t3::File()->absUrl( 'fileadmin/image.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); 

Specifies path to file / folder WITH absolute path

Example:

\nn\t3::File()->addPathSite('fileadmin/test.jpg');
 // ==> returns var/www/website/fileadmin/test.jpg
Copied!

| @return string

Source Code 

public function addPathSite($file)
{
	return $this->stripPathSite($file, true);
}
Copied!

File::addSuffix() 

\nn\t3::File()->addSuffix($filename = NULL, $newSuffix = ''); 

Replaces the suffix for a file name.

\nn\t3::File()->addSuffix('image', 'jpg'); // => image.jpg
\nn\t3::File()->addSuffix('image.png', 'jpg'); // => image.jpg
\nn\t3::File()->addSuffix('path/to/image.png', 'jpg'); // => path/to/image.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 = ''); 

Cleans a file name

$clean = \nn\t3::File()->cleanFilename('fileadmin/noe_so_not.jpg'); // 'fileadmin/noe_so_not.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); 

Copies a file. Returns false if the file could not be copied. Returns (new) file name if copying was successful.

$filename = \nn\t3::File()->copy('fileadmin/image.jpg', 'fileadmin/image-copy.jpg');
Copied!
@param string $src Path to the source file
@param string $dest Path to the destination file
@param boolean $renameIfFileExists Rename file if a file with the same name already exists at the destination location
@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); 

Create a folder in fileadmin/ To create a folder outside the fileadmin, use the method \nn\t3::File()->mkdir().

\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 a single file or a zipped archive.

Download as ZIP requires the PHP extension gmp. If extension is not available, the .tar variant is used. On Mac, the function is always used due to security warnings from the Finder, the function always uses 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!

If an array is passed, a tar/zip download is started. By passing an associative array with file name as key and path in the archive as value the file and folder structure in the zip archive can be determined.

\nn\t3::File()->download( ['fileadmin/test-1.pdf', 'fileadmin/test-2.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'one.pdf', 'fileadmin/test-2.pdf'=>'two.pdf'], 'archive.zip' );
\nn\t3::File()->download( ['fileadmin/test-1.pdf'=>'zip-folder-1/one.pdf', 'fileadmin/test-2.pdf'=>'zip-folder-2/two.pdf'], 'archive.zip' );
Copied!
@param mixed $files String or array of the files to be loaded
@param mixed $filename Optional: Overwrite file name during 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); 

Checks whether a file exists. Returns the absolute path to the file.

\nn\t3::File()->exists('fileadmin/image.jpg');
Copied!

Also exists as ViewHelper:

{nnt3:file.exists(file:'path/to/image.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 = ''); 

Save EXIF data for file in JSON.

\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 = ''); 

Get image info + EXIF data for file. Also searches for JSON file that may have been generated after processImage()

| @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 = ''); 

Get ALL EXIF data for file.

\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); 

Returns the folder to a file

Example:

\nn\t3::File()->getFolder('fileadmin/test/example.txt');
// ==> returns 'fileadmin/test/'
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 = ''); 

Get EXIF image data for file.

\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 = ''); 

get imagesize for file.

\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 = ''); 

Get EXIF GEO data for file. Address data is determined automatically if possible

\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); 

Returns the path of a file using a file name and the storage. Example:

\nn\t3::File()->getPath('media/image.jpg', $storage);
// ==> returns '/var/www/.../fileadmin/media/image.jpg'
\nn\t3::File()->getPath('fileadmin/media/image.jpg');
// ==> returns '/var/www/.../fileadmin/media/image.jpg'
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); 

Gets path to the file, relative to the Typo3 installation directory (PATH_site). Can handle all types of objects.

\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); 

Returns the relative path of a file to the specified storage.

Example:

\nn\t3::File()->getRelativePathInStorage('fileadmin/media/image.jpg', $storage);
// ==> returns 'media/image.jpg'
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); 

Finds a matching sys_file_storage for a file or folder path. To do this, searches through all sys_file_storage entries and compares whether the basePath of the storage matches the path of the file.

\nn\t3::File()->getStorage('fileadmin/test/example.txt');
\nn\t3::File()->getStorage( $falFile );
\nn\t3::File()->getStorage( $sysFileReference );
// returns ResourceStorage with basePath "fileadmin/"
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); 

Specifies whether the file type is allowed

\nn\t3::File()->isForbidden('image.jpg'); => returns 'true'
\nn\t3::File()->isForbidden('hack.php'); => returns 'false'
Copied!

| @return boolean

Source Code 

public function isAllowed($filename = null)
{
	return !$this->isForbidden($filename);
}
Copied!

File::isConvertableToImage() 

\nn\t3::File()->isConvertableToImage($filename = NULL); 

Specifies whether the file can be converted to an image

\nn\t3::File()->isConvertableToImage('image.jpg'); => returns true
\nn\t3::File()->isConvertableToImage('text.ppt'); => returns false
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); 

Indicates whether it is a video on YouTube / Vimeo. If yes, an array with embedding information is returned.

\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); 

Returns whether the specified path is a folder

Example:

\nn\t3::File()->isFolder('fileadmin'); // => returns true
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 = []); 

Indicates whether the file type is prohibited

\nn\t3::File()->isForbidden('image.jpg'); => returns 'false'
\nn\t3::File()->isForbidden('image.xyz', ['xyz']); => returns 'false'
\nn\t3::File()->isForbidden('hack.php'); => returns 'true'
\nn\t3::File()->isForbidden('.htaccess'); => returns 'true'
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); 

Indicates whether the file is in an image

\nn\t3::File()->isImage('image.jpg'); => returns true
\nn\t3::File()->isImage('text.ppt'); => returns false
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); 

Indicates whether the file is a video

\nn\t3::File()->isVideo('path/to/video.mp4'); => returns true
Copied!

| @return boolean

Source Code 

public function isVideo($filename = null)
{
	return $this->type($filename) == 'video';
}
Copied!

File::mkdir() 

\nn\t3::File()->mkdir($path = ''); 

Create a folder

\nn\t3::File()->mkdir( 'fileadmin/my/folder/' );
\nn\t3::File()->mkdir( '1:/my/folder/' );
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); 

Moves a file

\nn\t3::File()->move('fileadmin/image.jpg', 'fileadmin/image-copy.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); 

Move an upload file to the target directory.

Can be the absolute path to the tmp file of the upload â or a TYPO3\CMS\Core\Http\UploadedFile, which can be retrieved in the controller via $this->request->getUploadedFiles().

\nn\t3::File()->moveUploadedFile('/tmp/xjauGSaudsha', 'fileadmin/image-copy.jpg');
\nn\t3::File()->moveUploadedFile( $fileObj, 'fileadmin/image-copy.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); 

Resolves ../../ specifications in path. Works with both existing paths (via realpath) and non-existing paths. non-existing paths.

\nn\t3::File()->normalizePath( 'fileadmin/test/../image.jpg' ); => fileadmin/image.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); 

Calculates an image via maxWidth, maxHeight etc. Simple version of \nn\t3::File()->processImage() Can be used if only the generation of reduced images is required without taking into account corrections to camera alignment etc.

Since the crop settings are stored in FileReference and not File,
cropVariant only works when a FileReference is passed.
\nn\t3::File()->process( 'fileadmin/imgs/portrait.jpg', ['maxWidth'=>200] );
\nn\t3::File()->process( '1:/images/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!

With the parameter $returnProcessedImage = true, not the file path to the new image but the processedImage object is returned.

\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 = []); 

Can be called directly after upload_copy_move(). Corrects the orientation of the image, which may have been saved in EXIF data. Simply use the method \nn\t3::File()->process() for the maxWidth statement.

Instructions for $processing:

| correctOrientation => Correct rotation (e.g. because photo was uploaded from smartphone)

| @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); 

Retrieves the content of a file

\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 = ''); 

relative path (from the current script) to a file / directory. If no path is specified, the Typo3 root directory is returned.

\nn\t3::File()->relPath( $file ); => ../fileadmin/image.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: Resolve prefix to relative path specification

\nn\t3::File()->resolvePathPrefixes('EXT:extname'); => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/'); => /typo3conf/ext/extname/
\nn\t3::File()->resolvePathPrefixes('EXT:extname/image.jpg'); => /typo3conf/ext/extname/image.jpg
\nn\t3::File()->resolvePathPrefixes('1:/uploads/image.jpg', true); => /var/www/website/fileadmin/uploads/image.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); 

Send PHP header for download. If the file physically exists, the filesize is determined automatically.

\nn\t3::File()->sendDownloadHeader( 'download.jpg' );
\nn\t3::File()->sendDownloadHeader( 'path/to/file/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); 

Returns the file size of a file in bytes If file does not exist, 0 is returned.

\nn\t3::File()->size('fileadmin/image.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); 

Removes the URL if it corresponds to the current domain

Example:

\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); 

Specifies the path to the file / folder WITHOUT an absolute path. Optionally, a prefix can be specified.

Example:

\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); 

Returns the suffix of the file

\nn\t3::File()->suffix('image.jpg'); => returns 'jpg'
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 = ''); 

Returns the suffix for a specific mime type / content type. Very reduced version - only a few types covered. Extensive version: https://bit.ly/3B9KrNA

\nn\t3::File()->suffixForMimeType('image/jpeg'); => returns 'jpg'
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); 

Returns the type of file based on the file suffix

\nn\t3::File()->type('image.jpg'); => returns 'image'
\nn\t3::File()->type('text.doc'); => returns 'document'
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 = ''); 

Creates a unique file name for the file if there is already a file with an identical name already exists in the target directory already exists in the target directory.

$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); 

Create a folder and/or file. Also creates the folders if they do not exist.

\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() 

Load and parse FlexForms

Overview of Methods 

\nn\t3::Flexform()->getFalMedia($ttContentUid = NULL, $field = ''); 

Deletes FAL media that were specified directly in the FlexForm

\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); 

Retrieves the flexform of a specific content element as an array

\nn\t3::Flexform()->getFlexform( 1201 );
Copied!

| @return array

| ➜ Go to source code of Flexform::getFlexform()

\nn\t3::Flexform()->insertCountries($config, $a = NULL); 

Inserts options from TypoScript for selection in a FlexForm or TCA.

	
select

nn\t3\Flexform->insertCountries
1
	
Copied!

| @return array

| ➜ Go to source code of Flexform::insertCountries()

\nn\t3::Flexform()->insertOptions($config, $a = NULL); 

Inserts options from TypoScript for selection in a FlexForm or TCA.

	
select

nn\t3\Flexform->insertOptions
plugin.tx_extname.settings.templates

tx_extname.colors

value
1
Nothing

1
	
Copied!

Various types of structure are permitted for the Typoscript:

plugin.tx_extname.settings.templates {
    # Direct key => label pairs
    small = Small Design
    # ... or: Label set in subarray
    mid {
        label = Mid Design
    }
    # ... or: Key set in subarray, practical e.g. for CSS classes
    10 {
        label = Big Design
        classes = big big-thing
    }
    # ... or a userFunc. Returns one of the variants above as an array
    30 {
        userFunc = nn\t3\Flexform->getOptions
    }
}
Copied!

The selection can be restricted to certain controller actions in the TypoScript. In this example, the "Yellow" option is only displayed if the switchableControllerAction | Category->list has been selected.

plugin.tx_extname.settings.templates {
    yellow {
        label = Yellow
        controllerAction = Category->list,...
    }
}
Copied!

| @return array

| ➜ Go to source code of Flexform::insertOptions()

\nn\t3::Flexform()->parse($xml = ''); 

Converts a Flexform XML into an array

\nn\t3::Flexform()->parse('');
Copied!

Also exists as a 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 = ''); 

Deletes FAL media that were specified directly in the FlexForm

\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); 

Retrieves the flexform of a specific content element as an 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); 

Inserts options from TypoScript for selection in a FlexForm or TCA.

	
select

nn\t3\Flexform->insertCountries
1
	
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); 

Inserts options from TypoScript for selection in a FlexForm or TCA.

	
select

nn\t3\Flexform->insertOptions
plugin.tx_extname.settings.templates

tx_extname.colors

value
1
Nothing

1
	
Copied!

Various types of structure are permitted for the Typoscript:

plugin.tx_extname.settings.templates {
    # Direct key => label pairs
    small = Small Design
    # ... or: Label set in subarray
    mid {
        label = Mid Design
    }
    # ... or: Key set in subarray, practical e.g. for CSS classes
    10 {
        label = Big Design
        classes = big big-thing
    }
    # ... or a userFunc. Returns one of the variants above as an array
    30 {
        userFunc = nn\t3\Flexform->getOptions
    }
}
Copied!

The selection can be restricted to certain controller actions in the TypoScript. In this example, the "Yellow" option is only displayed if the switchableControllerAction | Category->list has been selected.

plugin.tx_extname.settings.templates {
    yellow {
        label = Yellow
        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 = ''); 

Converts a Flexform XML into an array

\nn\t3::Flexform()->parse('');
Copied!

Also exists as a 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(); 

Get the current FE user. Alias to \nn\t3::FrontendUser()->getCurrentUser();

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

Also exists as 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); 

Return all existing user groups. Returns an associative array, key is the uid, value is the title.

\nn\t3::FrontendUser()->getAvailableUserGroups();
Copied!

Alternatively, true can be used to return the complete data set for the user groups can be returned:

\nn\t3::FrontendUser()->getAvailableUserGroups( true );
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getAvailableUserGroups()

\nn\t3::FrontendUser()->getCookie(); 

Gets the current fe_typo_user cookie.

$cookie = \nn\t3::FrontendUser()->getCookie();
Copied!

| @return string

| ➜ Go to source code of FrontendUser::getCookie()

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

Get the cookie name of the frontend user cookie. Usually fe_typo_user, unless it has been changed in the LocalConfiguration.

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

return string

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

\nn\t3::FrontendUser()->getCurrentUser(); 

Get array with the data of the current FE user.

\nn\t3::FrontendUser()->getCurrentUser();
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getCurrentUser()

\nn\t3::FrontendUser()->getCurrentUserGroups($returnRowData = false); 

Get user groups of the current FE user as an array. The uids of the user groups are used as keys in the returned array.

// Minimal version: By default, Typo3 only returns title, uid and pid
\nn\t3::FrontendUser()->getCurrentUserGroups(); // [1 => ['title'=>'Group A', 'uid' => 1, 'pid'=>5]]

// If true, the complete data record for the fe_user_group can be read from the DB
\nn\t3::FrontendUser()->getCurrentUserGroups( true ); // [1 => [... all fields of the DB] ]
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getCurrentUserGroups()

\nn\t3::FrontendUser()->getCurrentUserUid(); 

Get UID of the current frontend user

$uid = \nn\t3::FrontendUser()->getCurrentUserUid();
Copied!

| @return int

| ➜ Go to source code of FrontendUser::getCurrentUserUid()

\nn\t3::FrontendUser()->getGroups($returnRowData = false); 

Get user groups of the current FE user. Alias to \nn\t3::FrontendUser()->getCurrentUserGroups();

// only load title, uid and pid of the groups
\nn\t3::FrontendUser()->getGroups();
// load complete data set of the groups
\nn\t3::FrontendUser()->getGroups( true );
Copied!

| @return array

| ➜ Go to source code of FrontendUser::getGroups()

\nn\t3::FrontendUser()->getLanguage(); 

Get language UID of the current user

$languageUid = \nn\t3::FrontendUser()->getLanguage();
Copied!

| @return int

| ➜ Go to source code of FrontendUser::getLanguage()

\nn\t3::FrontendUser()->getSession(); 

Get the current user session.

\nn\t3::FrontendUser()->getSession();
Copied!

| @return \TYPO3\CMS\Core\Session\UserSession

| ➜ Go to source code of FrontendUser::getSession()

\nn\t3::FrontendUser()->getSessionData($key = NULL); 

Get session data for FE users

\nn\t3::FrontendUser()->getSessionData('store')
Copied!

| @return mixed

| ➜ Go to source code of FrontendUser::getSessionData()

\nn\t3::FrontendUser()->getSessionId(); 

Get session ID of the current frontend user

$sessionId = \nn\t3::FrontendUser()->getSessionId();
Copied!

| @return string

| ➜ Go to source code of FrontendUser::getSessionId()

\nn\t3::FrontendUser()->hasRole($roleUid); 

Checks whether the user has a specific role.

\nn\t3::FrontendUser()->hasRole( $roleUid );
Copied!
@param $role
@return bool

| ➜ Go to source code of FrontendUser::hasRole()

\nn\t3::FrontendUser()->isInUserGroup($feGroups = NULL); 

Checks whether the current frontend user is within a specific user group.

\nn\t3::FrontendUser()->isInUserGroup( 1 );
\nn\t3::FrontendUser()->isInUserGroup( ObjectStorage );
\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); 

Checks whether the user is currently logged in as a FE user. Earlier: isset($GLOBALS['TSFE']) && $GLOBALS['TSFE']->loginUser

// Check after complete initialization of the front/backend
\nn\t3::FrontendUser()->isLoggedIn();

// Check using the JWT, e.g. in an eID script before authentication
\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); 

Log in user manually. from v10: Alias to \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(); 

Log out the current FE-USer manually

\nn\t3::FrontendUser()->logout();
Copied!

| @return void

| ➜ Go to source code of FrontendUser::logout()

\nn\t3::FrontendUser()->removeCookie(); 

Manually delete the current fe_typo_user cookie

\nn\t3::FrontendUser()->removeCookie()
Copied!

| @return void

| ➜ Go to source code of FrontendUser::removeCookie()

\nn\t3::FrontendUser()->resolveUserGroups($arr = [], $ignoreUids = []); 

Converts an array or a comma-separated list with user group UIDs into | fe_user_groups data from the database. Checks for inherited subgroup.

\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); 

Set the fe_typo_user cookie manually.

If no sessionID is passed, Typo3 searches for the FE user's session ID itself.

When calling this method from a MiddleWare, the request should be passed with . This allows, for example, the global $_COOKIE value and the cookieParams.fe_typo_user in the request before authentication via typo3/cms-frontend/authentication in a separate MiddleWare must be set. Helpful if cross-domain authentication is required (e.g. via 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); 

Change the password of an FE user. Alias to \nn\t3::FrontendUserAuthentication()->setPassword().

\nn\t3::FrontendUser()->setPassword( 12, '123password$#' );
\nn\t3::FrontendUser()->setPassword( $frontendUserModel, '123Password#$' );
Copied!

| @return boolean

| ➜ Go to source code of FrontendUser::setPassword()

\nn\t3::FrontendUser()->setSessionData($key = NULL, $val = NULL, $merge = true); 

Set session data for FE user

// Merge session data for `shop` with new data (existing keys in `shop` are not deleted)
\nn\t3::FrontendUser()->setSessionData('store', ['a'=>1]);

// Overwrite session data for `shop` (`a` from the example above is deleted)
\nn\t3::FrontendUser()->setSessionData('store', ['b'=>1], false);
Copied!

| @return mixed

| ➜ Go to source code of FrontendUser::setSessionData()

Methods 

FrontendUser::get() 

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

Get the current FE user. Alias to \nn\t3::FrontendUser()->getCurrentUser();

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

Also exists as 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); 

Return all existing user groups. Returns an associative array, key is the uid, value is the title.

\nn\t3::FrontendUser()->getAvailableUserGroups();
Copied!

Alternatively, true can be used to return the complete data set for the user groups can be returned:

\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(); 

Gets the current 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(); 

Get the cookie name of the frontend user cookie. Usually fe_typo_user, unless it has been changed in the LocalConfiguration.

\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(); 

Get array with the data of the current FE user.

\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); 

Get user groups of the current FE user as an array. The uids of the user groups are used as keys in the returned array.

// Minimal version: By default, Typo3 only returns title, uid and pid
\nn\t3::FrontendUser()->getCurrentUserGroups(); // [1 => ['title'=>'Group A', 'uid' => 1, 'pid'=>5]]

// If true, the complete data record for the fe_user_group can be read from the DB
\nn\t3::FrontendUser()->getCurrentUserGroups( true ); // [1 => [... all fields of the 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(); 

Get UID of the current frontend user

$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); 

Get user groups of the current FE user. Alias to \nn\t3::FrontendUser()->getCurrentUserGroups();

// only load title, uid and pid of the groups
\nn\t3::FrontendUser()->getGroups();
// load complete data set of the groups
\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(); 

Get language UID of the current user

$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(); 

Get the current user session.

\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); 

Get session data for FE users

\nn\t3::FrontendUser()->getSessionData('store')
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(); 

Get session ID of the current frontend user

$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); 

Checks whether the user has a specific role.

\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); 

Checks whether the current frontend user is within a specific user group.

\nn\t3::FrontendUser()->isInUserGroup( 1 );
\nn\t3::FrontendUser()->isInUserGroup( ObjectStorage );
\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); 

Checks whether the user is currently logged in as a FE user. Earlier: isset($GLOBALS['TSFE']) && $GLOBALS['TSFE']->loginUser

// Check after complete initialization of the front/backend
\nn\t3::FrontendUser()->isLoggedIn();

// Check using the JWT, e.g. in an eID script before authentication
\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); 

Log in user manually. from v10: Alias to \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(); 

Log out the current FE-USer manually

\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(); 

Manually delete the current fe_typo_user cookie

\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 = []); 

Converts an array or a comma-separated list with user group UIDs into | fe_user_groups data from the database. Checks for inherited subgroup.

\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); 

Set the fe_typo_user cookie manually.

If no sessionID is passed, Typo3 searches for the FE user's session ID itself.

When calling this method from a MiddleWare, the request should be passed with . This allows, for example, the global $_COOKIE value and the cookieParams.fe_typo_user in the request before authentication via typo3/cms-frontend/authentication in a separate MiddleWare must be set. Helpful if cross-domain authentication is required (e.g. via 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); 

Change the password of an FE user. Alias to \nn\t3::FrontendUserAuthentication()->setPassword().

\nn\t3::FrontendUser()->setPassword( 12, '123password$#' );
\nn\t3::FrontendUser()->setPassword( $frontendUserModel, '123Password#$' );
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); 

Set session data for FE user

// Merge session data for `shop` with new data (existing keys in `shop` are not deleted)
\nn\t3::FrontendUser()->setSessionData('store', ['a'=>1]);

// Overwrite session data for `shop` (`a` from the example above is deleted)
\nn\t3::FrontendUser()->setSessionData('store', ['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() 

Front-end user methods: From logging in to changing passwords

Overview of Methods 

\nn\t3::FrontendUserAuthentication()->login($username = '', $password = '', $startFeUserSession = true); 

Login of an FE user using the user name and password

// Check credentials and start feUser session
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password' );

// Check only, do not establish a feUser session
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password', false );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::login()

\nn\t3::FrontendUserAuthentication()->loginBySessionId($sessionId = ''); 

Login of an FE user using a session ID.

The session ID corresponds to the TYPO3 cookie fe_typo_user. As a rule, there is one entry for one entry in the fe_sessions table for each FE user session. Up to Typo3 v10, the the ses_id column corresponded exactly to the cookie value.

As of Typo3 v10, the value is also hashed.

See also \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 of an FE user based on the user name

\nn\t3::FrontendUserAuthentication()->loginByUsername( '99grad' );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginByUsername()

\nn\t3::FrontendUserAuthentication()->loginField($value = NULL, $fieldName = 'uid'); 

Login of an FE user using any field. No password required.

\nn\t3::FrontendUserAuthentication()->loginField( $value, $fieldName );
Copied!

| @return array

| ➜ Go to source code of FrontendUserAuthentication::loginField()

\nn\t3::FrontendUserAuthentication()->loginUid($uid = NULL); 

Login of an FE user using an 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); 

Create a new frontend user session in the fe_sessions table. Either the fe_users.uid or the fe_users.username can be transferred.

The user is not automatically logged in. Instead, only a valid session is created and prepared in the database, which Typo3 can later use for authentication.

Returns the session ID.

The session ID corresponds exactly to the value in the fe_typo_user cookie- but not necessarily the value that is stored in fe_sessions.ses_id. The value in the database is hashed from TYPO3 v11 hashed.

$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 1 );
$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 'david' );

$hashInDatabase = \nn\t3::Encrypt()->hashSessionId( $sessionId );
Copied!

If the session is to be re-established with an existing SessionId, a (non-hashed) second parameter can be used as an optional, second parameter, a (non-hashed) SessionId can be passed:

\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); 

Change the password of an FE user.

\nn\t3::FrontendUserAuthentication()->setPassword( 12, '123Password#$' );
\nn\t3::FrontendUserAuthentication()->setPassword( $frontendUserModel, '123Password#$' );
Copied!

| @return boolean

| ➜ Go to source code of FrontendUserAuthentication::setPassword()

Methods 

FrontendUserAuthentication::login() 

\nn\t3::FrontendUserAuthentication()->login($username = '', $password = '', $startFeUserSession = true); 

Login of an FE user using the user name and password

// Check credentials and start feUser session
\nn\t3::FrontendUserAuthentication()->login( '99grad', 'password' );

// Check only, do not establish a feUser session
\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 of an FE user using a session ID.

The session ID corresponds to the TYPO3 cookie fe_typo_user. As a rule, there is one entry for one entry in the fe_sessions table for each FE user session. Up to Typo3 v10, the the ses_id column corresponded exactly to the cookie value.

As of Typo3 v10, the value is also hashed.

See also \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 of an FE user based on the user name

\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 of an FE user using any field. No password required.

\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 of an FE user using an 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); 

Create a new frontend user session in the fe_sessions table. Either the fe_users.uid or the fe_users.username can be transferred.

The user is not automatically logged in. Instead, only a valid session is created and prepared in the database, which Typo3 can later use for authentication.

Returns the session ID.

The session ID corresponds exactly to the value in the fe_typo_user cookie- but not necessarily the value that is stored in fe_sessions.ses_id. The value in the database is hashed from TYPO3 v11 hashed.

$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 1 );
$sessionId = \nn\t3::FrontendUserAuthentication()->prepareSession( 'david' );

$hashInDatabase = \nn\t3::Encrypt()->hashSessionId( $sessionId );
Copied!

If the session is to be re-established with an existing SessionId, a (non-hashed) second parameter can be used as an optional, second parameter, a (non-hashed) SessionId can be passed:

\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); 

Change the password of an FE user.

\nn\t3::FrontendUserAuthentication()->setPassword( 12, '123Password#$' );
\nn\t3::FrontendUserAuthentication()->setPassword( $frontendUserModel, '123Password#$' );
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() 

Calculating and converting geopositions and data.

To convert geo-coordinates into address data and vice versa, a Google Maps ApiKey must be created and stored in the Extension Manager for nnhelpers. Alternatively, you can a separate ApiKey can be specified during initialization:

nn\t3::Geo( $myApiKey )->getCoordinates('...');
Copied!

Overview of Methods 

\nn\t3::Geo()->autoComplete($params = []); 

Autocomplete search: Finds addresses (names) based on a search term

$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'); 

Convert geo-coordinates into address data (reverse geo coding) If the extension nnaddress is installed, it will be used for the resolution.

// Return the first result
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021 );

// Return ALL results
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true );

// return ALL results in English
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true, 'en' );

// $lng and $lat can also be passed as an array
\nn\t3::Geo()->getAddress( ['lat'=>50.08060702093021, 'lng'=>8.250693320181336] );

// Use your own API key?
\nn\t3::Geo( $apiKey )->getAddress( 8.250693320181336, 50.08060702093021 );
Copied!

Example for return:

[
    '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(); 

Get api key for methods in this class. The Api key can either be specified when initializing \nn\t3::Geo() or in the Extension Manager for 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'); 

Convert address data into geo-coordinates (geo coding) If the extension nnaddress is installed, it will be used for the resolution.

// Query via string, return first result
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );

// Query via array
\nn\t3::Geo()->getCoordinates( ['street'=>'Blumenstrasse 2', 'zip'=>'65189', 'city'=>'Wiesbaden', 'country'=>'DE'] );

// Return all results
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true );

// Return all results in English
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true, 'en' );

// Use your own api key
\nn\t3::Geo( $apiKey )->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );
Copied!

Example for return:

[
    '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 search: Finds POIs in the vicinity of a point See https://bit.ly/43CXxjX for possible type specifications.

$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 = []); 

Normalizes a result from the GeoCoding

@param array $row
@return array

| ➜ Go to source code of Geo::parseAddressCompontent()

\nn\t3::Geo()->toGps($coordinate, $hemisphere); 

Convert GPS coordinates into readable latitude/longitude coordinates

\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 search: Finds addresses (names) based on a search term

$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'); 

Convert geo-coordinates into address data (reverse geo coding) If the extension nnaddress is installed, it will be used for the resolution.

// Return the first result
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021 );

// Return ALL results
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true );

// return ALL results in English
\nn\t3::Geo()->getAddress( 8.250693320181336, 50.08060702093021, true, 'en' );

// $lng and $lat can also be passed as an array
\nn\t3::Geo()->getAddress( ['lat'=>50.08060702093021, 'lng'=>8.250693320181336] );

// Use your own API key?
\nn\t3::Geo( $apiKey )->getAddress( 8.250693320181336, 50.08060702093021 );
Copied!

Example for return:

[
    '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(); 

Get api key for methods in this class. The Api key can either be specified when initializing \nn\t3::Geo() or in the Extension Manager for 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'); 

Convert address data into geo-coordinates (geo coding) If the extension nnaddress is installed, it will be used for the resolution.

// Query via string, return first result
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );

// Query via array
\nn\t3::Geo()->getCoordinates( ['street'=>'Blumenstrasse 2', 'zip'=>'65189', 'city'=>'Wiesbaden', 'country'=>'DE'] );

// Return all results
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true );

// Return all results in English
\nn\t3::Geo()->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden', true, 'en' );

// Use your own api key
\nn\t3::Geo( $apiKey )->getCoordinates( 'Blumenstrasse 2, 65189 Wiesbaden' );
Copied!

Example for return:

[
    '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 search: Finds POIs in the vicinity of a point See https://bit.ly/43CXxjX for possible type specifications.

$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 = []); 

Normalizes a result from the 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); 

Convert GPS coordinates into readable latitude/longitude coordinates

\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() 

Make simple redirects, build URLs

Overview of Methods 

\nn\t3::Http()->buildUri($pageUid, $vars = [], $absolute = false); 

Build URI, works in frontend and backend context. Takes realURL into account

\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); 

Determine redirect destination

\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 = ''); 

Redirect to a page

\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); 

Build URI, works in frontend and backend context. Takes realURL into account

\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); 

Determine redirect destination

\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 = ''); 

Redirect to a page

\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 for methods around the localization of Typo3

Overview of Methods 

\nn\t3::LL()->get($id = '', $extensionName = '', $args = [], $explode = '', $langKey = NULL, $altLangKey = NULL); 

Get localization for a specific key.

Uses the translations that are specified in the xlf of an extension. These files are located by default under EXT:extname/Resources/Private/Language/locallang.xlf or EXT:extname/Resources/Private/Language/en.locallang.xlf for the respective translation.

// Simple example:
\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');

// Replace arguments in the string: 'After the %s comes the %s' or `Before the %2$s comes the %1$s'
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', ['one', 'two']);

// explode() the result at a separator character
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, ',');

// Translate to a language other than the current frontend language
\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); 

Translates a text via DeepL. An API key must be entered in the Extension Manager. DeepL allows the translation of up to 500,000 characters / month free of charge.

\nn\t3::LL()->translate( 'The horse does not eat cucumber salad' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 1 );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN', 'DE' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 1, 0 );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN', 'DE', $apiKey );
Copied!
@param string $srcText Text to be translated
@param string|int $targetLanguageKey Target language (e.g. 'EN' or '1')
@param string|int $sourceLanguageKey Source language (e.g. 'DE' or '0')
@param string $apiKey DeepL Api key (if not defined in the ExtensionManager)
@return string

| ➜ Go to source code of LL::translate()

Methods 

LL::get() 

\nn\t3::LL()->get($id = '', $extensionName = '', $args = [], $explode = '', $langKey = NULL, $altLangKey = NULL); 

Get localization for a specific key.

Uses the translations that are specified in the xlf of an extension. These files are located by default under EXT:extname/Resources/Private/Language/locallang.xlf or EXT:extname/Resources/Private/Language/en.locallang.xlf for the respective translation.

// Simple example:
\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');

// Replace arguments in the string: 'After the %s comes the %s' or `Before the %2$s comes the %1$s'
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', ['one', 'two']);

// explode() the result at a separator character
\nn\t3::LL()->get('tx_nnaddress_domain_model_entry', 'nnaddress', null, ',');

// Translate to a language other than the current frontend language
\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); 

Translates a text via DeepL. An API key must be entered in the Extension Manager. DeepL allows the translation of up to 500,000 characters / month free of charge.

\nn\t3::LL()->translate( 'The horse does not eat cucumber salad' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 1 );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN', 'DE' );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 1, 0 );
\nn\t3::LL()->translate( 'The horse does not eat cucumber salad', 'EN', 'DE', $apiKey );
Copied!
@param string $srcText Text to be translated
@param string|int $targetLanguageKey Target language (e.g. 'EN' or '1')
@param string|int $sourceLanguageKey Source language (e.g. 'DE' or '0')
@param string $apiKey DeepL Api key (if not defined in the ExtensionManager)
@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 to the sys_log table

Overview of Methods 

\nn\t3::Log()->error($extName = '', $message = '', $data = []); 

Write a warning in the sys_log table. Abbreviation for nnt3::Log()->log(..., 'error');

\nn\t3::Log()->error( 'extname', 'text', ['die'=>'data'] );
Copied!

return void

| ➜ Go to source code of Log::error()

\nn\t3::Log()->info($extName = '', $message = '', $data = []); 

Write an info to the sys_log table. Abbreviation for nnt3::Log()->log(..., 'info');

\nn\t3::Log()->error( 'extname', 'text', ['die'=>'data'] );
Copied!

return void

| ➜ Go to source code of Log::info()

\nn\t3::Log()->log($extName = 'nnhelpers', $message = NULL, $data = [], $severity = 'info'); 

Writes an entry to the sys_log table. The severity level can be specified, e.g. info, warning or 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 = []); 

Write a warning in the sys_log table. Abbreviation for nnt3::Log()->log(..., 'error');

\nn\t3::Log()->error( 'extname', 'text', ['die'=>'data'] );
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 = []); 

Write an info to the sys_log table. Abbreviation for nnt3::Log()->log(..., 'info');

\nn\t3::Log()->error( 'extname', 'text', ['die'=>'data'] );
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'); 

Writes an entry to the sys_log table. The severity level can be specified, e.g. info, warning or 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() 

Little helper for sending emails

Overview of Methods 

\nn\t3::Mail()->send($paramOverrides = []); 

Send an e-mail.

$html = \nn\t3::Template()->render('MailTemplate', ['varKey'=>'varValue'], 'tx_extname_plugin');

\nn\t3::Mail()->send([
    'html' => $html,
    'plaintext' => Optional: text version
    'fromEmail' => Sender email
    'fromName' => Sender name
    'toEmail' => Recipient email(s)
    'ccToEmail' => CC recipient email(s)
    'bccToEmail' => BCC recipient email(s)
    'replyToEmail' => Reply to recipient's email
    'replyToName' => Reply to name
    'subject' => Subject
    'attachments' => [...],
    'emogrify' => Convert CSS styles to inline styles (default: `true`)
    'absPrefix' => Convert relative paths to absolute paths (default: `true`)
    'headers' => ['List-Unsubscribe' => ', <https://www.unsubscribe.com>'],
]);
Copied!

Embed images with ``` File attachments with ``` | @return void

| ➜ Go to source code of Mail::send()

Methods 

Mail::send() 

\nn\t3::Mail()->send($paramOverrides = []); 

Send an e-mail.

$html = \nn\t3::Template()->render('MailTemplate', ['varKey'=>'varValue'], 'tx_extname_plugin');

\nn\t3::Mail()->send([
    'html' => $html,
    'plaintext' => Optional: text version
    'fromEmail' => Sender email
    'fromName' => Sender name
    'toEmail' => Recipient email(s)
    'ccToEmail' => CC recipient email(s)
    'bccToEmail' => BCC recipient email(s)
    'replyToEmail' => Reply to recipient's email
    'replyToName' => Reply to name
    'subject' => Subject
    'attachments' => [...],
    'emogrify' => Convert CSS styles to inline styles (default: `true`)
    'absPrefix' => Convert relative paths to absolute paths (default: `true`)
    'headers' => ['List-Unsubscribe' => ', <https://www.unsubscribe.com>'],
]);
Copied!

Embed images with ``` File attachments with ``` | @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() 

Simplifies the use of FlashMessages.

In the backend: FlashMessages are automatically displayed at the top

\nn\t3::Message()->OK('Title', 'Infotext');
\nn\t3::Message()->ERROR('Title', 'Infotext');
Copied!

In the frontend: FlashMessages can be output via ViewHelper

\nn\t3::Message()->OK('Title', 'Infotext');



\nn\t3::Message()->setId('top')->OK('Title', 'Infotext');
Copied!

... or rendered as HTML and returned:

echo \nn\t3::Message()->render('above');
echo \nn\t3::Message()->render();
Copied!

Overview of Methods 

\nn\t3::Message()->ERROR($title = '', $text = ''); 

Outputs an "ERROR" flash message

\nn\t3::Message()->ERROR('Title', 'Infotext');
Copied!

| @return void

| ➜ Go to source code of Message::ERROR()

\nn\t3::Message()->OK($title = '', $text = ''); 

Outputs an "OK" flash message

\nn\t3::Message()->OK('Title', 'Info text');
Copied!

| @return void

| ➜ Go to source code of Message::OK()

\nn\t3::Message()->WARNING($title = '', $text = ''); 

Outputs a "WARNING" flash message

\nn\t3::Message()->WARNING('Title', 'Info text');
Copied!

| @return void

| ➜ Go to source code of Message::WARNING()

\nn\t3::Message()->flash($title = '', $text = '', $type = 'OK', $queueID = NULL); 

Saves a flash message in the message queue for frontend or backend. | @return void

| ➜ Go to source code of Message::flash()

\nn\t3::Message()->flush($queueID = NULL); 

Deletes all flash messages Optionally, a queue ID can be specified.

\nn\t3::Message()->flush('above');
\nn\t3::Message()->flush();
Copied!

| @return array

| ➜ Go to source code of Message::flush()

\nn\t3::Message()->render($queueID = NULL); 

Renders the Flash messages in the queue Simple example:

\nn\t3::Message()->OK('Yes', 'No');
echo \nn\t3::Message()->render();
Copied!

Example with a queue ID:

\nn\t3::Message()->setId('above')->OK('Yes', 'No');
echo \nn\t3::Message()->render('above');
Copied!

Output in the fluid via the ViewHelper:

{nnt3:flashMessages()}
Copied!

| @return string

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

\nn\t3::Message()->setId($name = NULL); 

Determines which MessageQueue is to be used

\nn\t3::Message()->setId('top')->OK('Title', 'Infotext');
Copied!

Output in Fluid via ViewHelper:

{nnt3:flashMessages(id:'above')}
Copied!

| @return void

| ➜ Go to source code of Message::setId()

Methods 

Message::ERROR() 

\nn\t3::Message()->ERROR($title = '', $text = ''); 

Outputs an "ERROR" flash message

\nn\t3::Message()->ERROR('Title', '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); 

Saves a flash message in the message queue for frontend or 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); 

Deletes all flash messages Optionally, a queue ID can be specified.

\nn\t3::Message()->flush('above');
\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 = ''); 

Outputs an "OK" flash message

\nn\t3::Message()->OK('Title', 'Info text');
Copied!

| @return void

Source Code 

public function OK( $title = '', $text = '' ) {
	$this->flash( $title, $text );
}
Copied!

Message::render() 

\nn\t3::Message()->render($queueID = NULL); 

Renders the Flash messages in the queue Simple example:

\nn\t3::Message()->OK('Yes', 'No');
echo \nn\t3::Message()->render();
Copied!

Example with a queue ID:

\nn\t3::Message()->setId('above')->OK('Yes', 'No');
echo \nn\t3::Message()->render('above');
Copied!

Output in the fluid via the ViewHelper:

{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); 

Determines which MessageQueue is to be used

\nn\t3::Message()->setId('top')->OK('Title', 'Infotext');
Copied!

Output in Fluid via ViewHelper:

{nnt3:flashMessages(id:'above')}
Copied!

| @return void

Source Code 

public function setId( $name = null ) {
	$this->queueId = $name;
	return $this;
}
Copied!

Message::WARNING() 

\nn\t3::Message()->WARNING($title = '', $text = ''); 

Outputs a "WARNING" flash message

\nn\t3::Message()->WARNING('Title', 'Info text');
Copied!

| @return void

Source Code 

public function WARNING( $title = '', $text = '' ) {
	$this->flash( $title, $text, 'WARNING' );
}
Copied!

Obj 

\nn\t3::Obj() 

Everything you need for objects and models.

Overview of Methods 

\nn\t3::Obj()->accessSingleProperty($obj, $key); 

Access to a key in an object or array key must be a single string, not a path

nnt3::Obj()->accessSingleProperty( $obj, 'uid' ); nnt3::Obj()->accessSingleProperty( $obj, 'fal_media' ); nnt3::Obj()->accessSingleProperty( $obj, 'falMedia' );

@param mixed $obj Model or array
@param string $key the key that is to be fetched

| @return mixed

| ➜ Go to source code of Obj::accessSingleProperty()

\nn\t3::Obj()->diff($objA, $objB, $fieldsToIgnore = [], $fieldsToCompare = [], $options = [], $path = '', $diff = []); 

Compares two objects, returns array with differences. If a property of objA does not exist in objB, it is ignored.

// Returns array with differences
\nn\t3::Obj()->diff( $objA, $objB );

// ignores the fields uid and title
\nn\t3::Obj()->diff( $objA, $objB, ['uid', 'title'] );

// Compares ONLY the fields title and bodytext
\nn\t3::Obj()->diff( $objA, $objB, [], ['title', 'bodytext'] );

// Options
\nn\t3::Obj()->diff( $objA, $objB, [], [], ['ignoreWhitespaces'=>true, 'ignoreTags'=>true, 'ignoreEncoding'=>true] );
Copied!
@param mixed $objA An object, array or model
@param mixed $objB The object or model to be compared
@param array $fieldsToIgnore List of properties that can be ignored. Empty = none
@param array $fieldsToCompare List of properties to be compared. Empty = all
@param boolean $options Options / tolerances when comparing
includeMissing => also add missing properties in $objB
ignoreWhitespaces => ignore spaces
ignoreEncoding => ignore UTF8 / ISO encoding
ignoreTags => ignore HTML tags
depth => depth to be compared

| @return array

| ➜ Go to source code of Obj::diff()

\nn\t3::Obj()->forceArray($obj); 

Converts to array

| @param mixed $obj

| @return array

| ➜ Go to source code of Obj::forceArray()

\nn\t3::Obj()->get($obj, $key = ''); 

Access to a value in the object using the key Alias to \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 or array
@param string $key the key / property

| @return mixed

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

\nn\t3::Obj()->getClassSchema($modelClassName = NULL); 

Get information about the classSchema of a model

\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); 

Access to ALL keys that are to be fetched in an object

\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 or class name
@return array

| ➜ Go to source code of Obj::getKeys()

\nn\t3::Obj()->getMethodArguments($className = NULL, $methodName = NULL); 

Get information about the arguments of a method. | Also takes into account the``type hinting``specified by@paramain``, e.g. forObjectStorage``.

\nn\t3::Obj()->getMethodArguments( \My\Model\Name::class, 'myMethodName' );
\nn\t3::Obj()->getMethodArguments( $myClassInstance, 'myMethodName' );
Copied!

Returns as an example:

'varName' => [
    'type' => 'Storage',
    '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); 

Return the list of properties of an object or model with type.

\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 or class name
@param mixed $key If TRUE, array with all information is retrieved, e.g. also default value etc.
@param boolean $onlySettable Only get properties that can also be set via setName()
@return array

| ➜ Go to source code of Obj::getProps()

\nn\t3::Obj()->getSetableKeys($obj); 

Get all keys of an object that have a SETTER. In contrast to \nn\t3::Obj()->getKeys(), only the property keys are are returned that can also be set, e.g. via setNameDerProp()

| @return array

| ➜ Go to source code of Obj::getSetableKeys()

\nn\t3::Obj()->getTableName($modelClassName = NULL); 

Returns the DB table name for a model

$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); 

Checks whether the object is a \TYPO3\CMS\Core\Resource\FileReference.

\nn\t3::Obj()->isFalFile( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFalFile()

\nn\t3::Obj()->isFile($obj); 

Checks whether the object is a \TYPO3\CMS\Core\Resource\File.

\nn\t3::Obj()->isFile( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFile()

\nn\t3::Obj()->isFileReference($obj); 

Checks whether the object is a \TYPO3\CMS\Extbase\Domain\Model\FileReference.

\nn\t3::Obj()->isFileReference( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isFileReference()

\nn\t3::Obj()->isModel($obj); 

Checks whether the object is a domain model.

\nn\t3::Obj()->isModel( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isModel()

\nn\t3::Obj()->isSimpleType($type = ''); 

Checks whether a type (string) is a "simple" type. Simple types are all types apart from models, classes etc. - e.g. 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); 

Checks whether the object is a storage.

\nn\t3::Obj()->isStorage( $obj );
Copied!

| @return boolean

| ➜ Go to source code of Obj::isStorage()

\nn\t3::Obj()->isSysCategory($obj); 

Checks whether the object is a SysCategory. Takes into account all models that are stored in sys_category.

\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 an array into an object

\nn\t3::Obj( \My\Doman\Model )->merge(['title'=>'New title']);
Copied!

This can even be used to write / overwrite FileReferences. In this example, $data is merged with an existing model. | falMedia is an ObjectStorage in the example. The first element in falMedia already exists already exists in the database(uid = 12). Only the title is updated here. The second element in the array (without uid) is new. For this, a new | sys_file_reference is automatically created in the database.

$data = [
    'uid' => 10,
    'title' => 'The title',
    'falMedia' => [
        ['uid'=>12, 'title'=>'1st image title'],
        ['title'=>'NEW image title', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
    ]
];
$oldModel = $repository->findByUid( $data['uid'] );
$mergedModel = \nn\t3::Obj($oldModel)->merge($data);
Copied!

Hint To create a new model with data from an array, there is the method there is the method $newModel = \nn\t3::Convert($data)->toModel( \My\Model\Name::class );

| @return object

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

\nn\t3::Obj()->parseType($paramType = ''); 

Parse a string with information about ObjectStorage.

\nn\t3::Obj()->parseType( 'string' );
\nn\t3::Obj()->parseType( 'Nng\Nnrestapi\Domain\Model\ApiTest' );
\nn\t3::Obj()->parseType( '\TYPO3\CMS\Extbase\Persistence\ObjectStorage' );
Copied!

Git an array with information back: | type is only set if it is an array or an ObjectStorage. | elementType is always the type of the model or the TypeHinting of the 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); 

Access to a key in an object or array. The key can also be a path, e.g. "img.0.uid"

nnt3::Obj()->prop( $obj, 'img.0.uid' );

@param mixed $obj Model or array
@param string $key the key that is to be fetched

| @return mixed

| ➜ Go to source code of Obj::prop()

\nn\t3::Obj()->props($obj, $keys = []); 

Get individual properties of an object or array

\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); 

Sets a value in an object or array.

\nn\t3::Obj()->set( $obj, 'title', $val );
Copied!
@param mixed $obj Model or array
@param string $key the key / property
@param mixed $val the value to be set
@param boolean $useSetter setKey() method to use for setting

| @return mixed

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

\nn\t3::Obj()->toArray($obj, $depth = 3, $fields = [], $addClass = false); 

Converts an object into an array For memory problems due to recursion: Specify max depth!

\nn\t3::Obj()->toArray($obj, 2, ['uid', 'title']);
\nn\t3::Obj()->toArray($obj, 1, ['uid', 'title', 'parent.uid']);
Copied!
@param mixed $obj ObjectStorage, model or array that is to be converted
@param integer $depth Depth to be converted. Always use for recursive conversion
@param array $fields only return these fields from the object / array
@param boolean $addClass Supplement '__class' with information about the class?

| @return array

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

Methods 

Obj::accessSingleProperty() 

\nn\t3::Obj()->accessSingleProperty($obj, $key); 

Access to a key in an object or array key must be a single string, not a path

nnt3::Obj()->accessSingleProperty( $obj, 'uid' ); nnt3::Obj()->accessSingleProperty( $obj, 'fal_media' ); nnt3::Obj()->accessSingleProperty( $obj, 'falMedia' );

@param mixed $obj Model or array
@param string $key the key that is to be fetched

| @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 = []); 

Compares two objects, returns array with differences. If a property of objA does not exist in objB, it is ignored.

// Returns array with differences
\nn\t3::Obj()->diff( $objA, $objB );

// ignores the fields uid and title
\nn\t3::Obj()->diff( $objA, $objB, ['uid', 'title'] );

// Compares ONLY the fields title and bodytext
\nn\t3::Obj()->diff( $objA, $objB, [], ['title', 'bodytext'] );

// Options
\nn\t3::Obj()->diff( $objA, $objB, [], [], ['ignoreWhitespaces'=>true, 'ignoreTags'=>true, 'ignoreEncoding'=>true] );
Copied!
@param mixed $objA An object, array or model
@param mixed $objB The object or model to be compared
@param array $fieldsToIgnore List of properties that can be ignored. Empty = none
@param array $fieldsToCompare List of properties to be compared. Empty = all
@param boolean $options Options / tolerances when comparing
includeMissing => also add missing properties in $objB
ignoreWhitespaces => ignore spaces
ignoreEncoding => ignore UTF8 / ISO encoding
ignoreTags => ignore HTML tags
depth => depth to be compared

| @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); 

Converts to 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 = ''); 

Access to a value in the object using the key Alias to \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 or array
@param string $key the 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); 

Get information about the classSchema of a model

\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); 

Access to ALL keys that are to be fetched in an object

\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 or class 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); 

Get information about the arguments of a method. | Also takes into account the``type hinting``specified by@paramain``, e.g. forObjectStorage``.

\nn\t3::Obj()->getMethodArguments( \My\Model\Name::class, 'myMethodName' );
\nn\t3::Obj()->getMethodArguments( $myClassInstance, 'myMethodName' );
Copied!

Returns as an example:

'varName' => [
    'type' => 'Storage',
    '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); 

Return the list of properties of an object or model with type.

\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 or class name
@param mixed $key If TRUE, array with all information is retrieved, e.g. also default value etc.
@param boolean $onlySettable Only get properties that can also be set via setName()
@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); 

Get all keys of an object that have a SETTER. In contrast to \nn\t3::Obj()->getKeys(), only the property keys are are returned that can also be set, e.g. via 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); 

Returns the DB table name for a model

$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); 

Checks whether the object is a \TYPO3\CMS\Core\Resource\FileReference.

\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); 

Checks whether the object is a \TYPO3\CMS\Core\Resource\File.

\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); 

Checks whether the object is a \TYPO3\CMS\Extbase\Domain\Model\FileReference.

\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); 

Checks whether the object is a domain model.

\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 = ''); 

Checks whether a type (string) is a "simple" type. Simple types are all types apart from models, classes etc. - e.g. 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); 

Checks whether the object is a storage.

\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); 

Checks whether the object is a SysCategory. Takes into account all models that are stored in sys_category.

\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 an array into an object

\nn\t3::Obj( \My\Doman\Model )->merge(['title'=>'New title']);
Copied!

This can even be used to write / overwrite FileReferences. In this example, $data is merged with an existing model. | falMedia is an ObjectStorage in the example. The first element in falMedia already exists already exists in the database(uid = 12). Only the title is updated here. The second element in the array (without uid) is new. For this, a new | sys_file_reference is automatically created in the database.

$data = [
    'uid' => 10,
    'title' => 'The title',
    'falMedia' => [
        ['uid'=>12, 'title'=>'1st image title'],
        ['title'=>'NEW image title', 'publicUrl'=>'fileadmin/_tests/5e505e6b6143a.jpg'],
    ]
];
$oldModel = $repository->findByUid( $data['uid'] );
$mergedModel = \nn\t3::Obj($oldModel)->merge($data);
Copied!

Hint To create a new model with data from an array, there is the method there is the method $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 = ''); 

Parse a string with information about ObjectStorage.

\nn\t3::Obj()->parseType( 'string' );
\nn\t3::Obj()->parseType( 'Nng\Nnrestapi\Domain\Model\ApiTest' );
\nn\t3::Obj()->parseType( '\TYPO3\CMS\Extbase\Persistence\ObjectStorage' );
Copied!

Git an array with information back: | type is only set if it is an array or an ObjectStorage. | elementType is always the type of the model or the TypeHinting of the 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); 

Access to a key in an object or array. The key can also be a path, e.g. "img.0.uid"

nnt3::Obj()->prop( $obj, 'img.0.uid' );

@param mixed $obj Model or array
@param string $key the key that is to be fetched

| @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 = []); 

Get individual properties of an object or array

\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); 

Sets a value in an object or array.

\nn\t3::Obj()->set( $obj, 'title', $val );
Copied!
@param mixed $obj Model or array
@param string $key the key / property
@param mixed $val the value to be set
@param boolean $useSetter setKey() method to use for setting

| @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); 

Converts an object into an array For memory problems due to recursion: Specify max depth!

\nn\t3::Obj()->toArray($obj, 2, ['uid', 'title']);
\nn\t3::Obj()->toArray($obj, 1, ['uid', 'title', 'parent.uid']);
Copied!
@param mixed $obj ObjectStorage, model or array that is to be converted
@param integer $depth Depth to be converted. Always use for recursive conversion
@param array $fields only return these fields from the object / array
@param boolean $addClass Supplement '__class' with information about the class?

| @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() 

Everything about the pages table.

Overview of Methods 

\nn\t3::Page()->addCssFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

CSS file in ```` inject See \nn\t3::Page()->addHeader() for simpler 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 ```` inject

\nn\t3::Page()->addCssLibrary( 'path/to/style.css' );
Copied!

| @return void

| ➜ Go to source code of Page::addCssLibrary()

\nn\t3::Page()->addFooter($str = ''); 

Append CSS or JS or HTML code to the footer. Decide for yourself which PageRender method to use.

\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 before the end of the `` inject See nnt3::Page()->addFooter() for simpler version.

\nn\t3::Page()->addFooterData( '' );
Copied!

@return void``

| ➜ Go to source code of Page::addFooterData()

\nn\t3::Page()->addHeader($str = ''); 

Append CSS or JS or HTML code to the footer. Decide for yourself which PageRender method to use.

\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('....');
Copied!

| @return void

| ➜ Go to source code of Page::addHeader()

\nn\t3::Page()->addHeaderData($html = ''); 

HTML code in ```` inject See \nn\t3::Page()->addHeader() for simpler version.

\nn\t3::Page()->addHeaderData( '' );
Copied!

| @return void

| ➜ Go to source code of Page::addHeaderData()

\nn\t3::Page()->addJsFile($path, $compress = false, $atTop = false, $wrap = false, $concat = false); 

JS file in ```` inject See \nn\t3::Page()->addHeader() for simpler 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 file at the end of the `` inject See nnt3::Page()->addJsFooterFile() for simpler 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 at the end of the `` inject

\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 ```` inject.

\nn\t3::Page()->addJsLibrary( 'path/to/file.js' );
Copied!

| @return void

| ➜ Go to source code of Page::addJsLibrary()

\nn\t3::Page()->clearCache($pid = NULL); 

Delete the page cache of one (or more) pages

\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); 

Get data of a page (from table "pages")

\nn\t3::Page()->get( $uid );
Copied!

| @return array

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

\nn\t3::Page()->getChildPids($parentPid = 0, $recursive = 999); 

Get list of child ids of one or more pages.

\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); 

Get data of a page (table pages).

// data of the current page
\nn\t3::Page()->getData();

// get data of the page with pid = 123
\nn\t3::Page()->getData( 123 );

// get data of the pages with pids = 123 and 456. Key of the array = 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 = ''); 

Get single field from page data. The value can be inherited from parent pages via slide = true.

(!) Important: Custom fields must be defined as rootLine in ext_localconf.php! See also \nn\t3::Registry()->rootLineFields(['key', '...']);

\nn\t3::Page()->getField('layout');
\nn\t3::Page()->getField('backend_layout_next_level', true, 'backend_layout');
Copied!

Also exists as 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(); 

Get page renderer

\nn\t3::Page()->getPageRenderer();
Copied!

| @return PageRenderer

| ➜ Go to source code of Page::getPageRenderer()

\nn\t3::Page()->getPid($fallback = NULL); 

Get PID of the current page. In the frontend: The current TSFE->id In the backend: The page that was selected in the page tree Without context: The pid of the 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(); 

Get PID from request string, e.g. in backend modules. Hacky. ToDo: Check if there is a better method.

\nn\t3::Page()->getPidFromRequest();
Copied!

| @return int

| ➜ Go to source code of Page::getPidFromRequest()

\nn\t3::Page()->getRootline($pid = NULL); 

Get rootline for given PID

\nn\t3::Page()->getRootline();
Copied!

| @return array

| ➜ Go to source code of Page::getRootline()

\nn\t3::Page()->getSiteRoot($returnAll = false); 

Get PID of the site root(s). Corresponds to the page in the backend that has the "globe" as an icon (in the page properties "use as start of website")

\nn\t3::Page()->getSiteRoot();
Copied!

| @return int

| ➜ Go to source code of Page::getSiteRoot()

\nn\t3::Page()->getSubpages($pid = NULL, $includeHidden = false, $includeAllTypes = false); 

Get menu for given PID

\nn\t3::Page()->getSubpages();
\nn\t3::Page()->getSubpages( $pid );
\nn\t3::Page()->getSubpages( $pid, true ); // Also fetch hidden pages
\nn\t3::Page()->getSubpages( $pid, false, true ); // Get all page types
\nn\t3::Page()->getSubpages( $pid, false, [PageRepository::DOKTYPE_SYSFOLDER] ); // Get specific page types
Copied!
@param int $pid
@param bool $includeHidden
@param bool|array $includeAllTypes
@return array

| ➜ Go to source code of Page::getSubpages()

\nn\t3::Page()->getTitle(); 

Get current page title (without suffix)

\nn\t3::Page()->getTitle();
Copied!

| @return string

| ➜ Go to source code of Page::getTitle()

\nn\t3::Page()->hasSubpages($pid = NULL); 

Checks whether a page has submenus

\nn\t3::Page()->hasSubpages();
Copied!

| @return boolean

| ➜ Go to source code of Page::hasSubpages()

\nn\t3::Page()->setTitle($title = ''); 

Change PageTitle ( -tag) Does not work if EXT:advancedtitle is activated!

\nn\t3::Page()->setTitle('YEAH!');
Copied!

Also available as ViewHelper:

{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 file in ```` inject See \nn\t3::Page()->addHeader() for simpler 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 ```` inject

\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 = ''); 

Append CSS or JS or HTML code to the footer. Decide for yourself which PageRender method to use.

\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 before the end of the `` inject See nnt3::Page()->addFooter() for simpler version.

\nn\t3::Page()->addFooterData( '' );
Copied!

@return void``

Source Code 

public function addFooterData( $html = '' ) {
	$this->getPageRenderer()->addFooterData( $html );
}
Copied!

Page::addHeader() 

\nn\t3::Page()->addHeader($str = ''); 

Append CSS or JS or HTML code to the footer. Decide for yourself which PageRender method to use.

\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('....');
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 ```` inject See \nn\t3::Page()->addHeader() for simpler version.

\nn\t3::Page()->addHeaderData( '' );
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 file in ```` inject See \nn\t3::Page()->addHeader() for simpler 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 file at the end of the `` inject See nnt3::Page()->addJsFooterFile() for simpler 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 at the end of the `` inject

\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 ```` inject.

\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); 

Delete the page cache of one (or more) pages

\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); 

Get data of a page (from table "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); 

Get list of child ids of one or more pages.

\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); 

Get data of a page (table pages).

// data of the current page
\nn\t3::Page()->getData();

// get data of the page with pid = 123
\nn\t3::Page()->getData( 123 );

// get data of the pages with pids = 123 and 456. Key of the array = 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 = ''); 

Get single field from page data. The value can be inherited from parent pages via slide = true.

(!) Important: Custom fields must be defined as rootLine in ext_localconf.php! See also \nn\t3::Registry()->rootLineFields(['key', '...']);

\nn\t3::Page()->getField('layout');
\nn\t3::Page()->getField('backend_layout_next_level', true, 'backend_layout');
Copied!

Also exists as 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(); 

Get page renderer

\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); 

Get PID of the current page. In the frontend: The current TSFE->id In the backend: The page that was selected in the page tree Without context: The pid of the 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(); 

Get PID from request string, e.g. in backend modules. Hacky. ToDo: Check if there is a better method.

\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); 

Get rootline for given PID

\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); 

Get PID of the site root(s). Corresponds to the page in the backend that has the "globe" as an icon (in the page properties "use as start of website")

\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); 

Get menu for given PID

\nn\t3::Page()->getSubpages();
\nn\t3::Page()->getSubpages( $pid );
\nn\t3::Page()->getSubpages( $pid, true ); // Also fetch hidden pages
\nn\t3::Page()->getSubpages( $pid, false, true ); // Get all page types
\nn\t3::Page()->getSubpages( $pid, false, [PageRepository::DOKTYPE_SYSFOLDER] ); // Get specific page types
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(); 

Get current page title (without suffix)

\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); 

Checks whether a page has submenus

\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 = ''); 

Change PageTitle ( -tag) Does not work if EXT:advancedtitle is activated!

\nn\t3::Page()->setTitle('YEAH!');
Copied!

Also available as ViewHelper:

{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() 

Helpful methods for registering extension components such as plugins, backend modules, FlexForms etc.

Overview of Methods 

\nn\t3::Registry()->addPageConfig($str = ''); 

Add page config

\nn\t3::Registry()->addPageConfig( 'test.was = 10' );
\nn\t3::Registry()->addPageConfig( '' );
\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 = ''); 

Inserts a hook that is executed when you click on "Clear cache". The following script is added to the ext_localconf.php of your 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 = []); 

Configure a plugin. Use in ext_localconf.php.

\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 = ''); 

Register a flexform for a plugin.

\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 = []); 

Register global namespace for Fluid. Mostly used in ext_localconf.php.

\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 = ''); 

Get a value from the sys_registry table.

\nn\t3::Registry()->get( 'nnsite', 'lastRun' );
Copied!

| @return void

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

\nn\t3::Registry()->getVendorExtensionName($combinedVendorPluginName = ''); 

Generate plugin name. Depending on the Typo3 version, the plugin name is returned with or without the vendor.

\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 = ''); 

Register an icon. Classically used in ext_tables.php.

\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 = []); 

Parse list with 'ControllerName' => 'action,list,show' Always specify the full class path in the ::class notation. Take into account that before Typo3 10 only the simple class name (e.g. Main) is used as the key.

\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); 

Register a plugin for selection via the dropdown CType in the backend. Use in Configuration/TCA/Overrides/tt_content.php â or ext_tables.php (deprecated).

\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 = []); 

Simplifies the registration of a list of plugins, which are combined into a group in the list_type dropdown. group in the list_type dropdown.

Use in Configuration/TCA/Overrides/tt_content.php:

\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); 

Register a field in the pages table that is to be inherited / slid to subpages. Register in ext_localconf.php:

\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, footer element, slide
    }
}
Copied!

| @return void

| ➜ Go to source code of Registry::rootLineFields()

\nn\t3::Registry()->set($extName = '', $path = '', $settings = [], $clear = false); 

Save a value in the sys_registry table. Data in this table is retained beyond the session. For example, a scheduler job can save when it was last executed. was executed.

Arrays are recursively merged / merged by default:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['one'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['two'=>'2'] );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['one'=>1, 'two'=>2]
Copied!

With true at the end, the previous values are deleted:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['one'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['two'=>'2'], true );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['two'=>2]
Copied!

| @return array

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

Methods 

Registry::addPageConfig() 

\nn\t3::Registry()->addPageConfig($str = ''); 

Add page config

\nn\t3::Registry()->addPageConfig( 'test.was = 10' );
\nn\t3::Registry()->addPageConfig( '' );
\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 = ''); 

Inserts a hook that is executed when you click on "Clear cache". The following script is added to the ext_localconf.php of your 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 = []); 

Configure a plugin. Use in ext_localconf.php.

\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 = ''); 

Register a flexform for a plugin.

\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 = []); 

Register global namespace for Fluid. Mostly used in ext_localconf.php.

\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 = ''); 

Get a value from the sys_registry table.

\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 = ''); 

Generate plugin name. Depending on the Typo3 version, the plugin name is returned with or without the vendor.

\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 = ''); 

Register an icon. Classically used in ext_tables.php.

\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 = []); 

Parse list with 'ControllerName' => 'action,list,show' Always specify the full class path in the ::class notation. Take into account that before Typo3 10 only the simple class name (e.g. Main) is used as the key.

\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); 

Register a plugin for selection via the dropdown CType in the backend. Use in Configuration/TCA/Overrides/tt_content.php â or ext_tables.php (deprecated).

\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 = []); 

Simplifies the registration of a list of plugins, which are combined into a group in the list_type dropdown. group in the list_type dropdown.

Use in Configuration/TCA/Overrides/tt_content.php:

\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); 

Register a field in the pages table that is to be inherited / slid to subpages. Register in ext_localconf.php:

\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, footer element, 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); 

Save a value in the sys_registry table. Data in this table is retained beyond the session. For example, a scheduler job can save when it was last executed. was executed.

Arrays are recursively merged / merged by default:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['one'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['two'=>'2'] );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['one'=>1, 'two'=>2]
Copied!

With true at the end, the previous values are deleted:

\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['one'=>'1'] );
\nn\t3::Registry()->set( 'nnsite', 'lastRun', ['two'=>'2'], true );

\nn\t3::Registry()->get( 'nnsite', 'lastRun' ); // => ['two'=>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() 

Access to GET / POST variables, file containers etc.

Overview of Methods 

\nn\t3::Request()->DELETE($url = '', $queryParams = [], $headers = []); 

Sends a DELETE request (via curl) to a 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); 

Sends a GET request (via curl) to a server

\nn\t3::Request()->GET( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->GET( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );

// if 'a'=>[1,2,3] should be sent as a=1&a=2&a=3 instead of 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); 

Sends a GET request to a server and parses the result as 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 from $_GET and $_POST variables

\nn\t3::Request()->GP();
Copied!

| @return array

| ➜ Go to source code of Request::GP()

\nn\t3::Request()->JSON($url = '', $data = [], $headers = NULL); 

Sends a JSON to a server via POST

\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'); 

Sends a POST request (via CURL) to a 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 = []); 

Sends a PUT request (via curl) to a 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 = []); 

Sends a PUT request (via curl) to a server as 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); 

Get and normalize file uploads from $_FILES.

Normalizes the following file upload variants. Removes empty file uploads from the array.

	
	
	
	
Copied!
Examples:
GetALL file info from $_FILES.
\nn\t3::Request()->files();
\nn\t3::Request()->files( true ); // Force array
Copied!

Get file info from tx_nnfesubmit_nnfesubmit[...].

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit');
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit', true); // Force array
Copied!

Only get files from tx_nnfesubmit_nnfesubmit[fal_media].

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media' );
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media', true ); // Force array
Copied!

| @return array

| ➜ Go to source code of Request::files()

\nn\t3::Request()->getAuthorizationHeader(); 

Read the Authorization header from the request.

\nn\t3::Request()->getAuthorizationHeader();
Copied!

Important: If this does not work, the following line is probably missing in the .htaccess is probably missing the following line:

# nnhelpers: Use when PHP is executed in PHP CGI mode
RewriteRule . - E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
Copied!

| @return string

| ➜ Go to source code of Request::getAuthorizationHeader()

\nn\t3::Request()->getBasicAuth(); 

Read the Basic Authorization Header from the request. If available, the username and password are returned.

$credentials = \nn\t3::Request()->getBasicAuth(); // ['username'=>'...', 'password'=>'...']
Copied!

Example call from a test script:

echo file_get_contents('https://username:password@www.testsite.com');
Copied!

| @return array

| ➜ Go to source code of Request::getBasicAuth()

\nn\t3::Request()->getBearerToken(); 

Read the bearer header Is used, among other things, to transmit a JWT (Json Web Token).

\nn\t3::Request()->getBearerToken();
Copied!

| @return string|null

| ➜ Go to source code of Request::getBearerToken()

\nn\t3::Request()->getJwt(); 

Read the JWT (Json Web Token) from the request, validate it and, if the signature is successfully check the signature and return the payload of the JWT.

\nn\t3::Request()->getJwt();
Copied!

| @return array|string

| ➜ Go to source code of Request::getJwt()

\nn\t3::Request()->getUri($varName = NULL); 

Return the request URI. Basically the URL / the GET string in the browser URL bar, which is stored in $_SERVER['REQUEST_URI'] is saved.

\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 = []); 

Sends a DELETE request (via curl) to a 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); 

Get and normalize file uploads from $_FILES.

Normalizes the following file upload variants. Removes empty file uploads from the array.

	
	
	
	
Copied!
Examples:
GetALL file info from $_FILES.
\nn\t3::Request()->files();
\nn\t3::Request()->files( true ); // Force array
Copied!

Get file info from tx_nnfesubmit_nnfesubmit[...].

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit');
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit', true); // Force array
Copied!

Only get files from tx_nnfesubmit_nnfesubmit[fal_media].

\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media' );
\nn\t3::Request()->files('tx_nnfesubmit_nnfesubmit.fal_media', true ); // Force array
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); 

Sends a GET request (via curl) to a server

\nn\t3::Request()->GET( 'https://...', ['a'=>'123'] );
\nn\t3::Request()->GET( 'https://...', ['a'=>'123'], ['Accept-Encoding'=>'gzip, deflate'] );

// if 'a'=>[1,2,3] should be sent as a=1&a=2&a=3 instead of 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(); 

Read the Authorization header from the request.

\nn\t3::Request()->getAuthorizationHeader();
Copied!

Important: If this does not work, the following line is probably missing in the .htaccess is probably missing the following line:

# nnhelpers: Use when PHP is executed in PHP CGI mode
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(); 

Read the Basic Authorization Header from the request. If available, the username and password are returned.

$credentials = \nn\t3::Request()->getBasicAuth(); // ['username'=>'...', 'password'=>'...']
Copied!

Example call from a test script:

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(); 

Read the bearer header Is used, among other things, to transmit a JWT (Json Web Token).

\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(); 

Read the JWT (Json Web Token) from the request, validate it and, if the signature is successfully check the signature and return the payload of the JWT.

\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); 

Return the request URI. Basically the URL / the GET string in the browser URL bar, which is stored in $_SERVER['REQUEST_URI'] is saved.

\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); 

Sends a GET request to a server and parses the result as 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 from $_GET and $_POST variables

\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); 

Sends a JSON to a server via POST

\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'); 

Sends a POST request (via CURL) to a 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 = []); 

Sends a PUT request (via curl) to a 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 = []); 

Sends a PUT request (via curl) to a server as 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() 

methods to simplify access to TypoScript setup, constants and PageTsConfig to simplify access.

Overview of Methods 

\nn\t3::Settings()->addPageConfig($str = ''); 

Add page config Alias to \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::Settings()->addPageConfig( 'test.was = 10' );
\nn\t3::Settings()->addPageConfig( '' );
\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 = ''); 

Fetches the TypoScript setup and the "settings" section there. Values from the FlexForm are not merged. Alias to \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-performance version for initializing the TSFE in the backend. Get the complete TypoScript setup, incl. '.' syntax.

Is saved via file cache.

\nn\t3::Settings()->getCachedTyposcript();
Copied!

| @return array

| ➜ Go to source code of Settings::getCachedTyposcript()

\nn\t3::Settings()->getConstants($tsPath = ''); 

Get array of TypoScript constants.

\nn\t3::Settings()->getConstants();
\nn\t3::Settings()->getConstants('path.to.constant');
Copied!

Also exists as ViewHelper:

{nnt3:ts.constants(path:'path.to.constant')}
Copied!

| @return array

| ➜ Go to source code of Settings::getConstants()

\nn\t3::Settings()->getExtConf($extName = ''); 

Get extension configuration. come from the LocalConfiguration.php, are defined via the extension settings defined in the backend or ext_conf_template.txt

Earlier: $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); 

Get setup from a given path, e.g. 'plugin.tx_example.settings'

\nn\t3::Settings()->getFromPath('plugin.path');
\nn\t3::Settings()->getFromPath('L', \nn\t3::Request()->GP());
\nn\t3::Settings()->getFromPath('a.b', ['a'=>['b'=>1]]);
Copied!

Also exists as ViewHelper:

{nnt3:ts.setup(path:'path.zur.setup')}
Copied!

| @return array

| ➜ Go to source code of Settings::getFromPath()

\nn\t3::Settings()->getFullTypoScriptFromConfigurationManager(); 

Get complete TypoScript via the Configuration Manager.

A simple wrapper for the core function but with try { ... } catch() Fallback.

Does not work in every context - e.g. not in the CLI context! Better: \nn\t3::Settings()->parseTypoScriptForPage(); use.

Returns the notation with dots. This can be done via | \nn\t3::TypoScript()->convertToPlainArray() into a normal array be converted into a normal array.

// ==> ['plugin.']['example.'][...]
$setup = \nn\t3::Settings()->getFullTypoScriptFromConfigurationManager();
Copied!

| @return array

| ➜ Go to source code of Settings::getFullTypoScriptFromConfigurationManager()

\nn\t3::Settings()->getFullTyposcript($pid = NULL); 

Get the complete TypoScript setup, as a simple array - without "." syntax Works both in the frontend and backend, with and without passed 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 = []); 

Get merge from TypoScript setup for a plugin and its flexform. Returns the TypoScript array from plugin.tx_extname.settings... back.

Important: Only specify $extensionName if the setup of a FREMDEN extension is to be fetched or there is no controller context because the call is made from the backend... otherwise the FlexForm values are not taken into account!

In the FlexForm ``` use! | ```` Then overwrite ``settings.varName` in the TypoScript setup

| $ttContentUidOrSetupArray can be the uid of a tt_content content element or a simple array to overwrite the values from the 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); 

Get page configuration

\nn\t3::Settings()->getPageConfig();
\nn\t3::Settings()->getPageConfig('RTE.default.preset');
\nn\t3::Settings()->getPageConfig( $tsPath, $pid );
Copied!

Also exists as ViewHelper:

{nnt3:ts.page(path:'path.to.pageconfig')}
Copied!

| @return array

| ➜ Go to source code of Settings::getPageConfig()

\nn\t3::Settings()->getPlugin($extName = NULL); 

Get the setup for a specific plugin.

\nn\t3::Settings()->getPlugin('extname') returns TypoScript from plugin.tx_extname...
Copied!

Important: Only specify $extensionName if the setup of a FREMDEN extension is to be fetched or there is no controller context because the call is made e.g. is made from the backend

| @return array

| ➜ Go to source code of Settings::getPlugin()

\nn\t3::Settings()->getSettings($extensionName = '', $path = ''); 

Fetches the TypoScript setup and the "settings" section there. Values from the FlexForm are not merged.

\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); 

Get site configuration. This is the configuration that has been defined in the YAML files in the /sites folder since TYPO3 9. Some of the settings can also be set via the "Sites" page module.

In the context of a MiddleWare, the site may not yet be parsed / loaded. In this case, the $request from the MiddleWare can be passed to determine the site.

$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); 

Get current (FIRST) StoragePid for the current plugin. Saved in the TypoScript setup of the extension under | plugin.tx_extname.persistence.storagePid or in the FlexForm of the plugin on the respective page.

IMPORTANT: Merge with selected StoragePID from the FlexForm only happens if $extNameis left empty.

\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); 

Get ALL storagePids for the current plugin. Saved as a comma-separated list in the TypoScript setup of the extension under | plugin.tx_extname.persistence.storagePid or in the FlexForm of the plugin on the respective page.

IMPORTANT: Merge with selected StoragePID from the FlexForm only happens if $extNameis left empty.

\nn\t3::Settings()->getStoragePids(); // [123, 466]
\nn\t3::Settings()->getStoragePids('nnsite'); // [123, 466]
Copied!

Also get the child-PageUids? | true takes the value for "Recursive" from the FlexForm or from the TypoScript of the extension of 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!

Alternatively, a numerical value can also be passed for the depth / recursion can also be passed.

\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); 

Parse TypoScript for specific pageUid.

Returns the notation with dots. This can be done via | \nn\t3::TypoScript()->convertToPlainArray() into a normal array be converted into a normal array.

// Get TypoScript for current pageUid
\nn\t3::Settings()->parseTypoScriptForPage();

// Get TypoScript for specific pageUid
\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 = ''); 

Write extension configuration. Writes an extension configuration in the LocalConfiguration.php. The values can also be corresponding configuration in ext_conf_template.txt, the values can also be edited via the Extension Manager / the Extension configuration in the backend.

\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 = ''); 

Add page config Alias to \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::Settings()->addPageConfig( 'test.was = 10' );
\nn\t3::Settings()->addPageConfig( '' );
\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 = ''); 

Fetches the TypoScript setup and the "settings" section there. Values from the FlexForm are not merged. Alias to \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-performance version for initializing the TSFE in the backend. Get the complete TypoScript setup, incl. '.' syntax.

Is saved via file cache.

\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 = ''); 

Get array of TypoScript constants.

\nn\t3::Settings()->getConstants();
\nn\t3::Settings()->getConstants('path.to.constant');
Copied!

Also exists as ViewHelper:

{nnt3:ts.constants(path:'path.to.constant')}
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 = ''); 

Get extension configuration. come from the LocalConfiguration.php, are defined via the extension settings defined in the backend or ext_conf_template.txt

Earlier: $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); 

Get setup from a given path, e.g. 'plugin.tx_example.settings'

\nn\t3::Settings()->getFromPath('plugin.path');
\nn\t3::Settings()->getFromPath('L', \nn\t3::Request()->GP());
\nn\t3::Settings()->getFromPath('a.b', ['a'=>['b'=>1]]);
Copied!

Also exists as ViewHelper:

{nnt3:ts.setup(path:'path.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); 

Get the complete TypoScript setup, as a simple array - without "." syntax Works both in the frontend and backend, with and without passed 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(); 

Get complete TypoScript via the Configuration Manager.

A simple wrapper for the core function but with try { ... } catch() Fallback.

Does not work in every context - e.g. not in the CLI context! Better: \nn\t3::Settings()->parseTypoScriptForPage(); use.

Returns the notation with dots. This can be done via | \nn\t3::TypoScript()->convertToPlainArray() into a normal array be converted into a normal array.

// ==> ['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 = []); 

Get merge from TypoScript setup for a plugin and its flexform. Returns the TypoScript array from plugin.tx_extname.settings... back.

Important: Only specify $extensionName if the setup of a FREMDEN extension is to be fetched or there is no controller context because the call is made from the backend... otherwise the FlexForm values are not taken into account!

In the FlexForm ``` use! | ```` Then overwrite ``settings.varName` in the TypoScript setup

| $ttContentUidOrSetupArray can be the uid of a tt_content content element or a simple array to overwrite the values from the 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); 

Get page configuration

\nn\t3::Settings()->getPageConfig();
\nn\t3::Settings()->getPageConfig('RTE.default.preset');
\nn\t3::Settings()->getPageConfig( $tsPath, $pid );
Copied!

Also exists as ViewHelper:

{nnt3:ts.page(path:'path.to.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); 

Get the setup for a specific plugin.

\nn\t3::Settings()->getPlugin('extname') returns TypoScript from plugin.tx_extname...
Copied!

Important: Only specify $extensionName if the setup of a FREMDEN extension is to be fetched or there is no controller context because the call is made e.g. is made from the backend

| @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 = ''); 

Fetches the TypoScript setup and the "settings" section there. Values from the FlexForm are not merged.

\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); 

Get site configuration. This is the configuration that has been defined in the YAML files in the /sites folder since TYPO3 9. Some of the settings can also be set via the "Sites" page module.

In the context of a MiddleWare, the site may not yet be parsed / loaded. In this case, the $request from the MiddleWare can be passed to determine the site.

$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); 

Get current (FIRST) StoragePid for the current plugin. Saved in the TypoScript setup of the extension under | plugin.tx_extname.persistence.storagePid or in the FlexForm of the plugin on the respective page.

IMPORTANT: Merge with selected StoragePID from the FlexForm only happens if $extNameis left empty.

\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); 

Get ALL storagePids for the current plugin. Saved as a comma-separated list in the TypoScript setup of the extension under | plugin.tx_extname.persistence.storagePid or in the FlexForm of the plugin on the respective page.

IMPORTANT: Merge with selected StoragePID from the FlexForm only happens if $extNameis left empty.

\nn\t3::Settings()->getStoragePids(); // [123, 466]
\nn\t3::Settings()->getStoragePids('nnsite'); // [123, 466]
Copied!

Also get the child-PageUids? | true takes the value for "Recursive" from the FlexForm or from the TypoScript of the extension of 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!

Alternatively, a numerical value can also be passed for the depth / recursion can also be passed.

\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); 

Parse TypoScript for specific pageUid.

Returns the notation with dots. This can be done via | \nn\t3::TypoScript()->convertToPlainArray() into a normal array be converted into a normal array.

// Get TypoScript for current pageUid
\nn\t3::Settings()->parseTypoScriptForPage();

// Get TypoScript for specific pageUid
\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 = ''); 

Write extension configuration. Writes an extension configuration in the LocalConfiguration.php. The values can also be corresponding configuration in ext_conf_template.txt, the values can also be edited via the Extension Manager / the Extension configuration in the backend.

\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() 

Generate and manipulate URL paths (slug)

Overview of Methods 

\nn\t3::Slug()->create($model); 

Generates a slug (URL path) for a model. Automatically determines the TCA field for the slug.

\nn\t3::Slug()->create( $model );
Copied!

| @return string

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

Methods 

Slug::create() 

\nn\t3::Slug()->create($model); 

Generates a slug (URL path) for a model. Automatically determines the TCA field for the 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() 

Everything about Storages

Overview of Methods 

\nn\t3::Storage()->clearStorageRowCache(); 

Deletes the StorageRowCache

\nn\t3::Storage()->clearStorageRowCache();
Copied!

| @return void

| ➜ Go to source code of Storage::clearStorageRowCache()

\nn\t3::Storage()->getFolder($file, $storage = NULL); 

Returns the Folder object for a target folder (or file) within a storage. Creates a folder if it does not yet exist

Examples:

\nn\t3::Storage()->getFolder( 'fileadmin/test/example.txt' );
\nn\t3::Storage()->getFolder( 'fileadmin/test/' );
        ==> returns \Folder object for the folder 'test/'
Copied!

| @return Folder

| ➜ Go to source code of Storage::getFolder()

\nn\t3::Storage()->getPid($extName = NULL); 

In the controller: Get current StoragePid for a plug-in. Alias to \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(); 

Deletes the 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); 

Returns the Folder object for a target folder (or file) within a storage. Creates a folder if it does not yet exist

Examples:

\nn\t3::Storage()->getFolder( 'fileadmin/test/example.txt' );
\nn\t3::Storage()->getFolder( 'fileadmin/test/' );
        ==> returns \Folder object for the folder 'test/'
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); 

In the controller: Get current StoragePid for a plug-in. Alias to \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() 

Simplifies the work and access to the sys_category of Typo3

Overview of Methods 

\nn\t3::SysCategory()->findAll($branchUid = NULL); 

Get list of all sys_categories

\nn\t3::SysCategory()->findAll();
Copied!

| @return array

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

\nn\t3::SysCategory()->findAllByUid($branchUid = NULL); 

Get list of all sys_categories, return uid as key

\nn\t3::SysCategory()->findAllByUid();
Copied!

| @return array

| ➜ Go to source code of SysCategory::findAllByUid()

\nn\t3::SysCategory()->findByUid($uidList = NULL); 

Get sys_categories by uid(s).

\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); 

Get the entire SysCategory tree (as an array). Each node has the attributes 'parent' and 'children' in order to recursively iterate through the tree.

// Get the entire tree
\nn\t3::SysCategory()->getTree();

// Get a specific branch of the tree
\nn\t3::SysCategory()->getTree( $uid );

// Get all branches of the tree, key is the UID of the SysCategory
\nn\t3::SysCategory()->getTree( true );
Copied!

ToDo: Check whether caching makes sense

| @return array

| ➜ Go to source code of SysCategory::getTree()

Methods 

SysCategory::findAll() 

\nn\t3::SysCategory()->findAll($branchUid = NULL); 

Get list of all sys_categories

\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); 

Get list of all sys_categories, return uid as key

\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); 

Get sys_categories by uid(s).

\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); 

Get the entire SysCategory tree (as an array). Each node has the attributes 'parent' and 'children' in order to recursively iterate through the tree.

// Get the entire tree
\nn\t3::SysCategory()->getTree();

// Get a specific branch of the tree
\nn\t3::SysCategory()->getTree( $uid );

// Get all branches of the tree, key is the UID of the SysCategory
\nn\t3::SysCategory()->getTree( true );
Copied!

ToDo: Check whether caching makes sense

| @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() 

Methods for configuring and accessing fields in the TCA.

Overview of Methods 

\nn\t3::TCA()->addModuleOptionToPage($label, $identifier, $iconIdentifier = ''); 

Add a selection option in the page properties under "Behavior -> Contains extension". Traditionally used in Configuration/TCA/Overrides/pages.php, previously in ext_tables.php

// Register the icon in ext_localconf.php (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('description', 'identifier', 'icon-identifier');
Copied!

| @return void

| ➜ Go to source code of TCA::addModuleOptionToPage()

\nn\t3::TCA()->createConfig($tablename = '', $basics = [], $custom = []); 

Get basic configuration for the TCA. These are the fields such as hidden, starttime etc., which are always the same for (almost) all tables.

Get ALL typical fields:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry', true,
    ['title'=>...]
)
Copied!

Get only certain fields:

'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(); 

Get color picker configuration for the TCA.

'config' => \nn\t3::TCA()->getColorPickerTCAConfig(),
Copied!

| @return array

| ➜ Go to source code of TCA::getColorPickerTCAConfig()

\nn\t3::TCA()->getColumn($tableName = '', $fieldName = '', $useSchemaManager = false); 

Gets configuration array for a field from the TCA. Alias to \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); 

Gets configuration array for a table from the TCA. Alias to \nn\t3::Db()->getColumns()

\nn\t3::TCA()->getColumns( 'pages' );
Copied!

| @return array

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

\nn\t3::TCA()->getConfig($path = ''); 

Get a configuration from the TCA for a path. Returns a reference to the config array of the corresponding field.

\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 = []); 

Get default configuration for various typical types in the TCA Serves as a kind of alias to write the most frequently used config arrays faster and and to be able to write them more quickly

\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 configurations can simply be overwritten / extended:

\nn\t3::TCA()->getConfigForType( 'text', ['rows'=>5] ); // => ['type'=>'text', 'rows'=>5, ...]
Copied!

For each type, the most frequently overwritten value in the config array can also be by passing a fixed value instead of an override array:

\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 for the field with the key `image` ]
Copied!

| @return array

| ➜ Go to source code of TCA::getConfigForType()

\nn\t3::TCA()->getFalFields($tableName = ''); 

Retrieves all field names from the TCA array that have a SysFileReference relation. For the table tt_content this would be 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 = []); 

Get FAL configuration for the TCA.

Standard config incl. image cropper, link and alternative image title This setting changes regularly, which is quite an imposition given the number of parameters and their changing position in the array is quite an imposition.

https://bit.ly/2SUvASe

\nn\t3::TCA()->getFileFieldTCAConfig('media');
\nn\t3::TCA()->getFileFieldTCAConfig('media', ['maxitems'=>1, 'fileExtensions'=>'jpg']);
Copied!

Is used in the TCA like this:

'falprofileimage' => [
    'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage', ['maxitems'=>1]),
],
Copied!

| @return array

| ➜ Go to source code of TCA::getFileFieldTCAConfig()

\nn\t3::TCA()->getRteTCAConfig(); 

Get RTE configuration for the TCA.

'config' => \nn\t3::TCA()->getRteTCAConfig(),
Copied!

| @return array

| ➜ Go to source code of TCA::getRteTCAConfig()

\nn\t3::TCA()->getSlugTCAConfig($fields = []); 

Get default slug configuration for the TCA.

'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); 

Inserts list of countries into a TCA. Alias to nnt3::Flexform->insertCountries( $config, $a = null ); Description and further examples there.

Example in the 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); 

Inserts a flex form into a TCA.

Example in the 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); 

Inserts options from TypoScript into a TCA for selection. Alias to nnt3::Flexform->insertOptions( $config, $a = null ); Description and further examples there.

Example in the 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 = []); 

Overwrite a configuration of the TCA, e.g. to overwrite a mask field with its own renderType or to change core settings in the TCA on the pages or tt_content tables.

The following example sets/overwrites the config array in the TCA under:

$GLOBALS['TCA']['tt_content']['columns']['mycol']['config'][...]
Copied!
\nn\t3::TCA()->setConfig('tt_content.columns.mycol', [
    'renderType' => 'nnsiteIconCollection',
    'iconconfig' => 'tx_nnsite.iconcollection',
]);
Copied!

See also \nn\t3::TCA()->setContentConfig() for a short version of this method when it comes to the table tt_content and \nn\t3::TCA()->setPagesConfig() for the table pages

| @return array

| ➜ Go to source code of TCA::setConfig()

\nn\t3::TCA()->setContentConfig($field = '', $override = [], $shortParams = NULL); 

Set or overwrite a configuration of the TCA for the table tt_content.

This example overwrites the config array of the tt_content table in the TCA for:

$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); 

Set or overwrite a configuration of the TCA for the pages table.

This example overwrites the config array of the pages table for the TCA:

$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 = ''); 

Add a selection option in the page properties under "Behavior -> Contains extension". Traditionally used in Configuration/TCA/Overrides/pages.php, previously in ext_tables.php

// Register the icon in ext_localconf.php (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('description', '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 = []); 

Get basic configuration for the TCA. These are the fields such as hidden, starttime etc., which are always the same for (almost) all tables.

Get ALL typical fields:

'columns' => \nn\t3::TCA()->createConfig(
    'tx_myext_domain_model_entry', true,
    ['title'=>...]
)
Copied!

Get only certain fields:

'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(); 

Get color picker configuration for the TCA.

'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); 

Gets configuration array for a field from the TCA. Alias to \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); 

Gets configuration array for a table from the TCA. Alias to \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 = ''); 

Get a configuration from the TCA for a path. Returns a reference to the config array of the corresponding field.

\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 = []); 

Get default configuration for various typical types in the TCA Serves as a kind of alias to write the most frequently used config arrays faster and and to be able to write them more quickly

\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 configurations can simply be overwritten / extended:

\nn\t3::TCA()->getConfigForType( 'text', ['rows'=>5] ); // => ['type'=>'text', 'rows'=>5, ...]
Copied!

For each type, the most frequently overwritten value in the config array can also be by passing a fixed value instead of an override array:

\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 for the field with the 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 = ''); 

Retrieves all field names from the TCA array that have a SysFileReference relation. For the table tt_content this would be 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 = []); 

Get FAL configuration for the TCA.

Standard config incl. image cropper, link and alternative image title This setting changes regularly, which is quite an imposition given the number of parameters and their changing position in the array is quite an imposition.

https://bit.ly/2SUvASe

\nn\t3::TCA()->getFileFieldTCAConfig('media');
\nn\t3::TCA()->getFileFieldTCAConfig('media', ['maxitems'=>1, 'fileExtensions'=>'jpg']);
Copied!

Is used in the TCA like this:

'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(); 

Get RTE configuration for the TCA.

'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 = []); 

Get default slug configuration for the TCA.

'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); 

Inserts list of countries into a TCA. Alias to nnt3::Flexform->insertCountries( $config, $a = null ); Description and further examples there.

Example in the 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); 

Inserts a flex form into a TCA.

Example in the 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); 

Inserts options from TypoScript into a TCA for selection. Alias to nnt3::Flexform->insertOptions( $config, $a = null ); Description and further examples there.

Example in the 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 = []); 

Overwrite a configuration of the TCA, e.g. to overwrite a mask field with its own renderType or to change core settings in the TCA on the pages or tt_content tables.

The following example sets/overwrites the config array in the TCA under:

$GLOBALS['TCA']['tt_content']['columns']['mycol']['config'][...]
Copied!
\nn\t3::TCA()->setConfig('tt_content.columns.mycol', [
    'renderType' => 'nnsiteIconCollection',
    'iconconfig' => 'tx_nnsite.iconcollection',
]);
Copied!

See also \nn\t3::TCA()->setContentConfig() for a short version of this method when it comes to the table tt_content and \nn\t3::TCA()->setPagesConfig() for the table 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); 

Set or overwrite a configuration of the TCA for the table tt_content.

This example overwrites the config array of the tt_content table in the TCA for:

$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); 

Set or overwrite a configuration of the TCA for the pages table.

This example overwrites the config array of the pages table for the TCA:

$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() 

Render fluid templates and manipulate paths to templates in the view.

Overview of Methods 

\nn\t3::Template()->findTemplate($view = NULL, $templateName = ''); 

Finds a template in an array of possible templatePaths of the view

\nn\t3::Template()->findTemplate( $this->view, 'example.html' );
Copied!

| @return string

| ➜ Go to source code of Template::findTemplate()

\nn\t3::Template()->getVariable($view, $varname = ''); 

Fetches ONE variable of the current view, i.e: Everything that was set via assign() and assignMultiple().

In the ViewHelper:

\nn\t3::Template()->getVariable( $renderingContext, 'varname' );
Copied!

In the controller:

\nn\t3::Template()->getVariable( $this->view, 'varname' );
Copied!

| @return array

| ➜ Go to source code of Template::getVariable()

\nn\t3::Template()->getVariables($view); 

Retrieves the variables of the current view, i.e: Everything that was set via assign() and assignMultiple().

In the ViewHelper:

\nn\t3::Template()->getVariables( $renderingContext );
Copied!

In the controller:

\nn\t3::Template()->getVariables( $this->view );
Copied!

| @return array

| ➜ Go to source code of Template::getVariables()

\nn\t3::Template()->mergeTemplatePaths($defaultTemplatePaths = [], $additionalTemplatePaths = []); 

Merge paths to templates, partials, layout

\nn\t3::Template()->mergeTemplatePaths( $defaultTemplatePaths, $additionalTemplatePaths );
Copied!

| @return array

| ➜ Go to source code of Template::mergeTemplatePaths()

\nn\t3::Template()->removeControllerPath($view); 

Removes the path of the controller name, e.g. /Main/... from the search for 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); 

Render a Fluid template using the 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!

Since TYPO3 12, the $request must also be passed when calling from a controller:

\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); 

Render simple fluid code via 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!

Since TYPO3 12, the $request must also be passed when calling from a controller:

\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 = []); 

Sets templates, partials and layouts for a view. $additionalTemplatePaths can be passed to prioritize paths

\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 = ''); 

Finds a template in an array of possible templatePaths of the view

\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 = ''); 

Fetches ONE variable of the current view, i.e: Everything that was set via assign() and assignMultiple().

In the ViewHelper:

\nn\t3::Template()->getVariable( $renderingContext, 'varname' );
Copied!

In the 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); 

Retrieves the variables of the current view, i.e: Everything that was set via assign() and assignMultiple().

In the ViewHelper:

\nn\t3::Template()->getVariables( $renderingContext );
Copied!

In the 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 = []); 

Merge paths to templates, partials, layout

\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); 

Removes the path of the controller name, e.g. /Main/... from the search for 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); 

Render a Fluid template using the 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!

Since TYPO3 12, the $request must also be passed when calling from a controller:

\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); 

Render simple fluid code via 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!

Since TYPO3 12, the $request must also be passed when calling from a controller:

\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 = []); 

Sets templates, partials and layouts for a view. $additionalTemplatePaths can be passed to prioritize paths

\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() 

Everything about the Typo3 frontend. Methods for initializing the FE from the backend context, access to the cObj and 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); 

Get $GLOBALS['TSFE']->cObj.

// since TYPO3 12.4 within a controller:
\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); 

Get $GLOBALS['TSFE']->cObj->data.

\nn\t3::Tsfe()->cObjData( $this->request ); => array with DB-row of the current content element
\nn\t3::Tsfe()->cObjData( $this->request, 'uid' ); => uid of the current content element
Copied!

| @return mixed

| ➜ Go to source code of Tsfe::cObjData()

\nn\t3::Tsfe()->cObjGetSingle($type = '', $conf = []); 

Render a TypoScript object. Earlier: $GLOBALS['TSFE']->cObj->cObjGetSingle()

\nn\t3::Tsfe()->cObjGetSingle('IMG_RESOURCE', ['file'=>'image.jpg', 'file.'=>['maxWidth'=>200]] )
Copied!

| ➜ Go to source code of Tsfe::cObjGetSingle()

\nn\t3::Tsfe()->forceAbsoluteUrls($enable = true); 

Sets config.absRefPrefix to the current URL.

This means that when rendering the links of content elements absolute URLs are used. Does not (yet) work for images.

\nn\t3::Environment()->forceAbsoluteUrls();
$html = \nn\t3::Content()->render(123);
Copied!

| ➜ Go to source code of Tsfe::forceAbsoluteUrls()

\nn\t3::Tsfe()->get($pid = NULL); 

Get $GLOBALS['TSFE']. If not available (because in BE) initialize.

\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); 

Get hidden content elements in the frontend. Can be used before rendering.

\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); 

Initialize the $GLOBALS['TSFE'] Only used for compatibility with older code that still uses $GLOBALS['TSFE'].

// Get TypoScript the 'old' way
$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); 

Inject fully initialized TypoScript into the request.

This is necessary when executing in a cached frontend context in which the TypoScript setup array is not initialized. It uses the TypoScriptHelper to create a complete TypoScript object and place it into the frontend.typoscript attribute of the request.

// In the 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); 

Deactivate cache for the frontend.

"Soft" variant: Uses a fake USER_INT object so that already rendered elements elements do not have to be rendered again. Workaround for TYPO3 v12+, since TypoScript Setup & Constants are no longer initialized when page is completely loaded from the cache.

\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); 

Get $GLOBALS['TSFE']->cObj.

// since TYPO3 12.4 within a controller:
\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); 

Get $GLOBALS['TSFE']->cObj->data.

\nn\t3::Tsfe()->cObjData( $this->request ); => array with DB-row of the current content element
\nn\t3::Tsfe()->cObjData( $this->request, 'uid' ); => uid of the current content element
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 = []); 

Render a TypoScript object. Earlier: $GLOBALS['TSFE']->cObj->cObjGetSingle()

\nn\t3::Tsfe()->cObjGetSingle('IMG_RESOURCE', ['file'=>'image.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); 

Sets config.absRefPrefix to the current URL.

This means that when rendering the links of content elements absolute URLs are used. Does not (yet) work for images.

\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); 

Get $GLOBALS['TSFE']. If not available (because in BE) initialize.

\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); 

Get hidden content elements in the frontend. Can be used before rendering.

\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); 

Initialize the $GLOBALS['TSFE'] Only used for compatibility with older code that still uses $GLOBALS['TSFE'].

// Get TypoScript the 'old' way
$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); 

Inject fully initialized TypoScript into the request.

This is necessary when executing in a cached frontend context in which the TypoScript setup array is not initialized. It uses the TypoScriptHelper to create a complete TypoScript object and place it into the frontend.typoscript attribute of the request.

// In the 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); 

Deactivate cache for the frontend.

"Soft" variant: Uses a fake USER_INT object so that already rendered elements elements do not have to be rendered again. Workaround for TYPO3 v12+, since TypoScript Setup & Constants are no longer initialized when page is completely loaded from the cache.

\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() 

Methods for parsing and converting TypoScript

Overview of Methods 

\nn\t3::TypoScript()->addPageConfig($str = ''); 

Add page config Alias to \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::TypoScript()->addPageConfig( 'test.was = 10' );
\nn\t3::TypoScript()->addPageConfig( '' );
\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); 

Convert TypoScript 'name.' syntax to normal array. Facilitates access

\nn\t3::TypoScript()->convertToPlainArray(['example'=>'test', 'example.'=>'here']);
Copied!

| @return array

| ➜ Go to source code of TypoScript::convertToPlainArray()

\nn\t3::TypoScript()->fromString($str = '', $overrideSetup = []); 

Converts a text into a TypoScript array.

$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 = ''); 

Add page config Alias to \nn\t3::Registry()->addPageConfig( $str );

\nn\t3::TypoScript()->addPageConfig( 'test.was = 10' );
\nn\t3::TypoScript()->addPageConfig( '' );
\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); 

Convert TypoScript 'name.' syntax to normal array. Facilitates access

\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 = []); 

Converts a text into a TypoScript array.

$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() 

Everything that is important and helpful on the subject of videos.

Overview of Methods 

\nn\t3::Video()->getEmbedUrl($type, $videoId = NULL); 

Return the embed URL based on the streaming platform. Classically, the URL that is used in the src attribute of the is used.

\nn\t3::Video()->getEmbedUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getEmbedUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );
Copied!

Also exists as ViewHelper:

{my.videourl->nnt3:video.embedUrl()}
Copied!

| @return string

| ➜ Go to source code of Video::getEmbedUrl()

\nn\t3::Video()->getExternalType($url = NULL); 

Returns an array with information about the streaming platform and code for embedding a video.

\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 to the video on the external platform e.g. to display an external link to the video

\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); 

Checks whether the URL is an external video on YouTube or Vimeo. Returns an array with data for embedding.

\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); 

Return the embed URL based on the streaming platform. Classically, the URL that is used in the src attribute of the is used.

\nn\t3::Video()->getEmbedUrl( 'youtube', 'nShlloNgM2E' );
\nn\t3::Video()->getEmbedUrl( 'https://www.youtube.com/watch?v=wu55ZG97zeI&feature=youtu.be' );
Copied!

Also exists as 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); 

Returns an array with information about the streaming platform and code for embedding a video.

\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 to the video on the external platform e.g. to display an external link to the video

\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); 

Checks whether the URL is an external video on YouTube or Vimeo. Returns an array with data for embedding.

\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() 

Various methods for parsing PHP annotations

Overview of Methods 

\nn\t3::AnnotationHelper()->parse($rawAnnotation = '', $namespaces = []); 

parse annotations and return an array with the "normal" comment block and the individual individual annotations from a DocComment.

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...' );
Copied!

Only fetch annotations that are in a specific namespace. In this example, only annotations that begin with @nn\rest are fetched, e.g. @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 = []); 

parse annotations and return an array with the "normal" comment block and the individual individual annotations from a DocComment.

\Nng\Nnhelpers\Helpers\AnnotationHelper::parse( '...' );
Copied!

Only fetch annotations that are in a specific namespace. In this example, only annotations that begin with @nn\rest are fetched, e.g. @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() 

Various methods for parsing PHP source code and comments in the source code source code (annotations). Objective: To create automated documentation from the comments in the PHP code.

Examples for the use incl. rendering of the template

In the controller with rendering via Fluid:

$path = \nn\t3::Environment()->extPath('myext') . 'Classes/Utilities/';
$doc = \Nng\Nnhelpers\Helpers\DocumentationHelper::parseFolder( $path );
$this->view->assign('doc', $doc);
Copied!

Generate the Typo3 / Sphinx ReST document via a custom 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); 

Get class name as string incl. full namespace from a PHP file. For example, returns Nng\Classes\MyClass.

\Nng\Nnhelpers\Helpers\DocumentationHelper::getClassNameFromFile( 'Classes/MyClass.php' );
Copied!

| @return string

| ➜ Go to source code of DocumentationHelper::getClassNameFromFile()

\nn\t3::DocumentationHelper()->getSourceCode($class, $method); 

Get source code of a method.

Returns the "raw" PHP code of the method of a class.

\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); 

Get information about a specific class.

Similar to parseFile() - however, the actual class name must be passed here. If you only know the path to the PHP file, use 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); 

Get all information about a single PHP file.

Parses the annotation above the class definition and optionally also all methods of the class. Returns an array where the arguments / parameters of each method are also listed.

Markdown can be used in the annotations, the Markdown is automatically converted to HTML code.

\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 = []); 

Parse a folder (recursively) for classes with annotations. Returns an array with information about each class and its methods.

The annotations (comments) above the class methods can be formatted in Markdown, they are automatically converted to HTML with appropriate `` and tags are converted.``

\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); 

Get class name as string incl. full namespace from a PHP file. For example, returns Nng\Classes\MyClass.

\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); 

Get source code of a method.

Returns the "raw" PHP code of the method of a class.

\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); 

Get information about a specific class.

Similar to parseFile() - however, the actual class name must be passed here. If you only know the path to the PHP file, use 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); 

Get all information about a single PHP file.

Parses the annotation above the class definition and optionally also all methods of the class. Returns an array where the arguments / parameters of each method are also listed.

Markdown can be used in the annotations, the Markdown is automatically converted to HTML code.

\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 = []); 

Parse a folder (recursively) for classes with annotations. Returns an array with information about each class and its methods.

The annotations (comments) above the class methods can be formatted in Markdown, they are automatically converted to HTML with appropriate `` and tags are converted.``

\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() 

Extension for the Extension Manager form.

Overview of Methods 

\nn\t3::ExtConfTemplateHelper()->textfield($conf = []); 

Show multiline text field / textarea in the Extension Manager configurator. Use this line in ext_conf_template.txt of your own extension:

# cat=basic; type=user[Nng\Nnhelpers\Helpers\ExtConfTemplateHelper->textfield]; label=My label
myFieldName =
Copied!

| @return string

| ➜ Go to source code of ExtConfTemplateHelper::textfield()

Methods 

ExtConfTemplateHelper::textfield() 

\nn\t3::ExtConfTemplateHelper()->textfield($conf = []); 

Show multiline text field / textarea in the Extension Manager configurator. Use this line in ext_conf_template.txt of your own extension:

# cat=basic; type=user[Nng\Nnhelpers\Helpers\ExtConfTemplateHelper->textfield]; label=My label
myFieldName =
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() 

The script helps to convert and parse JavaScript object strings into an array.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

The helper makes it possible to use the JavaScript object notation in TypoScript and to convert it into an array via the {nnt3:parse.json()} ViewHelper. This is practical if, for example, slider configurations or other JavaScript objects are to be defined in TypoScript in order to use them later in JavaScript.

Another application example: You want to use the "normal" JS syntax in a .json file instead of the JSON syntax. Let's take a look at an example. This text was written in a text file and is to be parsed via PHP:

// Contents of a text file.
{
    example: ['one', 'two', 'three']
}
Copied!

PHP would report an error in this example with json_decode(): The string contains comments, wrapping and the keys and values are not enclosed in double quotes. However, the JsonHelper or the ViewHelper $jsonHelper->decode() can easily convert it.

This is how you could define a JS object in the TypoScript setup:

// Content in the TS setup
my_conf.data (
  {
     dots: true,
     sizes: [1, 2, 3]
  }
)
Copied!

The mixture is a little confusing: my_conf.data (...) opens a section in the TypoScript for multi-line code. There is then a "normal" JavaScript object between the (...) This can then simply be used as an array in the Fluid template:

{nnt3:ts.setup(path:'my_conf.data')->f:variable(name:'myConfig')}
{myConfig->nnt3:parse.json()->f:debug()}
Copied!

Or attach it to an element as a data attribute to parse it later via JavaScript:

{nnt3:ts.setup(path:'my_conf.data')->f:variable(name:'myConfig')}
...
Copied!

This script is mainly based on the work of https://bit.ly/3eZuNu2 and has been optimized by us for PHP 7+.all credit and glory please in this direction.

Overview of Methods 

\nn\t3::JsonHelper()->decode($str, $useArray = true); 

Converts a JS object string into an array.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

The PHP function json_decode() only works with JSON syntax: {"key": "value"}. Neither line breaks nor comments are allowed in JSON. This function can also be used to parse strings in JavaScript notation.

| @return array|string

| ➜ Go to source code of JsonHelper::decode()

\nn\t3::JsonHelper()->encode($var); 

Converts a variable into JSON format. Relic of the original class, probably from a time when json_encode() did not yet exist.

\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); 

Removes comments from the code and parses the string.

\Nng\Nnhelpers\Helpers\JsonHelper::removeCommentsAndDecode( "// Comment\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); 

Converts a JS object string into an array.

$data = \Nng\Nnhelpers\Helpers\JsonHelper::decode( "{title:'Test', cat:[2,3,4]}" );
print_r($data);
Copied!

The PHP function json_decode() only works with JSON syntax: {"key": "value"}. Neither line breaks nor comments are allowed in JSON. This function can also be used to parse strings in JavaScript notation.

| @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); 

Converts a variable into JSON format. Relic of the original class, probably from a time when json_encode() did not yet exist.

\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); 

Removes comments from the code and parses the string.

\Nng\Nnhelpers\Helpers\JsonHelper::removeCommentsAndDecode( "// Comment\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() 

A wrapper for parsing markdown and translation into HTML and vice versa.

Overview of Methods 

\nn\t3::MarkdownHelper()->parseComment($comment = '', $encode = true); 

Convert comment string to readable HTML string Comments can use Markdown. Removes '' and '' etc.

\Nng\Nnhelpers\Helpers\MarkdownHelper::parseComment( '...' );
Copied!

| @return string

| ➜ Go to source code of MarkdownHelper::parseComment()

\nn\t3::MarkdownHelper()->removeAsterisks($comment = ''); 

Removes the comment asterisks in a text.

\Nng\Nnhelpers\Helpers\MarkdownHelper::removeAsterisks( '...' );
Copied!

| @return string

| ➜ Go to source code of MarkdownHelper::removeAsterisks()

\nn\t3::MarkdownHelper()->toHTML($str = ''); 

Convert a text containing markdown to HTML.

\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); 

Convert comment string to readable HTML string Comments can use Markdown. Removes '' and '' 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 = ''); 

Removes the comment asterisks in a 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 = ''); 

Convert a text containing markdown to HTML.

\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() 

Translation management via Deep-L.

In order to use this function, a Deep-L API key must be stored in the nnhelpers extension manager. The key is free of charge and allows the translation of 500,000 characters per month.

// Activate translator
$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );

// Allow translation via Deep-L
$translationHelper->setEnableApi( true );
// Set target language
$translationHelper->setTargetLanguage( 'EN' );

// Allow max. Allow max. number of translations (for debugging purposes)
$translationHelper->setMaxTranslations( 2 );

// Path in which the l18n files should be saved / cached
$translationHelper->setL18nFolderpath( 'EXT:nnhelpers/Resources/Private/Language/' );

// Start translation
$text = $translationHelper->translate('my.example.key', 'This is the text to be translated');
Copied!

Overview of Methods 

\nn\t3::TranslationHelper()->createKeyHash($param = ''); 

Generates a unique hash from the key that is required to identify a text. Each text has the same key in all languages.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['my', 'key', 'array'] );
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::createKeyHash()

\nn\t3::TranslationHelper()->createTextHash($text = ''); 

Generates a unique hash / checksum from the text. The transferred text is always the base language. If the text in the base language changes, the method returns a different checksum. This recognizes when a text needs to be retranslated. Pure changes to whitespaces and tags are ignored.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['my', 'key', 'array'] );
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::createTextHash()

\nn\t3::TranslationHelper()->getEnableApi(); 

Returns whether the API is enabled.

$translationHelper->getEnableApi(); // default: false
Copied!

| @return boolean

| ➜ Go to source code of TranslationHelper::getEnableApi()

\nn\t3::TranslationHelper()->getL18nFolderpath(); 

Returns the current folder in which the translation files are cached. Default is typo3conf/l10n/nnhelpers/

$translationHelper->getL18nFolderpath();
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getL18nFolderpath()

\nn\t3::TranslationHelper()->getL18nPath(); 

Return the absolute path to the l18n cache file. Default is typo3conf/l10n/nnhelpers/[LANG].autotranslated.json

$translationHelper->getL18nPath();
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getL18nPath()

\nn\t3::TranslationHelper()->getMaxTranslations(); 

Gets the maximum number of translations to be made per instance.

$translationHelper->getMaxTranslations(); // default: 0 = infinite
Copied!

| @return integer

| ➜ Go to source code of TranslationHelper::getMaxTranslations()

\nn\t3::TranslationHelper()->getTargetLanguage(); 

Gets the target language for the translation

$translationHelper->getTargetLanguage(); // Default: EN
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::getTargetLanguage()

\nn\t3::TranslationHelper()->loadL18nData(); 

Load complete language file.

$translationHelper->loadL18nData();
Copied!

| @return array

| ➜ Go to source code of TranslationHelper::loadL18nData()

\nn\t3::TranslationHelper()->saveL18nData($data = []); 

Save complete language file

$translationHelper->saveL18nData( $data );
Copied!

| @return boolean

| ➜ Go to source code of TranslationHelper::saveL18nData()

\nn\t3::TranslationHelper()->setEnableApi($enableApi); 

Activates / deactivates the translation via 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); 

Sets the current folder in which the translation files are cached. The idea is to translate the translated texts for backend modules only once and then save them in the extension folder. From there they are then deployed to GIT.

Default is typo3conf/l10n/nnhelpers/

$translationHelper->setL18nFolderpath('EXT:myext/Resources/Private/Language/');
Copied!
@param string $l18nFolderpathPath to the folder with the translation files (JSON)
@return self

| ➜ Go to source code of TranslationHelper::setL18nFolderpath()

\nn\t3::TranslationHelper()->setMaxTranslations($maxTranslations); 

Sets the maximum number of translations to be made per instance. Helps with debugging (so that the Deep-L quota is not exhausted by testing) and with TimeOuts if many texts need to be translated.

$translationHelper->setMaxTranslations( 5 ); // Abort after 5 translations
Copied!
@param $maxTranslations
@return self

| ➜ Go to source code of TranslationHelper::setMaxTranslations()

\nn\t3::TranslationHelper()->setTargetLanguage($targetLanguage); 

Sets the target language for the translation

$translationHelper->setTargetLanguage( 'FR' );
Copied!
@param string $targetLanguage Target language of the translation
@return self

| ➜ Go to source code of TranslationHelper::setTargetLanguage()

\nn\t3::TranslationHelper()->translate($key, $text = ''); 

Translate a text.

$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );
$translationHelper->setEnableApi( true );
$translationHelper->setTargetLanguage( 'EN' );
$text = $translationHelper->translate('my.example.key', 'This is the text to be translated');
Copied!

| @return string

| ➜ Go to source code of TranslationHelper::translate()

Methods 

TranslationHelper::createKeyHash() 

\nn\t3::TranslationHelper()->createKeyHash($param = ''); 

Generates a unique hash from the key that is required to identify a text. Each text has the same key in all languages.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['my', 'key', 'array'] );
Copied!

| @return string

Source Code 

public function createKeyHash( $param = '' ) {
	return md5(json_encode(['_'=>$param]));
}
Copied!

TranslationHelper::createTextHash() 

\nn\t3::TranslationHelper()->createTextHash($text = ''); 

Generates a unique hash / checksum from the text. The transferred text is always the base language. If the text in the base language changes, the method returns a different checksum. This recognizes when a text needs to be retranslated. Pure changes to whitespaces and tags are ignored.

$translationHelper->createKeyHash( '12345' );
$translationHelper->createKeyHash( ['my', '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(); 

Returns whether the API is enabled.

$translationHelper->getEnableApi(); // default: false
Copied!

| @return boolean

Source Code 

public function getEnableApi() {
	return $this->enableApi;
}
Copied!

TranslationHelper::getL18nFolderpath() 

\nn\t3::TranslationHelper()->getL18nFolderpath(); 

Returns the current folder in which the translation files are cached. Default is typo3conf/l10n/nnhelpers/

$translationHelper->getL18nFolderpath();
Copied!

| @return string

Source Code 

public function getL18nFolderpath() {
	return $this->l18nFolderpath;
}
Copied!

TranslationHelper::getL18nPath() 

\nn\t3::TranslationHelper()->getL18nPath(); 

Return the absolute path to the l18n cache file. Default is 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(); 

Gets the maximum number of translations to be made per instance.

$translationHelper->getMaxTranslations(); // default: 0 = infinite
Copied!

| @return integer

Source Code 

public function getMaxTranslations() {
	return $this->maxTranslations;
}
Copied!

TranslationHelper::getTargetLanguage() 

\nn\t3::TranslationHelper()->getTargetLanguage(); 

Gets the target language for the translation

$translationHelper->getTargetLanguage(); // Default: EN
Copied!

| @return string

Source Code 

public function getTargetLanguage() {
	return $this->targetLanguage;
}
Copied!

TranslationHelper::loadL18nData() 

\nn\t3::TranslationHelper()->loadL18nData(); 

Load complete language file.

$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 = []); 

Save complete language file

$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); 

Activates / deactivates the translation via 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); 

Sets the current folder in which the translation files are cached. The idea is to translate the translated texts for backend modules only once and then save them in the extension folder. From there they are then deployed to GIT.

Default is typo3conf/l10n/nnhelpers/

$translationHelper->setL18nFolderpath('EXT:myext/Resources/Private/Language/');
Copied!
@param string $l18nFolderpathPath to the folder with the translation files (JSON)
@return self

Source Code 

public function setL18nFolderpath($l18nFolderpath) {
	$this->l18nFolderpath = $l18nFolderpath;
	return $this;
}
Copied!

TranslationHelper::setMaxTranslations() 

\nn\t3::TranslationHelper()->setMaxTranslations($maxTranslations); 

Sets the maximum number of translations to be made per instance. Helps with debugging (so that the Deep-L quota is not exhausted by testing) and with TimeOuts if many texts need to be translated.

$translationHelper->setMaxTranslations( 5 ); // Abort after 5 translations
Copied!
@param $maxTranslations
@return self

Source Code 

public function setMaxTranslations($maxTranslations) {
	$this->maxTranslations = $maxTranslations;
	return $this;
}
Copied!

TranslationHelper::setTargetLanguage() 

\nn\t3::TranslationHelper()->setTargetLanguage($targetLanguage); 

Sets the target language for the translation

$translationHelper->setTargetLanguage( 'FR' );
Copied!
@param string $targetLanguage Target language of the translation
@return self

Source Code 

public function setTargetLanguage($targetLanguage) {
	$this->targetLanguage = $targetLanguage;
	return $this;
}
Copied!

TranslationHelper::translate() 

\nn\t3::TranslationHelper()->translate($key, $text = ''); 

Translate a text.

$translationHelper = \nn\t3::injectClass( \Nng\Nnhelpers\Helpers\TranslationHelper::class );
$translationHelper->setEnableApi( true );
$translationHelper->setTargetLanguage( 'EN' );
$text = $translationHelper->translate('my.example.key', 'This is the text to be translated');
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 /> 

This ViewHelper is not a separate ViewHelper that can be used in Fluid.

It serves as a base class for your own ViewHelper.

| $escapeOutput = false is set as the default. If XSS attacks could be a problem with your ViewHelper, this should be overwritten.

Use extend in your own ViewHelper to use it. Here is an example boilerplate with everything you need to get started:

registerArgument('title', 'string', 'info', false);
 }

 public static function renderStatic( array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext ) {

     // Simply use `$title` instead of `$arguments['title']`
     foreach ($arguments as $k=>$v) {
        ${$k} = $v;
     }

     // Render content between the ViewHelper tag
     if (!$title) $title = $renderChildrenClosure();

     // Example to get all current variables in the Fluid template
     // $templateVars = \nn\t3::Template()->getVariables( $renderingContext );

     return $title;
 }
}
Copied!

abstractTagBased 

Description 

<nnt3:abstractTagBased /> 

This ViewHelper is not a separate ViewHelper that can be used in Fluid. It serves as a base class for your own tag-based ViewHelper.

Use extend in your own ViewHelper to use it. Here is an example boilerplate with everything you need to get started:

registerArgument('title', 'string', 'info', 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 /> 

Get frontend user

Returns an array with the data of the backend user, also contains the user's settings.

{nnt3:backendUser.get(key:'uc.example')}
{nnt3:backendUser.get()->f:variable.set(name:'beUser')}
Copied!

color.convert 

Description 

<nnt3:color.convert /> 

Convert a color

{hex->nn:color.convert(to:'rgb')}
Copied!

content.column 

Description 

<nnt3:content.column /> 

Renders the contents of a column (colPos) of the backend layout. If no page ID is specified via pid, it uses the current page ID.

{nnt3:content.column(colPos:110)}
Copied!

With slide, the content element of the parent page is fetched if no content element exists in the column on the specified page.

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

The column content of an external page can be rendered with pid:

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

Slide also works for external pages:

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

| @return string

content.columnData 

Description 

<nnt3:content.columnData /> 

Loads the raw data of a column (colPos) of the backend layout.

This is the raw tt_content-data array of a column (colPos) from the backend layout. By default, the relations (FAL, assets, media...) are also loaded. Can be prevented via relations:0.

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

| @return array

contentElement 

Description 

<nnt3:contentElement /> 

Rendering a content element

The ViewHelper that we probably use most often.

Render content element from the table tt_content with the uid: 123.

{nnt3:contentElement(uid:123)}
Copied!

Render content element from the tt_content table where tt_content.content_uuid = 'footer'.

{nnt3:contentElement(uid:'footer', field:'content_uuid')}
Copied!

Replace variables in the rendered content element. Allows you to create a content element in the backend that works with fluid variables - e.g. for a mail template where the recipient's name should appear in the text.

{nnt3:contentElement(uid:123, data:'{greeting:\'Hello!\'}')}
{nnt3:contentElement(uid:123, data:feUser.data)}
Copied!

A contentUid does not necessarily have to be passed to render the variables. HTML code can also be parsed directly:

{data.bodytext->nnt3:contentElement(data:'{greeting:\'Hello!\'}')}
Copied!

| @return string

die 

Description 

<nnt3:die /> 

Does nothing, except to end the script.

This allows the script to be canceled during the rendering process of Fluid. Practical for debugging mail templates, for example.

{nnt3:die()}
Copied!

| @return death

encrypt.hash 

Description 

<nnt3:encrypt.hash /> 

Generates a hash from a string or a number.

{secret->nnt3:encrypt.hash()}
{nnt3:encrypt(value:secret)}
Copied!

Helpful if, for example, an email is to be sent with a confirmation link.

The UID of the data record is also transferred as a hash. The controller then checks whether the hash can be generated from the passed uid If not, the uid has been manipulated.

	
...
	
Copied!

| @return string

explode 

Description 

<nnt3:explode /> 

Turns a string into an 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 /> 

Get absolute URL to a file.

{nnt3:file.absPath(file:'path/to/image.jpg')}
Copied!

| @return string

file.exists 

Description 

<nnt3:file.exists /> 

Checks whether a file exists.

{nnt3:file.exists(file:'path/to/image.jpg')}
Copied!
	
Where did the image go?
	
Copied!

| @return boolean

file.include 

Description 

<nnt3:file.include /> 

Inserts the content of a file.

{nnt3:file.include(file:'path/to/file.html')}
Copied!

| @return string

flashMessages 

Description 

<nnt3:flashMessages /> 

Outputs a flash message.

In the controller:

\nn\t3::Message()->OK('Title', 'Infotext');
\nn\t3::Message()->setId('above')->ERROR('Title', 'Infotext');
Copied!

In the fluid:

	
	
Copied!

The core functions:

	
	
Copied!

| @return string

format.attrEncode 

Description 

<nnt3:format.attrEncode /> 

Masks "critical" characters so that they can be used as an attribute to an HTML tag.

... 
... 
Copied!

| @return string

format.code 

Description 

<nnt3:format.code /> 

Highlighted code sections via PrismJS.

The code can be made available for direct download via download.

The file is generated dynamically via JS and streamed - no additional files are created on the server. nnhelpers uses this function to offer the boilerplates as a download.

More information at: https://prismjs.com/

Build: https://bit.ly/3BLqmx0

	
... Markup ...
	
	
	
... Markup ...
	
Copied!

| @return string

format.htmlToSphinx 

Description 

<nnt3:format.htmlToSphinx /> 

Converts HTML tags to Sphinx syntax for the TER documentation.

{annotation->f:format.raw()->nnt3:format.htmlToSphinx()}
Copied!

From the following code ...

	
This is a description of this method
$a = 99;
	
Copied!
$a = 99;
Copied!

this is rendered here:

This is a description of this method

.. code-block:: php

   $a = 99;
Copied!

| @return string

format.indentCode 

Description 

<nnt3:format.indentCode /> 

Adds an indentation to each line of a code block. Used for the Sphinx documentation to correctly indent code within . code-block:: correctly.

{sourceCode->nnt3:format.indentCode(spaces: 3)}
Copied!

| @return string

format.jsonEncode 

Description 

<nnt3:format.jsonEncode /> 

Converts an array or object into JSON format.

{some.object->nnt3:format.jsonEncode()}
Copied!

| @return string

format.replace 

Description 

<nnt3:format.replace /> 

Search and replace text in a string.

{nnt3:format.replace(str:'alles schön im Juli.', from:'Juli', to:'Mai')}
{varname->nnt3:format.replace(from:'July', to:'May')}
Copied!

| @return string

frontendUser.get 

Description 

<nnt3:frontendUser.get /> 

Get frontend user

Returns an array with the data of the frontend user, e.g. to personalize pages, mails or content.

{nnt3:frontendUser.get(key:'first_name')}
{nnt3:frontendUser.get()->f:variable.set(name:'feUser')}
Copied!

image 

Description 

<nnt3:image /> 

Simplifies the use of the ImageViewhelper.

Does not throw an error if no image or src was passed. Also allows the transfer of an array, simply pulls the first image.

// tt_content.image is actually an array. It simply renders the first image!
{nnt3:image(image:data.image)}

// does not throw an error (if the editor has not uploaded an image!)
{nnt3:image(image:'')}
Copied!

page.data 

Description 

<nnt3:page.data /> 

Simplifies access to data from the pages table.

{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!

Important for slide to work: If a custom field has been added to the pages table, the field must first be registered in ext_localconf.php.

\nn\t3::Registry()->rootLineFields(['logo']);
Copied!

page.title 

Description 

<nnt3:page.title /> 

Set current page title.

Changes the ````-tag of the current page.

Does not work if EXT:advancedtitle is activated!

{nnt3:page.title(title:'Page title')}
{entry.title->nnt3:page.title()}
Copied!

pagination.paginate 

Description 

<nnt3:pagination.paginate /> 

Replacement for the f:widget.paginate ViewHelper, which was removed in TYPO3 12. THANK YOU to https://www.in2code.de/ for the blog post!

Include partial for the Paginator in your own extension

plugin.tx_myext_plugin {
partialRootPaths {
 10 = EXT:nnhelpers/Resources/Private/Partials/
}
}
Copied!

In the Fluid template:

	
	
	
...
	
	
	
	
Copied!

| @return string

pagination.uri 

Description 

<nnt3:pagination.uri /> 

UriViewHelper

parse.code 

Description 

<nnt3:parse.code /> 

Ensures HTML entities inside 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 /> 

Parses a FlexForm (XML) and turns it into an array.

Useful if you have a raw data record of the table tt_content in front of you and need a value from the FlexForm in pi_flexform.

{row.pi_flexform->nnt3:parse.flexForm()->f:debug()}
Copied!

| @return array

parse.json 

Description 

<nnt3:parse.json /> 

Converts a normal JavaScript object that is passed as a string into an array. Allows you to create configurations for sliders and other JS libraries in TypoScript and parse them later via JS.

See JsonHelper for examples.

{myConfig->nnt3:parse.json()->f:debug()}
Copied!
	
...
	
Copied!

| @return mixed

parse.markdown 

Description 

<nnt3:parse.markdown /> 

Converts a string to HTML with Markdown.

{myMarkdownCode->nnt3:parse.markdown()}
Copied!

| @return mixed

translate 

Description 

<nnt3:translate /> 

Translate a text, including optional translation via Deep-L.

See also the TranslationHelper documentation for integration via PHP or a controller.

// Translation via 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!
// translation via Deep-L
{nnt3:translate(id:'my-ll-id', text:'The 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!
// Translate a block in the Fluid template

  I will be translated automatically, including all HTML tags!
Copied!

ts.constants 

Description 

<nnt3:ts.constants /> 

Get value from the TypoScript constants.

Simple and direct access from the Fluid template - regardless of the extension that renders the template.

{nnt3:ts.constants(path:'path.to.constant')}
{nnt3:ts.constants(path:'path.zur', key:'constant')}
{nnt3:ts.constants(path:'path.{dynamicKey}.whatever')}
Copied!

| @return mixed

ts.extConf 

Description 

<nnt3:ts.extConf /> 

Get configuration for an extension from the extension manager.

{nnt3:ts.extConf(path:'nnfiletransfer.pathLogo')}
{nnt3:ts.extConf(path:'nnfiletransfer', key:'pathLogo')}
Copied!

| @return mixed

ts.page 

Description 

<nnt3:ts.page /> 

Get value from the PageTSconfig.

Simple and direct access from the Fluid template - regardless of the extension that renders the template.

{nnt3:ts.page(path:'path.zum.page.config')}
{nnt3:ts.page(path:'path.zum.page', key:'config')}
{nnt3:ts.page(path:'path.zum.page.{dynamicKey}.whatever')}
Copied!

| @return mixed

ts.setup 

Description 

<nnt3:ts.setup /> 

Get value from the TypoScript setup.

Simple and direct access from the Fluid template - regardless of the extension that renders the template.

{nnt3:ts.setup(path:'path.zum.typoscript.setup')}
{nnt3:ts.setup(path:'path.zum.typoscript', key:'setup')}
{nnt3:ts.setup(path:'path.zum.typoscript.{dynamicKey}.whatever')}
Copied!

| @return mixed

uniqid 

Description 

<nnt3:uniqid /> 

Returns a unique, one-time ID.

Useful e.g. for unique IDs or class names in Fluid templates.

{nnt3:uniqid()}
Copied!
... 
Copied!

| @return string

uri.image 

Description 

<nnt3:uri.image /> 

Simplifies the use of the Uri.ImageViewhelper.

Does not throw an error if no image or src was passed. Also allows the transfer of an array, simply pulls the first image.

// tt_content.image is actually an array. It simply renders the first image!
{nnt3:uri.image(image:data.image)}

// does not throw an error (if the editor has not uploaded an image!)
{nnt3:uri.image(image:'')}
Copied!

uri.page 

Description 

<nnt3:uri.page /> 

Generates a URL to a page in the frontend. Corresponds almost exactly to the Typo3 ViewHelper {f:uri.page()} - but can also be used in a context context where no frontend(TSFE) exists, e.g. in the template of a backend module or in the mail template of ascheduler job. mail templates of a scheduler job.

{nnt3:uri.page(pageUid:1, additionalParams:'...')}
Copied!

video.embedUrl 

Description 

<nnt3:video.embedUrl /> 

Converts a youTube URL into the watch variant, e.g. for embedding in an iFrame.

{my.videourl->nnt3:video.embedUrl()}
Copied!
<iframe src="{nnt3:video.embedUrl(url: my.videourl)}" frameborder="0" allowfullscreen></iframe>
Copied!

widget.accordion 

Description 

<nnt3:widget.accordion /> 

Widget for displaying an accordion.

Is used en masse in nnhelpers in the templates of the backend module.

	
...
	
Copied!
	
...
	
Copied!
{nnt3:widget.accordion(title:'title', content:'...' icon:'fas fa-plus', class:'nice-thing')}
Copied!

| @return string

Use Cases & Examples 

Debugging 

You might think: The Typo3 DebuggerUtility is great. Yes, it is.

But have you ever tried to debug a QueryBuilder-Statment? Or have you tried to find a debug command somewhere in your code that you forgot to remove and you can't remember in which class and method you had put it?

Here is the one thing that will get you addicted to nnhelpers. Even if you ignore the rest and go your own way. This is worth it:

\nn\t3::debug( $whatever );
Copied!

Creating Extensions 

Many small things make you wonder while you develop Typo3 extensions.

One of them is: When Typo3 switched to the IconRegistry way of registering icons in ext_tables.php – why do you have to first use the correct instance of the {Type}IconProvider to get the icon in its place? To much brain work.

So, here you go. Stop asking Google. Ask nnhelpers:

\nn\t3::Registry()->icon('my-icon-identifier', 'EXT:myext/Resources/Public/Icons/wizicon.svg');
Copied!

TCA nightmares 

Another one of my favorites: Defining FALs in the TCA. Remember the 28 lines of code for enabling the file select/upload in the TCA? Remember having to slightly change the syntax and structure with (almost) every major Typo3 update?

Well, here is your time-saver for your next FAL definition in the TCA:

'falprofileimage' => [
   'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage'),
],
Copied!

Ah, ok - your missing some options here? No problem:

'falprofileimage' => [
   'config' => \nn\t3::TCA()->getFileFieldTCAConfig('falprofileimage', ['maxitems'=>1, 'fileExtensions'=>'jpg']),
],
Copied!

And of course, there are lots more, like a oneliner for a Rich Text Editor (RTE).

If the core team decides to move away from ckeditor like they (fortunately) did with rtehtmlarea, then it won't be your problem anymore. It will be nnhelpers problem.

'mytextfield' => [
   'config' => \nn\t3::TCA()->getRteTCAConfig(),
],
Copied!

... or a color-picker:

'mycolor' => [
   'config' => \nn\t3::TCA()->getColorPickerTCAConfig(),
],
Copied!

Injecting a FlexForm in a TCA-field 

Well, let's go wild. Ever though of injecting an external FlexForm in a TCA?

Don't dream about it. Code it.

'myoptions' => [
   'config' => \nn\t3::TCA()->insertFlexForm('FILE:EXT:path/to/yourFlexForm.xml');
],
Copied!

Might sound crazy, but we actually need this all the time when extending the best extension ever developed for Typo3: Mask (EXT:mask).

In the following example, we had about 30 slider-options for transition-types, duration, resposiveness etc. Every option is selectable in the plugin by the user. With plain old mask this would mean extending the tt_content-table by 30 fields. Fields, that have no other logic connected to them(searchability, indexing, sorting etc.). A one-time-shot for rendering the content-element – and therefore a clear case for a FlexForm.

Mask doesn't allow injecting a FlexForm (yet). So here is what we do in Configuration/TCA/Overrides/tt_content.php. (Make sure to define a dependency from your extension to mask!)

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 pimping 

One thing we love to do is make the values in a FlexForm configurable over TypoScript Setup oder the pageTSConfig, e.g. to let the user see different options in the dropdown of a flexform (or TCA), depending on the rootline he is on in the backend.

Look at this nice Helper:

<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!

Ah, right. And then there was that thing about inserting a select-field for all countries.

<config>
   <type>select</type>
   <renderType>selectSingle</renderType>
   <items type="array"></items>
   <itemsProcFunc>nn\t3\Flexform->insertCountries</itemsProcFunc>
   <insertEmpty>1</insertEmpty>
</config>
Copied!

Sending Mails 

Great. Typo3 just removed SwiftMailer. We went through this already a few years ago, when Typo3 switched TO SwiftMailer. We have the mail-function scattered over 562 extensions. Thanks.

And, nope, sorry, we DON'T spend hours reading the breaking changes everytime we have to do an update. We upgrade the core, put on our helmets and safety-belts and see what happens. Google will somehow cut us out of the accident scene.

Good to know, some things never change.

\nn\t3::Mail()->send([
   'html'	=> $html,
   'fromEmail'	=> 'me@somewhere.de',
   'toEmail'	=> 'you@faraway.de',
   'subject'	=> 'Nice'
]);
Copied!

Worried about Outlook? Don't worry. Emogrifier is helping nnhelper as default settings.

Want to add attachments?

\nn\t3::Mail()->send([
   ...
   'attachments' => ['path/to/file.jpg', 'path/to/other.pdf']
]);
Copied!
What about adding attachments (or inline-images) from your Fluid mail-template?
Add data-embed="1" to your image or link. nn\t3::Mail() will take care of the hard work.
<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!

Rendering Fluid 

In the Mail-examples above we forgot to talk about the StandaloneView for rendering Templates. Of course, nnhelpers makes life easier here, too:

\nn\t3::Template()->render( 'path/to/template.html', $vars );
Copied!

But, right, then there was that thing about setting the partialRootPaths, layoutRootPaths etc. As you probably have noticed yourself, most of the time, you are in an extension when using the StandaloneView. And most of the time you want to use the view settings defined in the TypoScript-Setup for this extension.

\nn\t3::Template()->render( 'Templatename', $vars, 'myext' );
Copied!

But then again, what if you need other partialRootPaths for rendering?

\nn\t3::Template()->render( 'Templatename', $vars, [
   'templateRootPaths' => ['EXT:myext/Resource/Somewhere/Templates/', ...],
   'layoutRootPaths' => ['EXT:myext/Resource/Somewhere/Layouts/', ...],
]);
Copied!

Let's put it this way: There is no wrong way to use nnhelpers. Think simple and intuitive. Do what seems logical to you. Most of the time, we will have had the same idea.

Importing data from one extension to another 

We recently updated a major project from Typo3 7 LTS to Typo3 10 LTS. The project used Calendar Base (EXT:cal) and had over 5.000 calender-entries. Unfortunatly EXT:cal had not been updated to work with Typo3 10 so we decided to switch to our own calendar extension nncalendar (which will be released for public in a few weeks).

But here we faced three main challenges:

  • It was impossible to activate EXT:cal in Typo3 10 - consequently there was no simple way to access the database-tables of Calendar Base or create "nice" Models with getters and setters
  • Calendar Base hat not migrated their calendar categories to the sys_category yet.
  • There were tons of raw images in the uploads/pic/ folder which needed to be converted to FAL images and attached to the new EntryModel of nncalendar

Here is the essence of what we came up with:

// Get all rows as array from the Calendar Base table. EXT:cal does NOT need to activated!
$calData = \nn\t3::Db()->statement( "SELECT * FROM tx_cal_event WHERE deleted = 0");

// This is the Repository we're aiming at
$calendarRepository = \nn\t3::injectClass(\Nng\Nncalendar\Domain\Repository\EntryRepository::class);

// Create NnCalendar-Models from the raw array-data
foreach ($calData as $row) {

   // [...] we had a few lines of code here for parsing and converting the date etc.

   $entry = \nn\t3::Convert($row)->toModel( \Nng\Nncalendar\Domain\Model\Entry::class );
   $calendarRepository->add( $entry );
}

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

Even setting the new SysCategories in the new Model was as simple as:

$row['category'] = [1, 4, 3];
$entry = \nn\t3::Convert($row)->toModel( \Nng\Nncalendar\Domain\Model\Entry::class );
Copied!

nnhelpers automatically recognizes, that the Entry-Model has SysCategories related to the field category and will create the according relations and ObjectStorage on-the-fly.

No different approach with migrating the images:

// 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!

nnhelpers automatically recognizes, that falImage is defined as a FAL or ObjectStorage in the Entry-Model and creates the sys_file and sys_file_reference which it then attaches to the model.

So, what are YOU going to do the rest of the day?

Database operations 

I can't remember how many times we just wanted to do a direct and straightforward update, delete or insert of individual records in a database table - without digging through the docs again and again.

Here is a small excerpt from the nn\t3::Db() methods that save us time every day:

Get data for the FrontendUser with uid = 12

$feUser = \nn\t3::Db()->findByUid('fe_user', 12);
Copied!

Ignore the enable-fields (hidden, start_time etc.)

$feUser = \nn\t3::Db()->findByUid('fe_user', 12, true);
Copied!

Get all entries from the table tx_news_domain_model_news

$news = \nn\t3::Db()->findAll('tx_news_domain_model_news');
Copied!

Get all Frontend-Users named Donny

$feUser = \nn\t3::Db()->findByValues('fe_users', ['first_name'=>'Donny']);
Copied!

Get the first Frontend-Users named Peter

$feUser = \nn\t3::Db()->findOneByValues('fe_users', ['first_name'=>'Peter']);
Copied!

Ignore the storagePid for a Repository

$myRepo = \nn\t3::injectClass( MyRepo::class );
\nn\t3::Db()->ignoreEnableFields( $myRepo );
Copied!

Ignore the storagePid and hidden-Flag for a Repository

$myRepo = \nn\t3::injectClass( MyRepo::class );
\nn\t3::Db()->ignoreEnableFields( $myRepo, true, true );
Copied!

Side-by-Side 

Still not believing, that this Extension could completely change the way you have been working on Typo3 projects up until now?

Let's have a look at some of the everyday tasks you have been implementing over and over again. Compare not only the number of code-lines involved in getting the job done – but also the brain-energy needed to memorize the steps, methods and parameters required in the direct comparison.

Also pay attention to how the main concept of building links in the backend context has changed from Version 8 to 9. Sure: Things have definately gotten better. But think of the time you would have spent to find this solution and update it in all of you extensions.

Then look at the nnhelpers one-liner on the right side. See the difference between building links in the frontend or backend context? Any difference in building the links from version 8 LTS to 9 LTS?

I think you understand, what we are talking about.

Getting the TypoScript Setup outside of the Controller 

Task: You need to get the demo.path value from the TypoScript setup of a plugin, but you are not in a context where you could simply do a $this->settings to retrieve it.

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!

WITH nnhelpers

$value = \nn\t3::Settings()->get('my_ext_table', 'demo.path');
Copied!

Retrieving data from a table 

Task: Get one row of raw data from the database table by its 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!

WITH nnhelpers

\nn\t3::Db()->findByUid('my_ext_table', 99);
Copied!

Retrieving data from a table 

Task: Get the raw data of a database table and ignore the hidden field and start/endtime restrictions i.e. to simply export it as CSV or iterate through it.

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!

WITH nnhelpers

\nn\t3::Db()->findAll('my_ext_table', true);
Copied!

Screenshots 

We are currently translating all the comments, annotations and descriptions in to English. Update coming soon!

Many, many time-savers 

nnhelpers Backend Module

Quick search function 

nnhelpers Backend Module

View source code in backend 

nnhelpers Backend Module

Download Boilerplates 

nnhelpers Backend Module

Smart namespacing 

nnhelpers Backend Module

Change log 

Version 1.0.0 

First public release after many years of development and improvement.

Known Problems 

Unfortunalety tons of problems related to the big, red warning on this page

Helpers for WordPress 

We have a vision. 

What if there was a similar collection of "helpers" for other content management systems? If the methods were even (almost) congruent? If a developer could simply "jump" between Joomla, WordPress, Drupal, NodeJS and TYPO3 without having to learn other concepts and core APIs over and over again.

This is the idea behind nnhelpers - with the long term goal to make even a large part of the code reusable between different CMS. Sure: This is a dream and it comes with hurdles. But just knowing: There are \nn\t3::debug() or \nn\t3::Db()->findAll() or \nn\t3::Environment()->getBaseUrl() - and this command is framework-spanning the same would already be a big help. No matter if you really want to implement nnhelpers then - or simply just use it as a cheat sheet to see how the function is implemented in detail within the respective system.

We set a starting point in 2022 and started to bring wphelpers to life: A mirror of nnhelpers for WordPress!

nng/wphelpers on packagist | WpHelpers in GIT on bitbucket.org

Using TYPO3Fluid as rendering engine in WordPress 

What was one of our first steps and methods of wphelpers? Getting a decent template engine up and running. WordPress relies on PHP-templating - from the point of view of a Fluid- or Twig-accustomed developer this feels like a anachronistic disaster.

With wphelpers you can now use this nice line within your WordPress plugin:

\nn\wp::Template()->render('EXT:my_wp_plugin/path/to/template.php', ['demo'=>123]);
Copied!

... and use it to render a fluid template! Thanks to the community who made Fluid available as a standalone version. And since Fluid is still one of the best template engines out there - why not "upgrade" WordPress with it? Now all templates of the TYPO3 extensions are reusable in WordPress!

And the performance? WordPress always argues that nothing is more performant than a PHP template. But if you know Fluid in depth, you knows that all templates are "translated" into pure PHP code and cached (same with Smarty etc.). So there will be hardly any difference in performance.

Let's do it! 

If there are other teams out there, who move in the parallel universes between TYPO3, WordPress etc. and find this idea interesting: What do you think about it? Feel like getting in on the action? Do you want to translate a method from nnhelpers into another system? into another system? Let's start the revolution ;)

We are looking forward to your feedback!

Sitemap