diff --git a/CodeExamples/localPackages/example_extension/Classes/Controller/ExampleController.php b/CodeExamples/localPackages/example_extension/Classes/Controller/ExampleController.php
index 983a635..ae243d5 100644
--- a/CodeExamples/localPackages/example_extension/Classes/Controller/ExampleController.php
+++ b/CodeExamples/localPackages/example_extension/Classes/Controller/ExampleController.php
@@ -31,6 +31,6 @@ class ExampleController extends ActionController
// Comment the code out, to use fluid template from
// "Resources/Private/Templates/Example/Example.html"
- // return 'Hello world!';
+ return 'Hello world!';
}
}
diff --git a/CodeExamples/localPackages/example_extension/Classes/Domain/Model/Address.php b/CodeExamples/localPackages/example_extension/Classes/Domain/Model/Address.php
new file mode 100644
index 0000000..304206d
--- /dev/null
+++ b/CodeExamples/localPackages/example_extension/Classes/Domain/Model/Address.php
@@ -0,0 +1,87 @@
+
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+
+class Address extends AbstractEntity
+{
+ /**
+ * @var string
+ */
+ protected $companyName;
+
+ /**
+ * @var string
+ */
+ protected $street;
+
+ /**
+ * @var string
+ */
+ protected $houseNumber;
+
+ /**
+ * @var string
+ */
+ protected $zip;
+
+ /**
+ * @var string
+ */
+ protected $city;
+
+ /**
+ * @var string
+ */
+ protected $country;
+
+ public function getCompanyName(): string
+ {
+ return $this->companyName;
+ }
+
+ public function getStreet(): string
+ {
+ return $this->street;
+ }
+
+ public function getHouseNumber(): string
+ {
+ return $this->houseNumber;
+ }
+
+ public function getZip(): string
+ {
+ return $this->zip;
+ }
+
+ public function getCity(): string
+ {
+ return $this->city;
+ }
+
+ public function getCountry(): string
+ {
+ return $this->country;
+ }
+}
diff --git a/CodeExamples/localPackages/example_extension/Classes/Domain/Repository/AddressRepository.php b/CodeExamples/localPackages/example_extension/Classes/Domain/Repository/AddressRepository.php
new file mode 100644
index 0000000..506d745
--- /dev/null
+++ b/CodeExamples/localPackages/example_extension/Classes/Domain/Repository/AddressRepository.php
@@ -0,0 +1,29 @@
+
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+use TYPO3\CMS\Extbase\Persistence\Repository;
+
+class AddressRepository extends Repository
+{
+
+}
diff --git a/CodeExamples/localPackages/example_extension/Configuration/TCA/tx_exampleextension_domain_model_address.php b/CodeExamples/localPackages/example_extension/Configuration/TCA/tx_exampleextension_domain_model_address.php
new file mode 100644
index 0000000..6af4230
--- /dev/null
+++ b/CodeExamples/localPackages/example_extension/Configuration/TCA/tx_exampleextension_domain_model_address.php
@@ -0,0 +1,101 @@
+ [
+ 'label' => 'company_name',
+ 'default_sortby' => 'company_name',
+ 'tstamp' => 'tstamp',
+ 'crdate' => 'crdate',
+ 'cruser_id' => 'cruser_id',
+ 'title' => $extensionLanguagePrefix . 'address',
+ 'delete' => 'deleted',
+ 'enablecolumns' => [
+ 'disabled' => 'hidden',
+ 'starttime' => 'starttime',
+ 'endtime' => 'endtime'
+ ],
+ 'searchFields' => 'company_name, street, city'
+ ],
+ 'interface' => [
+ 'showRecordFieldList' => 'company_name, street, house_number, zip, city, country'
+ ],
+ 'palettes' => [
+ 'address' => [
+ 'showitem' => implode(',', [
+ 'street, house_number',
+ '--linebreak--',
+ 'zip, city',
+ '--linebreak--',
+ 'country',
+ ]),
+ ],
+ ],
+ 'types' => [
+ '0' => [
+ 'showitem' => implode(',', [
+ '--div--;' . $coreLanguagePrefix . 'general',
+ 'company_name;;address',
+ ]),
+ ],
+ ],
+ 'columns' => [
+ 'company_name' => [
+ 'label' => $extensionLanguagePrefix . 'company_name',
+ 'config' => [
+ 'type' => 'input',
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ 'street' => [
+ 'label' => $extensionLanguagePrefix . 'street',
+ 'config' => [
+ 'type' => 'input',
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ 'house_number' => [
+ 'label' => $extensionLanguagePrefix . 'house_number',
+ 'config' => [
+ 'type' => 'input',
+ 'size' => 10,
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ 'zip' => [
+ 'label' => $extensionLanguagePrefix . 'zip',
+ 'config' => [
+ 'type' => 'input',
+ 'size' => 10,
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ 'city' => [
+ 'label' => $extensionLanguagePrefix . 'city',
+ 'config' => [
+ 'type' => 'input',
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ 'country' => [
+ 'label' => $extensionLanguagePrefix . 'country',
+ 'config' => [
+ 'type' => 'input',
+ 'max' => 255,
+ 'eval' => 'trim,required',
+ ],
+ ],
+ ],
+ ];
+})();
diff --git a/CodeExamples/localPackages/example_extension/Resources/Private/Language/locallang_tca.xlf b/CodeExamples/localPackages/example_extension/Resources/Private/Language/locallang_tca.xlf
new file mode 100644
index 0000000..4ee28b2
--- /dev/null
+++ b/CodeExamples/localPackages/example_extension/Resources/Private/Language/locallang_tca.xlf
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CodeExamples/localPackages/example_extension/ext_tables.sql b/CodeExamples/localPackages/example_extension/ext_tables.sql
new file mode 100644
index 0000000..d340b20
--- /dev/null
+++ b/CodeExamples/localPackages/example_extension/ext_tables.sql
@@ -0,0 +1,22 @@
+CREATE TABLE tx_exampleextension_domain_model_address (
+ uid int(11) unsigned NOT NULL auto_increment,
+ pid int(11) unsigned DEFAULT '0' NOT NULL,
+
+ crdate int(11) unsigned DEFAULT '0' NOT NULL,
+ cruser_id int(11) unsigned DEFAULT '0' NOT NULL,
+ tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+ hidden tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ deleted tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ starttime int(11) unsigned DEFAULT '0' NOT NULL,
+ endtime int(11) unsigned DEFAULT '0' NOT NULL,
+
+ company_name varchar(255) DEFAULT '' NOT NULL,
+ street varchar(255) DEFAULT '' NOT NULL,
+ house_number varchar(255) DEFAULT '' NOT NULL,
+ zip varchar(255) DEFAULT '' NOT NULL,
+ city varchar(255) DEFAULT '' NOT NULL,
+ country varchar(255) DEFAULT '' NOT NULL,
+
+ PRIMARY KEY (uid),
+ KEY parent (pid)
+);
diff --git a/Documentation/source/Configuration.rst b/Documentation/source/Configuration.rst
index ffddf59..0ca9121 100644
--- a/Documentation/source/Configuration.rst
+++ b/Documentation/source/Configuration.rst
@@ -1,14 +1,138 @@
Configuration
=============
+There are many different ways and places in TYPO3 for configuration. We will cover
+the different places and types of configuration, including when to use a certain way.
+
+By following the API you also make sure modern approaches like configuration loaders
+will work with your extensions.
+
Places of configuration
-----------------------
+The following places exist to configure a TYPO3 Extensions:
+
PHP
^^^
+PHP via :file:`LocalConfiguration.php` and :file:`AdditionalConfiguration.php`.
+
+Some extensions allow to place configuration in custom files, e.g. EXT:realurl. I
+would call that a bad practice as you have arbitrary places to check for certain
+configurations.
+
+Instead use existing places like the two mentioned files above. This is done by
+either using:
+
+.. code-block:: php
+
+ return [
+ 'EXTCONF' => [
+ 'extkey' => [
+ // options
+ ],
+ ],
+ ];
+
+This way you can access the configuration via ``$GLOBALS['EXTCONF']['extkey']``.
+
+Or by providing a :file:`ext_conf_template.txt` in the root of your Extension.
+The content is TypoScript as documented at :ref:`t3coreapi:extension-options`.
+Afterwards you can access the options through an API.
+
TypoScript
^^^^^^^^^^
+TypoScript and Flexforms are merged by Extbase, so you do not have to do any
+additional work and combine both. They are available as Variable ``{settings}`` in
+all Templates. Also inside the Controller they are available as array in
+``$this->settings`` out of the box.
+
+.. admonition:: Task
+
+ Add some settings and print them in Template and Controller.
+
+The configuration via TypoScript has to be located at a specific path:
+
+.. code-block:: typoscript
+ :linenos:
+
+ // For all frontend plugins of the extension
+ plugin {
+ tx_exampleextension {
+ settings {
+ // The configuration goes here
+ }
+ }
+ }
+
+ // For a specific frontend plugin of the extension
+ plugin {
+ tx_exampleextension_pluginkey {
+ settings {
+ // The configuration goes here
+ }
+ }
+ }
+
+ // For Backend Modules
+ module {
+ tx_exampleextension {
+ settings {
+ // The configuration goes here
+ }
+ }
+ }
+
+Extbase itself already has some configuration options available via TypoScript, some
+are mentioned at :ref:`t3extbasebook:typoscript_configuration` section of Extbase
+book.
+
+.. tip::
+
+ The whole ``settings`` array is passed into all templates, layouts and partials.
+ This way it's possible for integrators to provide arbitary information.
+
+Also it's possible to insert a plugin via TypoScript. In that case the settings can
+be provided only for that instance:
+
+.. code-block:: typoscript
+ :linenos:
+
+ lib.instance = USER
+ lib.instance {
+ userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
+ extensionName = ExampleExtension
+ pluginName = pluginkey
+ vendorName = Workshop
+ settings {
+ testKey = testValue
+ }
+ }
+
+Flexforms
+^^^^^^^^^
+
+Flexforms are like TCA, which will be covered later on. The format is XML instead of
+PHP and saved inside the database field ``pi_flexform`` of the ``tt_content`` record.
+This way editors are able to adjust provided settings within a plugin record.
+
Custom
^^^^^^
+
+Do whatever you want, e.g. use yaml or TypoScript by calling the parser for contents
+from anywhere.
+
+When to use which
+-----------------
+
+The Flexform approach provides the best UX as it uses the known UI of TYPO3 inside a
+record.
+
+The TypoScript provided the best UX when integrators have to deploy configuration or
+configuration is necessary on multiple pages. Also if the plugin is inserted directly
+via TypoScript.
+
+The PHP approach is best suited for instance wide configuration, which nearly never
+exists. Things like API Keys might depend on the current Domain or Website, and there
+can be multiple in a single TYPO3 instance.
diff --git a/Documentation/source/CustomRecords.rst b/Documentation/source/CustomRecords.rst
index 5dd7fda..32645f6 100644
--- a/Documentation/source/CustomRecords.rst
+++ b/Documentation/source/CustomRecords.rst
@@ -1,14 +1,208 @@
Custom records
==============
+The basics are behind us, now let's get deeper into the system and create a new
+record type, like ``tt_address`` which can be displayed through our plugin.
+
TCA
---
+.. admonition:: Task
+
+ Create necessary TCA for our new record.
+
+Before we can do anything with Extbase, we need to configure TYPO3. The TCA (=Table
+Configuration Array) contains configuration for each database table. TYPO3 will
+generate the list view and edit forms from this configuration.
+
+Extbase uses this configuration for mapping and database queries, together with
+relation handling.
+
+TYPO3 provides a rich documentation about the TCA at
+https://docs.typo3.org/typo3cms/TCAReference/. That's why this section is empty, all
+information are available there.
+
+One thing to notice is that Extbase uses "Convention over Configuration". While we
+can configure Extbase to map a Model to a specific database table, we can auto match
+them. For a Model ``Workshop\ExampleExtension\Domain\Model\Address``, the database
+table would be ``tx_exampleextension_domain_model_address``. So this will be
+our database table name for our example.
+
+Also each property within the model is written lowerCamelCase, while the database
+columns are written snake_case.
+
+Our new record will be an address record with the following fields:
+
+* Company Name
+
+* Street
+
+* House number
+
+* Zip
+
+* City
+
+* Country
+
+.. note::
+
+ By default new records are only allowed on pages of type "Folder".
+
+ext_tables.sql
+--------------
+
+.. admonition:: Task
+
+ Create necessary sql for our new record.
+
+.. admonition:: Task
+
+ Create some records, edit them, play around.
+
+Once the TCA is provided, we need to create the table in our Database.
+Each extension can provide a :file:`ext_tables.sql` in the root directory. Within the
+install tool and TYPO3 Console, you can update the database schema to match the
+current necessary structure of all extensions.
+
+If multiple extensions adjust the same field, the last one in load order is used.
+
+The example :file:`ext_tables.sql` is:
+
+.. literalinclude:: ../../CodeExamples/localPackages/example_extension/ext_tables.sql
+ :language: sql
+
+Model
+-----
+
+.. admonition:: Task
+
+ Create Model representing our records.
+
+Once we are able to create and edit records in TYPO3 backend, we are ready to go with
+Extbase. First we need a representation of our Data. This is done with a Model, in
+our case this has to match the table name and is called
+``Workshop\ExampleExtension\Domain\Model\Address`` and located at
+:file:`Classes/Domain/Model/Address.php`.
+
+Each model is a PHP class structure like:
+
+.. literalinclude:: ../../CodeExamples/localPackages/example_extension/Classes/Domain/Model/Address.php
+ :language: php
+ :linenos:
+ :lines: 1-4,24-32,58-61,87
+
Repository
----------
+.. admonition:: Task
+
+ Create Repository to access records.
+
+In order to get, update or delete our records, we need a repository. This will return
+the models for us. The repository is another class which can be completely empty:
+
+The file is located at :file:`Classes/Domain/Repository/AddressRepository.php`:
+
+.. literalinclude:: ../../CodeExamples/localPackages/example_extension/Classes/Domain/Repository/AddressRepository.php
+ :language: php
+ :linenos:
+ :lines: 1-4, 24-
+
+The parent class already provides all necessary methods for daily use cases.
+
Controller
----------
-Model
------
+.. admonition:: Task
+
+ Provide available records to template.
+
+In order to provide records in form of models to our template, we first need an
+instance of our repository:
+
+.. code-block:: php
+ :linenos:
+
+ use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+ use Workshop\ExampleExtension\Domain\Repository\AddressRepository;
+
+ class ExampleController extends ActionController
+ {
+ /**
+ * @var AddressRepository
+ */
+ protected $addressRepository;
+
+ public function __construct(AddressRepository $addressRepository)
+ {
+ $this->addressRepository = $addressRepository;
+ }
+ }
+
+With the above code we only can create instances of the controller if an instance of
+the Repository is provided.
+
+Extbase itself will analyse dependencies inside ``__construct`` and will provide
+instances. This is called Dependency Injection and works in three different ways with
+Extbase. The above one is the preferred as this is not Extbase specific but will also
+work in other PHP Frameworks and without any Dependency Injection at all.
+
+We then can call the accordingly method to fetch records, which then can be assigned
+to the view:
+
+.. code-block:: php
+ :linenos:
+
+ class ExampleController extends ActionController
+ {
+ public function exampleAction()
+ {
+ $this->view->assign('addresses', $this->addressRepository->findAll());
+ }
+ }
+
+The ``AddressRepository`` extends the base ``Repository`` class and inherits some
+methods, e.g. ``findAll``.
+
+Template
+--------
+
+With our records in our template, we can iterate over them to display them.
+
+:file:`Resources/Private/Templates/Example/Example.html`:
+
+.. code-block:: html
+ :linenos:
+
+
+
{address.companyName}
+
+ {address.street} {address.houseNumber}
+ {address.zip} {address.city}
+ {address.country}
+
+
+
+Configure storage pid
+---------------------
+
+We should not see any addresses yet, that’s due to the generated database query by
+Extbase. If no storage pid is configured, Extbase will fetch records from pid 0.
+
+Within the content element we can select arbitrary "Record Storage Page" entries to
+use for records.
+
+We could also configure the pid via TypoScript:
+
+.. code-block:: typoscript
+ :linenos:
+
+ plugin {
+ tx_exampleextension {
+ persistence {
+ storagePid = 2
+ }
+ }
+ }
+
diff --git a/Documentation/source/conf.py b/Documentation/source/conf.py
index df0fb2c..cf712d6 100644
--- a/Documentation/source/conf.py
+++ b/Documentation/source/conf.py
@@ -308,6 +308,7 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
't3coreapi': ('https://docs.typo3.org/typo3cms/CoreApiReference/', None),
+ 't3extbasebook': ('https://docs.typo3.org/typo3cms/ExtbaseFluidBook/', None),
}
# Allow inline PHP highlighting