www.e-net.info




Extbase zu Ende gespielt...!?
T3ak12 - Februar 2012

e-net Consulting GmbH & Co. KG
Helge Funk - @tox234
Christian Kuhn - @lolli42
Übersicht



• XCLASS on steroids

• Globaler Namespace in Fluid

• Argumente für Partials

• Request Handler

• Objekthierarchien auf Datenbankebene

• Propertyabhängige Validierung

• Fluid Goodies
XCLASS on steroids


• Klassen und Interface-Implementierungen werden per TypoScript registriert

config.tx_extbase {
    objects {
        Tx_Extbase_MVC_Controller_FlashMessages {
             className = Tx_T3Ak12_MVC_Controller_FlashMessageContainer
        }
        Tx_T3Ak12_MyObjectInterface {
             className = Tx_T3Ak12_Domain_Model_MyObject
        }
    }
}

• t3lib_div::makeInstance vs. Tx_Extbase_Object_ObjectManager

$myObject = t3lib_div::makeInstance('Tx_T3Ak12_Domain_Model_MyObject');

$myObject = $this->objectManager->get('Tx_T3Ak12_MyObjectInterface');


Der Object Manager ruft – im Gegensatz zu makeInstance() – nach dem Konstruktor zuerst existierende
inject* Methoden und dann initializeObject() auf.
XCLASS on steroids

• Implementierung

interface Tx_T3Ak12_MyObjectInterface {
    public function setValue(array $data);
}

class Tx_T3Ak12_Domain_Model_MyObject implements Tx_T3Ak12_MyObjectInterface {

    protected $data;

    public function setValue(array $data) {
        $this->data = $data;
    }
}

• Injection

class Tx_T3Ak12_Controller_MyController {

    /**
     * @var Tx_T3Ak12_MyObjectInterface
     */
    protected $myObject;

    /**
      * @param Tx_T3Ak12_MyObjectInterface $myObject
      */
    public function injectMyObject(Tx_T3Ak12_MyObjectInterface $myObject) {
         $this->myObject = $myObject;
    }
}
Globaler Namespace in Fluid

• Globale Anmeldung eines Namespaces in Fluid-Templates für Standard-Libraries

config.tx_extbase {
    objects {
        Tx_Fluid_Core_Parser_TemplateParser {
             className = Tx_T3Ak12_View_TemplateParser
        }
    }
}

class Tx_T3Ak12_View_TemplateParser extends Tx_Fluid_Core_Parser_TemplateParser {

    protected $namespacesBase = array();

    public function initializeObject() {
        $this->namespacesBase = $this->namespaces += array(
            't3ak12' => 'Tx_T3Ak12_ViewHelpers'
        );
    }

    protected function reset() {
        $this->namespaces = $this->namespacesBase;
    }
}


Der Namespace steht nun global in Fluid-Templates zur Verfügung:

<t3ak12:customViewHelper foo=“bar“ />
Argumente für Partials

• Übergabe aller Templatevariablen über {_all} ab TYPO3 4.6 möglich

<f:render partial="ListElement" arguments="{_all}" />

• Backport für TYPO3 4.5

class Tx_T3Ak12_Core_ViewHelper_TemplateVariableContainer
    extends Tx_Fluid_Core_ViewHelper_TemplateVariableContainer {

    static protected $reservedVariableNames = array(
        'true', 'false', 'on', 'off', 'yes', 'no', '_all'
    );

    public function get($identifier) {
        if ($identifier === '_all') {
            return $this->variables;
        }
        if (!array_key_exists($identifier, $this->variables)) {
             // throw Exception here ...
        }
        return $this->variables[$identifier];
    }

    public function exists($identifier) {
        if ($identifier === '_all') {
            return TRUE;
        }
        return array_key_exists($identifier, $this->variables);
    }
}
Request Handler

• Aufbereitung des Requests in verschiedenen Scopes: Web (FE/BE), CLI,
WebService
• z.B. FrontendRequestHandler: Verifizierung des Request Hash, Cache Handling
• CLI Request Handler ab TYPO3 4.7 verfügbar
• LwEnetMultipleActionForms -> Aufbereitung des Request mit Session-Daten
config.tx_extbase.mvc.requestHandlers {
    Tx_T3Ak12_Web_FrontendRequestHandler = Tx_T3Ak12_Web_FrontendRequestHandler
}


class Tx_T3Ak12_Web_FrontendRequestHandler ... {
    public function handleRequest() {
        …
        $this->dispatcher->dispatch($request, $response);
        return $response;
    }
    public function canHandleRequest() {
        // Can this request be handled
    }
    public function getPriority() {
        return 110; // Priority chain
    }
}
Objekthierarchien auf Datenbankebene




                   Product



      Socks                       Shirt



                         Men              Women
Objekthierarchien auf Datenbankebene

• Basisklasse: Übergreifende Eigenschaften

interface Tx_T3Ak12_Domain_Model_ProductInterface extends Tx_Extbase_DomainObject_DomainObjectInterface
{
    public function getName();
    public function setName($name);


    public function getPrice();
    public function setPrice($price);
}



class Tx_T3Ak12_Domain_Model_Product extends Tx_Extbase_DomainObject_AbstractEntity implements
Tx_T3Ak12_Domain_Model_ProductInterface {


    protected $name;
    public function getName() {code for getter}
    public function setName($name) {code for setter}


    protected $price;
    public function getPrice() {code for getter}
    public function setPrice($price) {code for setter}
}
Objekthierarchien auf Datenbankebene

• Erweiterte Produktklasse

interface Tx_T3Ak12_Domain_Model_ShirtInterface {
    public function getColor();
    public function setColor($color);


    public function getSize();
    public function setSize($size);
}



class Tx_T3Ak12_Domain_Model_Shirt extends Tx_T3Ak12_Domain_Model_Product implements
Tx_T3Ak12_Domain_Model_ShirtInterface {


    protected $color;
    public function getColor() {code for getter}
    public function setColor($color) {code for setter}


    protected $size;
    public function getSize() {code for getter}
    public function setSize($size) {code for setter}
}
Objekthierarchien auf Datenbankebene

• Repositories: Über findAll() werden nur die entsprechenden Objekte geliefert
class Tx_T3Ak12_Domain_Repository_ProductRepository
     extends Tx_Extbase_Persistence_Repository {}


class Tx_T3Ak12_Domain_Repository_ShirtRepository
    extends Tx_T3Ak12_Domain_Repository_ProductRepository {}


• TCA
$TCA['tx_lwsmaproducts_domain_model_product']['ctrl']['type'] = 'record_type';


• Mapping
config.tx_extbase.persistence.classes {
     Tx_T3Ak12_Domain_Model_Product {
         mapping.tableName = tx_t3ak12_domain_model_product
         mapping.recordType = Tx_T3Ak12_Domain_Model_Product
         subclasses {
              Tx_T3Ak12_Domain_Model_Shirt = Tx_T3Ak12_Domain_Model_Shirt
         }
    }
    Tx_T3Ak12_Domain_Model_Shirt {
         mapping.tableName = tx_t3ak12_domain_model_product
         mapping.recordType = Tx_T3Ak12_Domain_Model_Shirt
    }
}
Propertyabhängige Validierung

• Property kann nicht in Abhängigkeit zu anderen Properties validiert werden
• kein Zugriff auf andere Property-Werte innerhalb eines Property-Validators
 /**
 * @var string
 * @validate StringLength(minimum='42')
 */
protected $property;


• Standardlösung in extbase: ModelValidator
• Automatischer Aufruf, keine Registrierung notwendig, Aufruf nach Property-
Validatoren
class Tx_T3Ak12_Domain_Model_'ModelName' extends
    Tx_Extbase_DomainObject_AbstractEntity {
}

class Tx_T3Ak12_Domain_Validator_'ModelName'Validator extends
    Tx_Extbase_Validation_Validator_AbstractValidator {

    public function isValid($object) {
        $isValid = TRUE;
        if ($object->getSecondProperty() === 'foo' ) {
            $notEmptyValidator = $this->validatorResolver->createValidator('NotEmpty');
            $isValid = $notEmptyValidator->isValid($object->getFirstProperty());
        }
        return $isValid;
    }
}
Propertyabhängige Validierung


• validatePropertyConstraint in LwEnetMultipleActionForms

/**
 * firstProperty
 *
 * @var string
 * @validatePropertyConstraint $secondProperty Equal(valueList='foo,baz') -> NotEmpty
 */
protected $firstProperty;
Fluid Goodies

• Partials einer anderen Extension rendern
• Externe Partials können verschachtelt werden
• Innerhalb von Forms verwendbar → Tokengenerierung

<fx:render partial="Foo/Bar/Baz" arguments="{_all}" extensionName="T3Ak12" />




• String-Vergleich für if-ViewHelper


<f:if condition="{object.property} == abc">
    baz
</f:if>
www.e-net.info

Questions!?

Thx for patience... let's start coding.
T3ak12 - Februar 2012

e-net Consulting GmbH & Co. KG
Helge Funk - @tox234
Christian Kuhn - @lolli42

T3ak12 extbase

  • 1.
    www.e-net.info Extbase zu Endegespielt...!? T3ak12 - Februar 2012 e-net Consulting GmbH & Co. KG Helge Funk - @tox234 Christian Kuhn - @lolli42
  • 2.
    Übersicht • XCLASS onsteroids • Globaler Namespace in Fluid • Argumente für Partials • Request Handler • Objekthierarchien auf Datenbankebene • Propertyabhängige Validierung • Fluid Goodies
  • 3.
    XCLASS on steroids •Klassen und Interface-Implementierungen werden per TypoScript registriert config.tx_extbase { objects { Tx_Extbase_MVC_Controller_FlashMessages { className = Tx_T3Ak12_MVC_Controller_FlashMessageContainer } Tx_T3Ak12_MyObjectInterface { className = Tx_T3Ak12_Domain_Model_MyObject } } } • t3lib_div::makeInstance vs. Tx_Extbase_Object_ObjectManager $myObject = t3lib_div::makeInstance('Tx_T3Ak12_Domain_Model_MyObject'); $myObject = $this->objectManager->get('Tx_T3Ak12_MyObjectInterface'); Der Object Manager ruft – im Gegensatz zu makeInstance() – nach dem Konstruktor zuerst existierende inject* Methoden und dann initializeObject() auf.
  • 4.
    XCLASS on steroids •Implementierung interface Tx_T3Ak12_MyObjectInterface { public function setValue(array $data); } class Tx_T3Ak12_Domain_Model_MyObject implements Tx_T3Ak12_MyObjectInterface { protected $data; public function setValue(array $data) { $this->data = $data; } } • Injection class Tx_T3Ak12_Controller_MyController { /** * @var Tx_T3Ak12_MyObjectInterface */ protected $myObject; /** * @param Tx_T3Ak12_MyObjectInterface $myObject */ public function injectMyObject(Tx_T3Ak12_MyObjectInterface $myObject) { $this->myObject = $myObject; } }
  • 5.
    Globaler Namespace inFluid • Globale Anmeldung eines Namespaces in Fluid-Templates für Standard-Libraries config.tx_extbase { objects { Tx_Fluid_Core_Parser_TemplateParser { className = Tx_T3Ak12_View_TemplateParser } } } class Tx_T3Ak12_View_TemplateParser extends Tx_Fluid_Core_Parser_TemplateParser { protected $namespacesBase = array(); public function initializeObject() { $this->namespacesBase = $this->namespaces += array( 't3ak12' => 'Tx_T3Ak12_ViewHelpers' ); } protected function reset() { $this->namespaces = $this->namespacesBase; } } Der Namespace steht nun global in Fluid-Templates zur Verfügung: <t3ak12:customViewHelper foo=“bar“ />
  • 6.
    Argumente für Partials •Übergabe aller Templatevariablen über {_all} ab TYPO3 4.6 möglich <f:render partial="ListElement" arguments="{_all}" /> • Backport für TYPO3 4.5 class Tx_T3Ak12_Core_ViewHelper_TemplateVariableContainer extends Tx_Fluid_Core_ViewHelper_TemplateVariableContainer { static protected $reservedVariableNames = array( 'true', 'false', 'on', 'off', 'yes', 'no', '_all' ); public function get($identifier) { if ($identifier === '_all') { return $this->variables; } if (!array_key_exists($identifier, $this->variables)) { // throw Exception here ... } return $this->variables[$identifier]; } public function exists($identifier) { if ($identifier === '_all') { return TRUE; } return array_key_exists($identifier, $this->variables); } }
  • 7.
    Request Handler • Aufbereitungdes Requests in verschiedenen Scopes: Web (FE/BE), CLI, WebService • z.B. FrontendRequestHandler: Verifizierung des Request Hash, Cache Handling • CLI Request Handler ab TYPO3 4.7 verfügbar • LwEnetMultipleActionForms -> Aufbereitung des Request mit Session-Daten config.tx_extbase.mvc.requestHandlers { Tx_T3Ak12_Web_FrontendRequestHandler = Tx_T3Ak12_Web_FrontendRequestHandler } class Tx_T3Ak12_Web_FrontendRequestHandler ... { public function handleRequest() { … $this->dispatcher->dispatch($request, $response); return $response; } public function canHandleRequest() { // Can this request be handled } public function getPriority() { return 110; // Priority chain } }
  • 8.
    Objekthierarchien auf Datenbankebene Product Socks Shirt Men Women
  • 9.
    Objekthierarchien auf Datenbankebene •Basisklasse: Übergreifende Eigenschaften interface Tx_T3Ak12_Domain_Model_ProductInterface extends Tx_Extbase_DomainObject_DomainObjectInterface { public function getName(); public function setName($name); public function getPrice(); public function setPrice($price); } class Tx_T3Ak12_Domain_Model_Product extends Tx_Extbase_DomainObject_AbstractEntity implements Tx_T3Ak12_Domain_Model_ProductInterface { protected $name; public function getName() {code for getter} public function setName($name) {code for setter} protected $price; public function getPrice() {code for getter} public function setPrice($price) {code for setter} }
  • 10.
    Objekthierarchien auf Datenbankebene •Erweiterte Produktklasse interface Tx_T3Ak12_Domain_Model_ShirtInterface { public function getColor(); public function setColor($color); public function getSize(); public function setSize($size); } class Tx_T3Ak12_Domain_Model_Shirt extends Tx_T3Ak12_Domain_Model_Product implements Tx_T3Ak12_Domain_Model_ShirtInterface { protected $color; public function getColor() {code for getter} public function setColor($color) {code for setter} protected $size; public function getSize() {code for getter} public function setSize($size) {code for setter} }
  • 11.
    Objekthierarchien auf Datenbankebene •Repositories: Über findAll() werden nur die entsprechenden Objekte geliefert class Tx_T3Ak12_Domain_Repository_ProductRepository extends Tx_Extbase_Persistence_Repository {} class Tx_T3Ak12_Domain_Repository_ShirtRepository extends Tx_T3Ak12_Domain_Repository_ProductRepository {} • TCA $TCA['tx_lwsmaproducts_domain_model_product']['ctrl']['type'] = 'record_type'; • Mapping config.tx_extbase.persistence.classes { Tx_T3Ak12_Domain_Model_Product { mapping.tableName = tx_t3ak12_domain_model_product mapping.recordType = Tx_T3Ak12_Domain_Model_Product subclasses { Tx_T3Ak12_Domain_Model_Shirt = Tx_T3Ak12_Domain_Model_Shirt } } Tx_T3Ak12_Domain_Model_Shirt { mapping.tableName = tx_t3ak12_domain_model_product mapping.recordType = Tx_T3Ak12_Domain_Model_Shirt } }
  • 12.
    Propertyabhängige Validierung • Propertykann nicht in Abhängigkeit zu anderen Properties validiert werden • kein Zugriff auf andere Property-Werte innerhalb eines Property-Validators /** * @var string * @validate StringLength(minimum='42') */ protected $property; • Standardlösung in extbase: ModelValidator • Automatischer Aufruf, keine Registrierung notwendig, Aufruf nach Property- Validatoren class Tx_T3Ak12_Domain_Model_'ModelName' extends Tx_Extbase_DomainObject_AbstractEntity { } class Tx_T3Ak12_Domain_Validator_'ModelName'Validator extends Tx_Extbase_Validation_Validator_AbstractValidator { public function isValid($object) { $isValid = TRUE; if ($object->getSecondProperty() === 'foo' ) { $notEmptyValidator = $this->validatorResolver->createValidator('NotEmpty'); $isValid = $notEmptyValidator->isValid($object->getFirstProperty()); } return $isValid; } }
  • 13.
    Propertyabhängige Validierung • validatePropertyConstraintin LwEnetMultipleActionForms /** * firstProperty * * @var string * @validatePropertyConstraint $secondProperty Equal(valueList='foo,baz') -> NotEmpty */ protected $firstProperty;
  • 14.
    Fluid Goodies • Partialseiner anderen Extension rendern • Externe Partials können verschachtelt werden • Innerhalb von Forms verwendbar → Tokengenerierung <fx:render partial="Foo/Bar/Baz" arguments="{_all}" extensionName="T3Ak12" /> • String-Vergleich für if-ViewHelper <f:if condition="{object.property} == abc"> baz </f:if>
  • 15.
    www.e-net.info Questions!? Thx for patience...let's start coding. T3ak12 - Februar 2012 e-net Consulting GmbH & Co. KG Helge Funk - @tox234 Christian Kuhn - @lolli42