TYPO3 LTS 9
Aus Vosp.info
Version vom 26. März 2019, 17:38 Uhr von F (Diskussion | Beiträge) (→Sprache der Backend core Labels übersetzen)
- https://forge.typo3.org/attachments/download/33482/TYPO3-v9-2-whats-new.german.pdf
- https://blog.comwrap.com/typo3-version-9-die-wichtigsten-features-des-major-releases
- https://jweiland.net/typo3/versionen-und-updates/version-9.html
- https://forge.typo3.org/attachments/download/33888/TYPO3-v9-LTS-whats-new.german.pdf
Inhaltsverzeichnis
- 1 Benötigte Software & Konfiguration
- 2 Typo3 Grundinstallation
- 3 Module
- 4 Entwicklung
- 5 Extensions
- 6 netz.coop Extensions
- 7 Speaking URLS
- 8 Source Code Änderungen - deprecated ...
- 9 Query Builder
- 10 Wenn Querybuilder keine Option ist
Benötigte Software & Konfiguration
apt-get install imagemagick wget bash-completion zip unzip apache2 libapache2-mod-php7.2 php7.2-cli php7.2 php7.2-common php7.2-imap php7.2-intl php7.2-mysql php7.2-readline php7.2-soap php7.2-zip php7.2-zip php7.2-gd php7.2-xml php7.2-gd php7.2-json php7.2-opcache php-imagick php7.2-curl php7.2-mbstring php7.2-bcmath php7.2-gmp php7.2-zip mysql-server composer
a2enmod deflate rewrite headers mime expires ssl
mysql_secure_installation
USE mysql;
UPDATE user SET plugin='mysql_native_password' WHERE User='root';
FLUSH PRIVILEGES;
exit;
#Falls Die Sicherheit für Passwörte nachträglich geändert werden muss.
mysql$ SHOW VARIABLES LIKE 'validate_password%';
mysql$ SET GLOBAL validate_password_policy=LOW;
vim /etc/mysql/mysql.conf.d/mysqld.cnf
#add
[mysqld]
validate_password_policy=LOW
Typo3 Grundinstallation
cd in /var/www/domain
git clone https://github.com/TYPO3/TYPO3.CMS.git
cd TYPO3.CMS/
git fetch --tags
git tag --list
git checkout tags/v.9.5.1
#Externe Bibliotheken installieren
composer install
cd ..
ln -s TYPO3.CMS typo3_src
ln -s typo3_src/typo3 typo3
ln -s typo3_src/index.php .
touch FIRST_INSTALL
# /etc/php/7.2/apache2/php.ini
max_execution_time = 240
max_input_vars = 1500
Module
Sites
Sprachen lanugages
- https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/SiteHandling/Basics.html
- https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/Internationalization/ManagingTranslations.html
- https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/SiteHandling/AddLanguages.html#
Achtung, derzeit existiert ein language fallback BUG :( https://forge.typo3.org/issues/86762 Seiten welche noch nicht übersetzt sind, kommen auf ne 404 Seite
- erstmal müssen Sprachen angelegt werden auf der Seite 0 (ganz ganz oben in der Seiten Hierrachie) ... dann kann angefangen werden Sprachen über Sites zu konfigurieren
- die Startseite (auch wenn nur Verweis) muss übersetzt werden mit dem Seiten oder Listen Modul
page = PAGE
page {
10 = FLUIDTEMPLATE
10 {
dataProcessing {
120 = TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor
120 {
languages = auto
as = ncMenuLanguage
}
}
}
}
Entwicklung
Fehlermeldungen (unvollstängig)
class CaptchaValidator extends AbstractValidator
// .........
public function isValid($word)
{
// .........
if (!$isValid) {
// Please enter the word or number as it appears in the image. The entered value was incorrect.
$this->addError(
$this->translateErrorMessage(
'9221561048',
'sr_freecap'
),
9221561048
);
}
return $isValid;
}
}
alle Fehler anzeigen die so existieren
<f:render partial="FormErrors" arguments="{for: 'user'}" />
speziellen Fehler anzeigen
<f:render partial="FieldError" arguments="{for: 'user', field: 'captcha'}" />
Ableiten
Controller ableiten
TYPO3.CMS_7.6_Schnipsel#Backend_Klassen_ableiten
- EXT/ancregister/Classes/Controller/NcFeuserEditController.php
<?php
namespace Netzcoop\Ancregister\Controller;
class NcFeuserEditController extends \Evoweb\SfRegister\Controller\FeuserEditController {
public function formAction(\Evoweb\SfRegister\Domain\Model\FrontendUser $user = null)
{
parent::formAction($user);
}
}
- ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['Evoweb\SfRegister\Controller\FeuserEditController'] = array(
'className' => 'Netzcoop\Ancregister\Controller\NcFeuserEditController'
);
Sprache
Extension Sprache verändern
- Configuration/TypoScript/setup.txt
plugin.tx_sfregister._LOCAL_LANG.de {
error_required = Bitte füllen Sie dieses Feld aus.
}
Sprache der Backend core Labels übersetzen
zum Beispiel im Backend unter Listen Modul die Spalten
- EXT:ancextension/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:core/Resources/Private/Language/locallang_core.xlf'][] = 'EXT:ancextension/Resources/Private/Language/de.locallang_ancbe.xlf';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:frontend/Resources/Private/Language/locallang_tca.xlf'][] = 'EXT:ancextension/Resources/Private/Language/de.locallang_ancbe.xlf';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride']['EXT:core/Resources/Private/Language/locallang_general.xlf'][] = 'EXT:ancextension/Resources/Private/Language/de.locallang_ancbe.xlf';
- EXT:ancextension/Resources/Private/Language/de.locallang_ancbe.xlf
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
<file source-language="en" datatype="plaintext" original="messages" date="2019-03-26T18:44:59Z" product-name="lang">
<header/>
<body>
<trans-unit id="LGL.enabled" xml:space="preserve">
<target>XXXXXXXXXXXXX</target>
</trans-unit>
<trans-unit id="fe_users.lockToDomain" xml:space="preserve">
<target>YYYYYYYYYYYYYYYYY</target>
</trans-unit>
<trans-unit id="labels.toggleall" xml:space="preserve">
<target>Alle auswählen</target>
</trans-unit>
<trans-unit id="rm.closeDoc" xml:space="preserve">
<target>Speichern und Schließen</target>
</trans-unit>
</body>
</file>
</xliff>
debuggen
sql queries
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
$frontendUserRepository = $objectManager->get('TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository');
$users = $frontendUserRepository->findAll();
$queryParser = $objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
krexx($queryParser->convertQueryToDoctrineQueryBuilder($frontendUserRepository->createQuery())->getSQL());
// ....
$rows = $qB->execute()->fetchAll();
krexx($qB->getSQL());
Einstellungen einer Extension
- sie befindet sich nicht mehr im Module Extension Manager sondern im Module Einstellungen, desweiteren wird sie durch De- und Neuinstallation der Extension die Einstellungen gelöscht!!! was sehr nervig sein kann
- ext_conf_template.txt
# cat=basic/enable/010;; type=int+; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.showsentmailinfoPageId
showsentmailinfoPageId =
# cat=basic/enable/016;; type=int+; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.showAfterEmailloginPageId
showAfterEmailloginPageId =
# cat=basic/enable/020;; type=int+; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.forgotTimeForDeactivateLogin
forgotTimeForDeactivateLogin =
# cat=basic/enable/030;; type=string; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.mailsubject
mailsubject =
# cat=basic/enable/040;; type=string; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.mailsender
mailsender =
# cat=basic/enable/050;; type=user[Netzcoop\Ancfeloginaddon\ViewHelpers\TextArea->render]; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.mailtext
mailtext =
# cat=basic/enable/017;; type=options[gleich=0,ungleich=1]; label=LLL:EXT:ancfeloginaddon/Resources/Private/Language/locallang_be.xml:basic.emailcondition2
emailcondition2 =
$confArray = unserialize($GLOBALS["TYPO3_CONF_VARS"]["EXT"]["extConf"][strtolower($this->extensionName)]);
Scheduler
- TYPO3.CMS 6.2 Extension entwickeln - Cron Scheduler
- https://docs.typo3.org/typo3cms/extensions/scheduler/DevelopersGuide/CreatingTasks/Index.html
Task
- Classes/Task/NcIndexTtnewsPdffilesForSearchTask.php
<?php
namespace Netzcoop\Ancext\Task;
/**
* Description of NcIndexTtnewsPdfFilesForSearch
*
* @author nc
*/
class NcIndexTtnewsPdffilesForSearchTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
/**
* @var string
*/
protected $commandIdentifier;
/**
* @var array
*/
protected $arguments = [];
/**
* Function execute from the Scheduler
*
* @return bool TRUE on successful execution
*/
public function execute() {
krexx($this->getArguments());
// ...
return true;
}
/**
* @param array $arguments
*/
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
/**
* @return array
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Return a text representation of the selected command and arguments
*
* @return string Information to display
*/
public function getAdditionalInformation()
{
$label = "spezielle Parameter: \n";
foreach($this->commandIdentifier as $key => $value ) {
$label .= "\t".$key.': '.$value."\n";
}
return $label;
}
/**
* @param string $commandIdentifier
*/
public function setCommandIdentifier($commandIdentifier)
{
$this->commandIdentifier = $commandIdentifier;
}
/**
* @return string
*/
public function getCommandIdentifier()
{
return $this->commandIdentifier;
}
}
AdditionalFieldProvider
diese Klasse ist für das Formular innerhalb eines Task zuständig, Felder werden definiert, validiert und gespeichert!
- Classes/Task/NcIndexTtnewsPdffilesForSearchAdditionalFieldProvider.php
<?php
namespace Netzcoop\Ancext\Task;
class NcIndexTtnewsPdffilesForSearchAdditionalFieldProvider extends \TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider {
/**
* @var \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager
*/
protected $commandManager;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
*/
protected $reflectionService;
/**
* @var \TYPO3\CMS\Extbase\Scheduler\Task
*/
protected $task;
/**
* Default language file of the extension linkvalidator
*
* @var string
*/
protected $languageFile = 'LLL:EXT:ancext/Resources/Private/Language/locallang.xlf';
const EXT_KEY = 'ancext_task';
/**
* Constructor
*
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
* @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
*/
public function __construct(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager = null, \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager = null, \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService = null)
{
$this->objectManager = $objectManager ?? \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
$this->commandManager = $commandManager ?? $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\CommandManager::class);
$this->reflectionService = $reflectionService ?? $this->objectManager->get(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
}
/**
* Render additional information fields within the scheduler backend.
*
* @param array &$taskInfo Array information of task to return
* @param AbstractTask|null $task When editing, reference to the current task. NULL when adding.
* @param SchedulerModuleController $schedulerModule Reference to the calling object (BE module of the Scheduler)
* @return array Additional fields
* @see \TYPO3\CMS\Scheduler\AdditionalFieldProvider#getAdditionalFields($taskInfo, $task, $schedulerModule)
*/
public function getAdditionalFields(array &$taskInfo, $task, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $schedulerModule)
{
$this->task = $task;
if ($this->task !== null) {
$this->task->setScheduler();
}
$argumentValues = $this->task->getArguments();
$fields = [];
$fields['ancext_task_description'] = $this->getCommandControllerActionDescriptionField();
$fieldname = 'newsFilePath';
$fields[$fieldname] = [
'code' => '<input type="text" class="form-control" name="tx_scheduler['.self::EXT_KEY.'][arguments]['.htmlspecialchars($fieldname).']" value="' . $argumentValues[$fieldname] . '">',
'label' => $this->languageFile.':ncIndexTtnewsPdffilesForSearchTask.field.newsFilePath',
'cshKey' => '',
'cshLabel' => $fieldname
];
return $fields;
}
/**
* Get description of selected command
*
* @return array
*/
protected function getCommandControllerActionDescriptionField()
{
return [
'code' => '',
'label' => $this->languageFile.':ncIndexTtnewsPdffilesForSearchTask.description'
];
}
public function validateAdditionalFields(array &$submittedData, \TYPO3\CMS\Scheduler\Controller\SchedulerModuleController $parentObject)
{
if(is_dir($submittedData[self::EXT_KEY]['arguments']['newsFilePath'])
|| is_dir(\TYPO3\CMS\Core\Core\Environment::getPublicPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'])
|| is_dir(\TYPO3\CMS\Core\Core\Environment::getProjectPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'])
) {
return true;
} else {
$this->addMessage(
$GLOBALS['LANG']->sL($this->languageFile . ':ncIndexTtnewsPdffilesForSearchTask.field.newsFilePath.error')
.'( '.$submittedData[self::EXT_KEY]['arguments']['newsFilePath']
.' || '.\TYPO3\CMS\Core\Core\Environment::getPublicPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath']
.' || '.\TYPO3\CMS\Core\Core\Environment::getProjectPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath']
.' )'
,
\TYPO3\CMS\Core\Messaging\FlashMessage::ERROR
);
return false;
}
}
public function saveAdditionalFields(array $submittedData, \TYPO3\CMS\Scheduler\Task\AbstractTask $task)
{
if(is_dir(\TYPO3\CMS\Core\Core\Environment::getPublicPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'])) {
$submittedData[self::EXT_KEY]['arguments']['newsFilePath'] = \TYPO3\CMS\Core\Core\Environment::getPublicPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'];
} else if(is_dir(\TYPO3\CMS\Core\Core\Environment::getProjectPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'])) {
$submittedData[self::EXT_KEY]['arguments']['newsFilePath'] = \TYPO3\CMS\Core\Core\Environment::getProjectPath().'/'.$submittedData[self::EXT_KEY]['arguments']['newsFilePath'];
}
$task->setCommandIdentifier($submittedData[self::EXT_KEY]['arguments']);
$task->setArguments((array)$submittedData[self::EXT_KEY]['arguments']);
}
}
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\Netzcoop\Ancext\Task\NcIndexTtnewsPdffilesForSearchTask::class] = array(
'extension' => $_EXTKEY,
'title' => 'LLL:EXT:'.$_EXTKEY.'/Resources/Private/Language/locallang.xlf:ncIndexTtnewsPdffilesForSearchTask.name',
'description' => 'LLL:EXT:'.$_EXTKEY.'/Resources/Private/Language/locallang.xlf:ncIndexTtnewsPdffilesForSearchTask.description',
'additionalFields' => \Netzcoop\Ancext\Task\NcIndexTtnewsPdffilesForSearchAdditionalFieldProvider::class
);
Backend
javascript im iframe im Backend einbinden
(Lösung von TYPO3.CMS_7.6_Schnipsel#Javascript_in_Iframe_im_Backend funzt nicht mehr )
- ext_localconf.php
<?php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['TYPO3\CMS\Backend\Form\FormResultCompiler'] = array(
'className' => 'Netzcoop\Extensionsname\Form\NcFormResultCompiler'
);
- extensionsname/Classes/Form/NcFormResultCompiler.php
<?php
namespace Netzcoop\Extensionsname\Form;
class NcFormResultCompiler extends \TYPO3\CMS\Backend\Form\FormResultCompiler {
public function printNeededJSFunctions() {
$pageRenderer = $this->getPageRenderer();
$pageRenderer->addJsFile('EXT:ancextensionname/Resources/Public/JavaScript/ancbackendIframe.js');
return parent::printNeededJSFunctions();
}
}
Extensions
scheduler
über EM Local
vhs
über EM Repository
includekrexx
über EM Repository
ws_scss
git clone https://github.com/svewap/ws_scss.git
gridelements
git clone https://github.com/TYPO3-extensions/gridelements.git
t3sbootstrap
- über https://www.t3sbootstrap.de/typo3-95/
- Konfiguration
- Einstellungen > Extension Configuration > t3sbootstrap > Custom SCSS
- Custom SCSS activate (clear cache and run Scheduler).
- Wartung > Flush TYPO3 and PHP Cache
- Scheduler
- Add task
- Class: T3SB Custom Scss - write a custom scss file
- Type: Single
- TASK "T3SB Custom Scss - write a custom scss file (t3sbootstrap)" ausführen
- Add task
- T3SB Config > nctypo9 (s. TYPO3_LTS_9#Beispiel_Seitenbaum) > New main configuration
- Einstellungen > Extension Configuration > t3sbootstrap > Custom SCSS
lang (Sprache)
Die Sprachkonfiguration wurde in das installtool verlegt
alte Extension Anpassungen
@inject => @TYPO3\CMS\Extbase\Annotation\Inject
@ignorevalidation => @TYPO3\CMS\Extbase\Annotation\IgnoreValidation
render Mode deprecated
<f:flashMessages renderMode="div" />
<f:flashMessages />
htmlEscape="false" deprecated
<f:translate key="email_user_salutation" htmlEscape="false"/>
<f:translate key="email_user_salutation" />
<f:translate key="email_user_salutation" htmlEscape="false"/>,
netz.coop Extensions
anclib
ancbasic
Konfiguration:
Beispiel Seitenbaum
id:0 nctypo
- id:1; Typ: Standard; Verhalten: Als Anfang der Website benutzen; Ressourcen: ancbasic; Erscheinungsbild > Backend-Layout ancbasic layout template; add Template enthält fluid_styled_content,gridelements, t3sbootstrap, anclib, ancbasic
- id:2; Typ: Ordner; Name: menu_main
- id:4: Typ: Seite; Name: Seite 1
- id:5: Typ: Seite; Name: Seite 2
- id:7: Typ: Seite; Name: Seite 2.1
- id:8: Typ: Seite; Name: Seite 2.2
- id:9: Typ: Seite; Name: Seite 2.3
- id:6: Typ: Seite; Name: Seite 3
- id:3; Typ: Ordner; Name: menu_footer
- id:10: Typ: Seite; Name: Kontakt
- id:11: Typ: Seite; Name: Impressum
- id:12: Typ: Seite; Name: Sitemap
- id:13: Typ: Seite; Name: Datenschutz
- id:2; Typ: Ordner; Name: menu_main
Speaking URLS
Site management => Sites
Source Code Änderungen - deprecated ...
@TYPO3\CMS\Extbase\Annotation\Inject not @inject
Query Builder
Klassen
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
queryBuilder
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tt_news');
FROM
$qB = $queryBuilder->from('tt_news', 'n');
WHERE
$qB->where(
$queryBuilder->expr()->eq('pid', (int) $store_page_id)
);
$qB->andWhere(
' n.ncindexcontent like \'%' . $searchword . '%\' '
);
Komplexe Abfragen
join
$qB->join(
'n',
'tt_news_cat_mm',
'p2c' . $join_i,
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('p2c' . $join_i . '.uid_local', $queryBuilder->quoteIdentifier('n.uid')),
$queryBuilder->expr()->in('p2c' . $join_i . '.uid_foreign', trim(implode(",", $ORCategoriesArray),','))
)
);
Equal
$qB->andWhere(
$qB->expr()->eq('mm.uid_local', $uid)
);
Equal OR Equal
$qB->andWhere(
$qB->expr()->orX(
$qB->expr()->eq('nc.parent_category', 1),
$qB->expr()->eq('nc.uid', 2)
)
);
LIKE =
$qB->where(
$qB->expr()->like(
'email',
$qB->createNamedParameter('%' . $qB->escapeLikeWildcards($domain) . '%')
)
);
Limit
$qB->setMaxResults(10);
Offset
$qB->setFirstResult(20);
Select
$qB->select('*', 'n.uid as uid');
Order By
$qB->orderBy('crdate', 'DESC');
Ausführen
$rows = $qB->execute()->fetchAll();
Count Distinct AS COUNT
$qB->addSelectLiteral(
$queryBuilder->expr()->count('n.uid', 'count')
);
Count Ausführen
$rows = $qB->execute()->fetch();
Wenn Querybuilder keine Option ist
Klassen
use TYPO3\CMS\Core\Database\ConnectionPool;
Individuelle SELECT Abfragen
protected $connectionPool;
/**
* @param string $table
*
* @return \TYPO3\CMS\Core\Database\Connection
*/
protected function getConnection(string $table)
{
if (empty($this->connectionPool)) {
$this->connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
}
return $this->connectionPool->getConnectionForTable($table);
}
...
$statement = 'SELECT * fe_users.email from fe_users WHERE activated_on>0 ORDER BY domains ASC';
$rows= $this->getConnection('fe_users')->executeQuery($statement)->fetchAll(\PDO::FETCH_BOTH);