* @var string
*/
protected $actionMethodName = 'indexAction';
+
+ /**
+ * Name of the special error action method which is called in case of errors
+ * @var string
+ */
+ protected $errorMethodName = 'errorAction';
/**
* Handles a request. The result output is returned by altering the given response.
$this->initializeAction();
$this->callActionMethod();
}
-
+
/**
* Implementation of the arguments initilization in the action controller:
* Automatically registers arguments of the current action
return $actionMethodName;
}
- /**
- * Returns TRUE if the given action (a name of an action like 'show'; without
- * trailing 'Action') should be cached, otherwise it returns FALSE.
- *
- * @param string $actionName
- * @return void
- * @author Jochen Rau <jochen.rau@typoplanet.de>
- */
- public function isCachableAction($actionName) {
- return !in_array($actionName, $this->nonCachableActions);
- }
-
/**
* Calls the specified action method and passes the arguments.
* If the action returns a string, it is appended to the content in the
* response object.
*
- * @param string $actionMethodName Name of the action method
* @return void
+ * @internal
*/
protected function callActionMethod() {
+ $preparedArguments = array();
foreach ($this->arguments as $argument) {
+ $this->preProcessArgument($argument);
$preparedArguments[] = $argument->getValue();
}
- $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
+ if (!$this->arguments->areValid()) {
+ $actionResult = call_user_func(array($this, $this->errorMethodName));
+ } else {
+ $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments);
+ }
if ($actionResult === NULL && $this->view instanceof Tx_ExtBase_MVC_View_ViewInterface) {
$this->response->appendContent($this->view->render());
} elseif (is_string($actionResult) && strlen($actionResult) > 0) {
$this->response->appendContent($actionResult);
}
}
+
+ /**
+ * This is a template method to process unvalid arguments. Overwrite this method in your concrete controller.
+ *
+ * @param Tx_ExtBase_MVC_Controller_Argument $argument The argument
+ * @return void
+ */
+ protected function preProcessArgument(Tx_ExtBase_MVC_Controller_Argument $argument) {
+ }
/**
* Prepares a view for the current action and stores it in $this->view.
}
/**
- * The default action of this controller.
+ * A special action which is called if the originally intended action could
+ * not be called, for example if the arguments were not valid.
*
- * This method should always be overridden by the concrete action
- * controller implementation.
- *
- * @return void
+ * @return string
*/
- protected function indexAction() {
- return 'No index action has been implemented yet for this controller.';
+ protected function errorAction() {
+ $message = 'An error occurred while trying to call ' . get_class($this) . '->' . $this->actionMethodName . '(). <br />' . PHP_EOL;
+ foreach ($this->arguments as $argument) {
+ if (!$argument->isValid()) {
+ foreach ($argument->getErrors() as $errorMessage) {
+ $message .= 'Error: ' . $errorMessage . '<br />' . PHP_EOL;
+ }
+ }
+ }
+ return $message;
}
}
?>
\ No newline at end of file
* The argument is valid
* @var boolean
*/
- protected $isValid = NULL;
+ protected $isValid = FALSE;
/**
* Any error (Tx_ExtBase_Error_Error) that occured while initializing this argument (e.g. a mapping error)
*/
protected $validator = NULL;
- /**
- * The property validator for this arguments datatype
- * @var Tx_ExtBase_Validation_Validator_ValidatorInterface
- */
- // TODO Remove DatatypeValidator
- protected $datatypeValidator = NULL;
-
/**
* Uid for the argument, if it has one
* @var string
public function setDataType($dataType) {
$this->dataType = ($dataType != '' ? $dataType : 'Text');
// TODO Make validator path and class names configurable
- $dataTypeValidatorClassName = 'Tx_ExtBase_Validation_Validator_' . $this->dataType;
+ $validatorClassName = 'Tx_ExtBase_Validation_Validator_' . $this->dataType;
$classFilePathAndName = t3lib_extMgm::extPath('extbase') . 'Classes/Validation/Validator/' . $this->dataType . '.php';
if (isset($classFilePathAndName) && file_exists($classFilePathAndName)) {
require_once($classFilePathAndName);
- $this->datatypeValidator = t3lib_div::makeInstance($dataTypeValidatorClassName);
+ $this->validator = t3lib_div::makeInstance($validatorClassName);
}
return $this;
}
*/
protected function isValidValueForThisArgument($value) {
$isValid = TRUE;
+ $this->clearErrors();
$validatorErrors = t3lib_div::makeInstance('Tx_ExtBase_Validation_Errors');
- // TODO use only Validator; do not distinguish between Validator and DatatypeValidator
if ($this->getValidator() !== NULL) {
- $isValid &= $this->getValidator()->isValid($value, $validatorErrors);
- } elseif ($this->getDatatypeValidator() !== NULL) {
- $isValid = $this->getDatatypeValidator()->isValid($value, $validatorErrors);
+ $isValid &= (boolean)$this->getValidator()->isValid($value, $validatorErrors);
} else {
throw new Tx_ExtBase_Validation_Exception_NoValidatorFound('No appropriate validator for the argument "' . $this->getName() . '" was found.', 1235748909);
}
$this->addError($error);
}
}
- $this->isValid = $isValid;
- return (boolean)$isValid;
+ $this->setIsValid($isValid);
+ return $isValid;
+ }
+
+ /**
+ * Sets the validity of the argument
+ *
+ * @return void
+ */
+ // TODO naming of the method setIsValid()
+ public function setIsValid($isValid) {
+ return $this->isValid = $isValid;
}
/**
$this->errors[] = $error;
}
+ /**
+ * Removes all errors
+ *
+ * @return void
+ */
+ public function clearErrors() {
+ $this->errors = array();
+ }
+
/**
* Get all initialization errors
*
return $this->errors;
}
+ /**
+ * Returns true if any error was recognized
+ *
+ * @return boolean True if an error occured
+ */
+ public function hasErrors() {
+ return (count($this->errors) > 0);
+ }
+
/**
* Set an additional validator
*
return $this->validator;
}
- /**
- * Returns the set datatype validator
- *
- * @return Tx_ExtBase_Validation_Validator_ValidatorInterface The set datatype validator
- */
- public function getDatatypeValidator() {
- return $this->datatypeValidator;
- }
-
/**
* Create and set a validator chain
*
return array_keys($argumentShortNames);
}
+ /**
+ * Returns errors of all arguments
+ *
+ * @return array An array of error messages
+ */
+ public function getErrors() {
+ $errors = array();
+ foreach ($this as $argument) {
+ $errors = array_merge($errors, $argument->getErrors());
+ }
+ return $errors;
+ }
+
+ /**
+ * Returns true if all arguments are valid
+ *
+ * @return boolean TRUE if all arguments are valid
+ */
+ public function areValid() {
+ $valid = TRUE;
+ foreach ($this as $argument) {
+ if (!$argument->isValid()) {
+ $valid = FALSE;
+ break;
+ }
+ }
+ return $valid;
+ }
+
/**
* Magic setter method for the argument values. Each argument
* value can be set by just calling the setArgumentName() method.
* @return string long argument name or empty string
*/
protected function translateToLongArgumentName($argumentName) {
-
if (in_array($argumentName, $this->getArgumentNames())) return $argumentName;
foreach ($this as $argument) {
$uid = $this->findUid($incomingFieldArray, $table);
if ($uid !== NULL) {
// FOUND a UID.
-
- var_dump($uid, $id);
- var_dump($incomingFieldArray);
if ($isNewRecord) {
// re-map the insertion to an update!
$tcemain->substNEWwitIDs[$id] = (int)$uid;
* @subpackage extbase
* @version $ID:$
*/
-// SK: I did not do an in-depth check of this class
// SK: PHPDoc ;-)
class Tx_ExtBase_Persistence_Mapper_ColumnMap {
public function isPersistableProperty($propertyName) {
return isset($this->columnMaps[$propertyName]);
}
+
+ /**
+ * Check if versioning is enabled .
+ *
+ * @return boolean
+ */
+ public function isVersionable() {
+ return ($GLOBALS['TCA'] [$this->tableName] ['ctrl'] ['versioningWS'] === '1');
+ }
/**
* Returns TRUE if the table has a pid column holding the id of the page the record is virtually stored on.
*
* @var t3lib_refindex
**/
- protected $refIndex;
+ protected $referenceIndex;
/**
* Statistics with counts of database operations
$this->persistenceSession = t3lib_div::makeInstance('Tx_ExtBase_Persistence_Session');
$GLOBALS['TSFE']->includeTCA();
$this->database = $GLOBALS['TYPO3_DB'];
- $this->refIndex = t3lib_div::makeInstance('t3lib_refindex');
+ $this->referenceIndex = t3lib_div::makeInstance('t3lib_refindex');
}
/**
*
* @return string The where part
*/
- protected function buildQueryByConditions(&$dataMap, $conditions) {
+ protected function buildQueryByConditions(Tx_ExtBase_Persistence_Mapper_DataMap &$dataMap, $conditions) {
$whereParts = array();
foreach ($conditions as $key => $condition) {
if (is_array($condition) && isset($condition[0])) {
*
* @return string The where part
*/
- protected function buildQueryByExample(&$dataMap, $propertyName, $example) {
+ protected function buildQueryByExample(Tx_ExtBase_Persistence_Mapper_DataMap &$dataMap, $propertyName, $example) {
$sql = '';
$columnMap = $dataMap->getColumnMap($propertyName);
if (!$columnMap) {
*
* @return string The query part with replaced placeholders
*/
- protected function replacePlaceholders(&$dataMap, $queryPart, $parameters) {
+ protected function replacePlaceholders(Tx_ExtBase_Persistence_Mapper_DataMap &$dataMap, $queryPart, $parameters) {
$sql = $queryPart;
foreach ($parameters as $parameter) {
$markPosition = strpos($sql, '?');
$fieldMap = $this->getFieldMapFromResult($res);
$rows = $this->getRowsFromResult($res);
$this->database->sql_free_result($res);
+ // TODO Implement language and workspace overlay
+ // foreach ($rows as $row) {
+ // $this->doLanguageAndWorkspaceOverlay($dataMap, $fieldMap, $row);
+ // }
- // SK: Do we want to make it possible to ignore "enableFields"?
- // TODO language overlay; workspace overlay
$objects = array();
if (is_array($rows)) {
if (count($rows) > 0) {
$this->statistics['fetch']++;
return $objects;
}
+
+ /**
+ * Fetches a rows from the database by given SQL statement snippets taking a relation table into account
+ *
+ * @param string Optional WHERE clauses put in the end of the query, defaults to '1=1. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
+ * @param string Optional GROUP BY field(s), defaults to blank string.
+ * @param string Optional ORDER BY field(s), defaults to blank string.
+ * @param string Optional LIMIT value ([begin,]max), defaults to blank string.
+ */
+ public function fetchWithRelationTable($parentObject, $columnMap, $where = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
+ if (!strlen($where)) {
+ $where = '1=1';
+ }
+ $from = $columnMap->getChildTableName() . ' LEFT JOIN ' . $columnMap->getRelationTableName() . ' ON (' . $columnMap->getChildTableName() . '.uid=' . $columnMap->getRelationTableName() . '.uid_foreign)';
+ $where .= ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid());
+
+ return $this->fetch($columnMap->getChildClassName(), $where, $from, $groupBy, $orderBy, $limit, $useEnableFields);
+ }
protected function getFieldMapFromResult($res) {
$fieldMap = array();
}
return $rows;
}
+
+ /**
+ * Performs woekspace and language overlay on the given row array..The language and workspaceid is automatically
+ * detected (depending on FE or BE context). You can also explicitly set the language/workspace uid.
+ *
+ * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap
+ * @param array $row The row array (as reference)
+ * @param string $languageUid The language uid
+ * @param string $workspaceUidUid The workspace uid
+ * @return void
+ */
+ protected function doLanguageAndWorkspaceOverlay(Tx_ExtBase_Persistence_Mapper_DataMap $dataMap, array &$fieldMap, array &$row, $languageUid = null, $workspaceUid = null) {
+ $tableName = $dataMap->getTableName();
+ if (TYPO3_MODE == 'FE') {
+ if (is_object($GLOBALS ['TSFE'])) {
+ $pageSelectObject = $GLOBALS ['TSFE']->sys_page;
+ if ($languageUid === NULL) {
+ $languageUid = $GLOBALS ['TSFE']->sys_language_content;
+ }
+ }
+ else {
+ require_once(PATH_t3lib . 'class.t3lib_page.php');
+ $pageSelectObject = t3lib_div::makeInstance('t3lib_pageSelect');
+
+ if ($languageUid === NULL) {
+ $languageUid = intval(t3lib_div::_GP('L'));
+ }
+ }
+
+
+ if ($workspaceUid !== NULL) {
+ $pageSelectObject->versioningWorkspaceId = $workspaceUid;
+ }
+ } else {
+ require_once(PATH_t3lib . 'class.t3lib_page.php');
+ $pageSelectObject = t3lib_div::makeInstance( 't3lib_pageSelect' );
+ //$pageSelectObject->versioningPreview = TRUE;
+ if ($workspaceUid === NULL) {
+ $workspaceUid = $GLOBALS ['BE_USER']->workspace;
+ }
+ $pageSelectObject->versioningWorkspaceId = $workspaceUid;
+ }
+
+ $row = $pageSelectObject->getRecordOverlay($tableName, $row, $languageUid, ''); //'hideNonTranslated'
+
+ // TODO Skip if empty languageoverlay (languagevisibility)
+
+ if ($dataMap->isVersionable($tableName)) {
+ $t3lib_pageSelect->versionOL($tableName, $row);
+ }
+ }
/**
* Get the join clause for the fetch method for a specific class. This will
return $join;
}
- /**
- * Fetches a rows from the database by given SQL statement snippets taking a relation table into account
- *
- * @param string Optional WHERE clauses put in the end of the query, defaults to '1=1. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
- * @param string Optional GROUP BY field(s), defaults to blank string.
- * @param string Optional ORDER BY field(s), defaults to blank string.
- * @param string Optional LIMIT value ([begin,]max), defaults to blank string.
- */
- public function fetchWithRelationTable($parentObject, $columnMap, $where = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
- if (!strlen($where)) {
- $where = '1=1';
- }
- $from = $columnMap->getChildTableName() . ' LEFT JOIN ' . $columnMap->getRelationTableName() . ' ON (' . $columnMap->getChildTableName() . '.uid=' . $columnMap->getRelationTableName() . '.uid_foreign)';
- $where .= ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid());
-
- return $this->fetch($columnMap->getChildClassName(), $where, $from, $groupBy, $orderBy, $limit, $useEnableFields);
- }
-
/**
* reconstitutes domain objects from $rows (array)
*
* @param array $rows The rows array fetched from the database (not associative)
* @return array An array of reconstituted domain objects
*/
- // SK: I Need to check this method more thoroughly.
- // SK: Are loops detected during reconstitution?
+ // TODO Check for infinite loops during reconstitution
protected function reconstituteObjects(Tx_ExtBase_Persistence_Mapper_DataMap $dataMap, array &$fieldMap, array &$rows) {
$objects = array();
foreach ($rows as $row) {
$object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObject);
} elseif ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
$where = $columnMap->getParentKeyFieldName() . '=' . intval($object->getUid());
- $relatedDataMap = $this->getDataMap($columnMap->getChildClassName());
$relatedObjects = $this->fetch($columnMap->getChildClassName(), $where);
$object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
} elseif ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
- $relatedDataMap = $this->getDataMap($columnMap->getChildClassName());
$relatedObjects = $this->fetchWithRelationTable($object, $columnMap);
$object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
}
return $objects;
}
+ /**
+ * Returns an array of properties with the property name as key and the converted property value as value.
+ *
+ * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map of the target object
+ * @param string $fieldMap the field map of the related database table.
+ * @param string $row The row to be mapped on properties
+ * @return void
+ */
protected function getProperties(Tx_ExtBase_Persistence_Mapper_DataMap $dataMap, array &$fieldMap, array &$row) {
$properties = array();
foreach ($dataMap->getColumnMaps() as $columnMap) {
* @param string $recurseIntoRelations
* @return void
*/
- // SK: I need to check this more thorougly
protected function insertObject(Tx_ExtBase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, $recurseIntoRelations = TRUE) {
$properties = $object->_getProperties();
$className = get_class($object);
$dataMap = $this->getDataMap($className);
- $row = $this->getRow($dataMap, $properties);
+ $row = $this->getRowToBeInstertedOrUpdated($dataMap, $properties);
if ($object instanceof Tx_ExtBase_DomainObject_AbstractValueObject) {
$conditions = $properties;
$uid = $this->database->sql_insert_id();
$object->_reconstituteProperty('uid', $uid);
- $this->refIndex->updateRefIndexTable($tableName, $uid);
+ $this->referenceIndex->updateRefIndexTable($tableName, $uid);
$this->persistRelations($object, $propertyName, $this->getRelations($dataMap, $properties));
}
*
* @return void
*/
- // SK: I need to check this more thorougly
protected function updateObject(Tx_ExtBase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, $recurseIntoRelations = TRUE) {
$properties = $object->_getDirtyProperties();
$dataMap = $this->getDataMap(get_class($object));
- $row = $this->getRow($dataMap, $properties);
+ $row = $this->getRowToBeInstertedOrUpdated($dataMap, $properties);
if ($parentObject instanceof Tx_ExtBase_DomainObject_DomainObjectInterface && $parentPropertyName !== NULL) {
$parentDataMap = $this->getDataMap(get_class($parentObject));
*
* @return void
*/
- // SK: I need to check this more thorougly
protected function deleteObject(Tx_ExtBase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, $recurseIntoRelations = FALSE, $onlySetDeleted = TRUE) {
$relations = array();
$properties = $object->_getDirtyProperties();
);
$this->statistics['delete']++;
}
- $this->refIndex->updateRefIndexTable($tableName, $uid);
+ $this->referenceIndex->updateRefIndexTable($tableName, $uid);
if ($recurseIntoRelations === TRUE) {
// FIXME disabled, recursive delete has to be implemented
* @param array $properties The properties of the object
* @return array A single row to be inserted in the database
*/
- // SK: I need to check this more thorougly
- protected function getRow(Tx_ExtBase_Persistence_Mapper_DataMap $dataMap, $properties) {
+ protected function getRowToBeInstertedOrUpdated(Tx_ExtBase_Persistence_Mapper_DataMap $dataMap, $properties) {
$relations = array();
foreach ($dataMap->getColumnMaps() as $columnMap) {
$propertyName = $columnMap->getPropertyName();
$this->statistics['delete']++;
}
}
-
+
/**
* Delegates the call to the Data Map.
* Returns TRUE if the property is persistable (configured in $TCA)
* @return void
*/
public function __call($methodName, $arguments) {
+ // TODO Forward arguments to find ByConditions
if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
$propertyName = Tx_ExtBase_Utility_Strings::lowercaseFirst(substr($methodName,6));
return $this->findByConditions(array($propertyName => $arguments[0]));
*/
public function isValid($value, Tx_ExtBase_Validation_Errors &$errors, array $validationOptions = array()) {
if ($value !== filter_var($value, FILTER_SANITIZE_STRING)) {
- $errors->append('The given subject was not a valid text (e.g. contained XML tags)."');
+ $errors->append('The given subject was not a valid text (e.g. contained XML tags).');
return FALSE;
}
return TRUE;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<appendix version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:xl="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:ns="http://docbook.org/ns/docbook"
+ xmlns:mathml="http://www.w3.org/1998/Math/MathML">
+ <title>Coding Guidelines</title>
+
+ <para>Coding Standards are an important factor for achieving a high code
+ quality. A common visual style, naming conventions and other technical
+ settings allow us to produce a homogenous code which is easy to read and
+ maintain. However, not all important factors can be covered by rules and
+ coding standards. Equally important is the style in which certain problems
+ are solved programmatically - it's the personality and experience of the
+ individual developer which shines through and ultimately makes the
+ difference between technically okay code or a well considered, mature
+ solution.</para>
+
+ <para>These guidelines try to cover both, the technical standards as well as
+ giving incentives for a common development style. These guidelines must be
+ followed by everyone who creates code for the FLOW3 core. Because TYPO3 is
+ based on FLOW3, it follows the same principles - therefore, whenever we
+ mention FLOW3 in the following sections, we equally refer to TYPO3. We hope
+ that you feel encouraged to follow these guidelines as well when creating
+ your own packages and FLOW3 based applications.</para>
+
+ <section>
+ <title>Code formatting and layout</title>
+
+ <subtitle>aka "beautiful code"</subtitle>
+
+ <para>The visual style of programming code is very important. In the TYPO3
+ project we want many programmers to contribute, but in the same style.
+ This will help us to:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Easily read/understand each others code and consequently easily
+ spot security problems or optimization opportunities</para>
+ </listitem>
+
+ <listitem>
+ <para>It is a signal about consistency and cleanliness, which is a
+ motivating factor for programmers striving for excellence</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Some people may object to the visual guidelines since everyone has
+ his own habits. You will have to overcome that in the case of FLOW3; the
+ visual guidelines must be followed along with coding guidelines for
+ security. We want all contributions to the project to be as similar in
+ style and as secure as possible.</para>
+
+ <section>
+ <title>General considerations</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>Almost every PHP file in FLOW3 contains exactly one class and
+ does not output anything if it is called directly. Therefore you
+ start your file with a <code><?php</code> tag and end it with the
+ closing <code>?></code>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Every file must contain a header stating encoding, namespace,
+ copyright and licensing information</para>
+
+ <para><orderedlist>
+ <listitem>
+ <para>Declare your namespace. The namespace must start with
+ "F3"!</para>
+ </listitem>
+
+ <listitem>
+ <para>Because it is likely that more than one person will work
+ on a class in the long run, we recommend adding a copyright
+ statement like <quote>Copyright belongs to the respective
+ authors</quote> and add yourself to the list of authors for
+ the methods you implemented or changed (significantly).</para>
+ </listitem>
+
+ <listitem>
+ <para>The copyright header itself must not start with
+ <literal>/**</literal>, as this may confuse documentation
+ generators!</para>
+ </listitem>
+ </orderedlist></para>
+
+ <example>
+ <title>The FLOW3 standard file header</title>
+
+ <programlisting language="php"><?php
+declare(ENCODING = 'utf-8');
+namespace F3\Your\Stuff\Here;
+
+/* *
+ * This script belongs to the FLOW3 framework. *
+ * *
+ * It is free software; you can redistribute it and/or modify it under *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version. *
+ * *
+ * This script is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
+ * General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with the script. *
+ * If not, see http://www.gnu.org/licenses/lgpl.html *
+ * *
+ * The TYPO3 project - inspiring people to share! *
+ * */</programlisting>
+ </example>
+ </listitem>
+
+ <listitem>
+ <para>Code lines are of arbitrary length, no limitations to 80
+ characters or something similar (wake up, graphical displays have
+ been available for decades now...)</para>
+ </listitem>
+
+ <listitem>
+ <para>Lines end with a newline a.k.a <code>chr(10)</code> - UNIX
+ style</para>
+ </listitem>
+
+ <listitem>
+ <para>Files must be encoded in UTF-8</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Make sure you use the correct license and mention the correct
+ package in the header, See <link
+ xl:href="http://forge.typo3.org/wiki/flow3-overview/Licensing_boilerplates_to_use_with_your_code">http://forge.typo3.org/wiki/flow3-overview/Licensing_boilerplates_to_use_with_your_code</link>
+ for some boilerplate text.</para>
+ </section>
+
+ <section>
+ <title>Indentation and line formatting</title>
+
+ <para>Indentation is done with tabs - and not spaces! The beginning of a
+ line is the only place where tabs are used, in all other places use
+ spaces. Always trim whitespace off the end of a line.</para>
+
+ <para>Here's a code snippet which shows the correct usage of tabs and
+ spaces:</para>
+
+ <para><example>
+ <title>Correct use of tabs and spaces</title>
+
+ <programlisting language="php">/**
+ * Returns the name of the currently set context.
+ *
+ * @return string Name of the current context
+ * @author Your Name <your@email.here>
+ */
+public function getContextName() {
+» return $this->contextName;
+}</programlisting>
+ </example></para>
+
+ <para>There seem to be very passionate opinions about whether TABs or
+ spaces should be used for indentation of code blocks in the scripts. If
+ you'd like to read more about this religious discussion, you find some
+ nice arguments in the <link
+ xl:href="http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=3978">Joels
+ on Software forum</link>.</para>
+ </section>
+
+ <section>
+ <title>Naming</title>
+
+ <para>Naming is a repeatedly undervalued factor in the art of software
+ development. Although everybody seems to agree on that nice names are a
+ nice thing to have, most developers choose cryptic abbreviations in the
+ end (to save some typing). Beware that we TYPO3 core developers are very
+ passionate about naming (some people call it fanatic, well ...). In our
+ opinion spending 15 minutes (or more ...) just to find a good name for a
+ method is well spent time! There are zillions of reasons for using
+ proper names and in the end they all lead to better readable,
+ manageable, stable and secure code.</para>
+
+ <para><itemizedlist>
+ <listitem>
+ <para>As a general note, english words (or abbreviations if
+ neccessary) must be used for all class names, method names,
+ comments, variables names, database table and field names.
+ Although PHP6 allows for using funny japanese, tibetian or
+ don't-know-what characters, the consensus is that english is much
+ better to read for the most of us.</para>
+ </listitem>
+
+ <listitem>
+ <para>If acronyms or abbreviations are embedded in names, keep
+ them in the case they usually are, i.e. keep
+ <acronym>URL</acronym> uppercase, also when used in a method name
+ like <methodname>getURLForLink()</methodname>,
+ <classname>ACMEManager</classname> etc.</para>
+ </listitem>
+ </itemizedlist></para>
+
+ <section>
+ <title>Package names</title>
+
+ <para>All package names are written in
+ <package>UpperCamelCase</package>. In order to avoid problems with
+ different filesystems, only the characters a-z, A-Z and 0-9 are
+ allowed for package names – don't use special characters.</para>
+ </section>
+
+ <section>
+ <title>Namespace names</title>
+
+ <para>Only the characters a-z, A-Z and 0-9 are allowed for namespace
+ names – don't use special characters. All namespace names are written
+ in <classname>UpperCamelCase</classname>, all uppercase names are
+ allowed for well established abbreviations.</para>
+
+ <note>
+ <para>When specifying class names to PHP, always reference the
+ global namespace inside namespaced code by using a leading
+ backslash. When referencing a class name inside a string (e.g. given
+ to the <methodname>create</methodname>-Method of the
+ <classname>ObjectFactory</classname>, in pointcut expressions or in
+ YAML files), never use a leading backslash. This follows the native
+ PHP notion of names in strings always being seen as fully
+ qualified.</para>
+ </note>
+ </section>
+
+ <section>
+ <title>Class names</title>
+
+ <para>Only the characters a-z, A-Z and 0-9 are allowed for class names
+ – don't use special characters.</para>
+
+ <para>All class names are written in
+ <classname>UpperCamelCase</classname>, all uppercase names are allowed
+ for well established abbreviations. Class names must be nouns, never
+ adjectives.</para>
+
+ <para>The name of abstract classes should start with the word
+ "Abstract".</para>
+
+ <para>A few examples follow:</para>
+
+ <example>
+ <title>Correct naming of classes</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><classname>\F3\FLOW3\Object</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\Manager</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\MySubObject</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\MyHTMLParser</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\Foo\Controller\DefaultController</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\AbstractLogger</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+
+ <example>
+ <title>Incorrect naming of classes</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><classname>\myClass</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\Urlwrapper</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\someObject\classname</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObjectMySubObject</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+ </section>
+
+ <section>
+ <title>Interface names</title>
+
+ <para>Only the characters a-z, A-Z and 0-9 are allowed for interface
+ names – don't use special characters.</para>
+
+ <para>All interface names are written in
+ <classname>UpperCamelCase</classname>, all uppercase names are allowed
+ for well established abbreviations. Interface names must be adjectives
+ or nouns and have the Interface suffix. A few examples follow:</para>
+
+ <example>
+ <title>Correct naming of interfaces</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\ObjectInterface</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\ManagerInterface</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\MySubObjectInterface</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\MyHTMLParserInterface</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+
+ <example>
+ <title>Incorrect naming of interfaces</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><classname>\myInterface</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\Urlwrapper</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\IsomeObject\classname</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\Manager\Interface</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+ </section>
+
+ <section>
+ <title>Exception names</title>
+
+ <para>Exception naming basically follows the rules for naming classes.
+ There are two possible types of exceptions: Generic exceptions and
+ specific exceptions. Generic exceptions should be named "Exception"
+ preceeded by their namespace. Specific exceptions should reside in
+ their own sub-namespace and must not contain the word
+ <literal>Exception</literal>.</para>
+
+ <example>
+ <title>Correct naming of exceptions</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\Exception</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\FLOW3\Object\Exception\InvalidClassName</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\Exception</classname></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>\F3\MyPackage\MyObject\Exception\OutOfCoffee</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+ </section>
+
+ <section>
+ <title>Method names</title>
+
+ <para>All method names are written in lowerCamelCase, all uppercase
+ names are allowed for well established abbreviations. In order to
+ avoid problems with different filesystems, only the characters a-z,
+ A-Z and 0-9 are allowed for method names – don't use special
+ characters.</para>
+
+ <para>Make method names descriptive, but keep them concise at the same
+ time. Constructors must always be called
+ <function>__construct()</function>, never use the class name as a
+ method name.</para>
+
+ <para>A few examples:</para>
+
+ <example>
+ <title>Correct naming of methods</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><methodname>myMethod()</methodname></para>
+ </listitem>
+
+ <listitem>
+ <para><methodname>someNiceMethodName()</methodname></para>
+ </listitem>
+
+ <listitem>
+ <para><methodname>betterWriteLongMethodNamesThanNamesNobodyUnderstands()</methodname></para>
+ </listitem>
+
+ <listitem>
+ <para><methodname>singYMCALoudly()</methodname></para>
+ </listitem>
+
+ <listitem>
+ <para><methodname>__construct()</methodname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+ </section>
+
+ <section>
+ <title>Variable names</title>
+
+ <para>Variable names are written in <varname>lowerCamelCase</varname>
+ and should be</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>self-explaining</para>
+ </listitem>
+
+ <listitem>
+ <para>not shortened beyond recognition, but rather longer if it
+ makes their meaning clearer</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The following example shows two variables with the same meaning
+ but different naming. You'll surely agree the longer versions are
+ better (don't you ...?).</para>
+
+ <example>
+ <title>Correct naming of variables</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><varname>$singletonObjectsRegistry</varname></para>
+ </listitem>
+
+ <listitem>
+ <para><varname>$argumentsArray</varname></para>
+ </listitem>
+
+ <listitem>
+ <para><varname>$aLotOfHTMLCode</varname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+
+ <example>
+ <title>Incorrect naming of variables</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><varname>$sObjRgstry</varname></para>
+ </listitem>
+
+ <listitem>
+ <para><varname>$argArr</varname></para>
+ </listitem>
+
+ <listitem>
+ <para><varname>$cx</varname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+
+ <para>As a special exception you may use variable names like
+ <varname>$i</varname>, <varname>$j</varname> and <varname>$k</varname>
+ for numeric indexes in <function>for</function> loops if it's clear
+ what they mean on the first sight. But even then you might want to
+ avoid them.</para>
+ </section>
+
+ <section>
+ <title>Constant names</title>
+
+ <para>All constant names are written in
+ <constant>UPPERCASE</constant>. This includes
+ <constant>TRUE</constant>, <constant>FALSE</constant> and
+ <constant>NULL</constant>. Words can be separated by underscores - you
+ can also use the underscore to group constants thematically:</para>
+
+ <example>
+ <title>Correct naming of constants</title>
+
+ <itemizedlist>
+ <listitem>
+ <para><constant>STUFF_LEVEL</constant></para>
+ </listitem>
+
+ <listitem>
+ <para><constant>COOLNESS_FACTOR</constant></para>
+ </listitem>
+
+ <listitem>
+ <para><constant>PATTERN_MATCH_EMAILADDRESS</constant></para>
+ </listitem>
+
+ <listitem>
+ <para><classname>PATTERN_MATCH_VALIDHTMLTAGS</classname></para>
+ </listitem>
+ </itemizedlist>
+ </example>
+
+ <para>It is, by the way, a good idea to use constants for defining
+ regular expression patterns (as seen above) instead of defining them
+ somewhere in your code.</para>
+ </section>
+
+ <section>
+ <title>File names</title>
+
+ <para>These are the rules for naming files:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>All file names are
+ <filename>UpperCamelCase</filename>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Class and interface files are named according to the class
+ or interface they represent</para>
+ </listitem>
+
+ <listitem>
+ <para>Each file must contain only one class or interface</para>
+ </listitem>
+
+ <listitem>
+ <para>Names of files containing code for unit tests must be the
+ same as the class which is tested, appended with
+ "Test.php".</para>
+ </listitem>
+
+ <listitem>
+ <para>Files are placed in a directory structure representing the
+ namespace structure.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Here are some examples:<example>
+ <title>File naming in FLOW3</title>
+
+ <para><itemizedlist>
+ <listitem>
+ <para><filename>TemplateEngine/TemplateEngineInterface.php</filename></para>
+
+ <para>Contains the interface
+ <classname>\F3\TemplateEngine\TemplateEngineInterface</classname>
+ which is part of the package
+ <package>\F3\TemplateEngine</package></para>
+ </listitem>
+
+ <listitem>
+ <para><filename>Error/RuntimeException.php</filename></para>
+
+ <para>Contains the
+ <classname>\F3\Error\RuntimeException</classname> being a
+ part of the package <package>\F3\Error</package></para>
+ </listitem>
+
+ <listitem>
+ <para><filename>DataAccess/Manager.php</filename></para>
+
+ <para>Contains class
+ <classname>\F3\DataAccess\Manager</classname> which is part
+ of the package <package>\F3\DataAccess</package></para>
+ </listitem>
+
+ <listitem>
+ <para><filename>FLOW3/Package/Manager.php</filename></para>
+
+ <para>Contains the class
+ <classname>\F3\FLOW3\Package\Manager</classname> which is
+ part of the package <package>\F3\FLOW3</package></para>
+ </listitem>
+
+ <listitem>
+ <para><filename>Package/ManagerTest.php</filename></para>
+
+ <para>Contains the class
+ <classname>\F3\FLOW3\Package\ManagerTest</classname> which
+ is a test case for PHPUnit.</para>
+ </listitem>
+ </itemizedlist></para>
+ </example></para>
+ </section>
+ </section>
+
+ <section>
+ <title>PHP code formatting</title>
+
+ <section>
+ <title>Strings</title>
+
+ <para>In general, we use single quotes to enclose literal
+ strings:</para>
+
+ <example>
+ <title>String literals</title>
+
+ <programlisting language="php">$vision = 'Inspiring people to share';</programlisting>
+ </example>
+
+ <para>If the string itself contains single quotes or apostrophes, we
+ use double quotes:</para>
+
+ <example>
+ <title>String literals enclosed by double quotes</title>
+
+ <programlisting language="php">$message = "'Kasper' is the name of the friendly ghost.";</programlisting>
+ </example>
+
+ <para>If you'd like to insert values from variables, we prefer to
+ concatenate strings:</para>
+
+ <example>
+ <title>Variable substitution</title>
+
+ <programlisting language="php">$message = 'Hey ' . $name . ', you look ' . $look . ' today!';</programlisting>
+ </example>
+
+ <para>A space must be inserted before and after the dot for better
+ readability:</para>
+
+ <example>
+ <title>Concatenated strings</title>
+
+ <programlisting language="php">$vision = 'Inspiring people ' . 'to share.';</programlisting>
+ </example>
+
+ <para>You may break a string into multiple lines if you use the dot
+ operator. You'll have to indent each following line to mark them as
+ part of the value assignment:</para>
+
+ <example>
+ <title>Multi-line strings</title>
+
+ <programlisting language="php">$vision = 'Inspiring' .
+ 'people ' .
+ 'to ' .
+ 'share';</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Arrays</title>
+
+ <para/>
+ </section>
+
+ <section>
+ <title>Classes</title>
+
+ <para>...<example>
+ <title>Classes</title>
+
+ <programlisting language="php">namespace F3\MyPackage;
+
+class MyObject {
+
+}</programlisting>
+ </example></para>
+ </section>
+
+ <section>
+ <title>Functions and methods</title>
+
+ <para/>
+ </section>
+
+ <section>
+ <title>if statements</title>
+
+ <para><itemizedlist>
+ <listitem>
+ <para>There needs to be one space between the
+ <function>if</function> keyword and the opening brace "(" of the
+ test expression</para>
+ </listitem>
+
+ <listitem>
+ <para>After the closing brace ")" of the test expression follows
+ one space before the curly brace "{"</para>
+ </listitem>
+
+ <listitem>
+ <para><function>else</function> and <function>elseif</function>
+ are on the same line as their corresponding curly braces</para>
+ </listitem>
+ </itemizedlist><example>
+ <title>if statements</title>
+
+ <programlisting language="php">if ($something || $somethingElse) {
+ doThis();
+} else {
+ doSomethingElse();
+}
+
+if (allGoesWrong() === TRUE) throw new \Exception('Hey, all went wrong!', 123);
+
+if (weHaveALotOfCriteria() === TRUE
+ && notEverythingFitsIntoOneLine() === TRUE
+ || youJustTendToLikeIt() === TRUE) {
+ doThis();
+
+} else {
+ ...
+}</programlisting>
+ </example></para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Documentation</title>
+
+ <para>All code must be documented with inline comments. The syntax is that
+ known from the Java programming language (JavaDoc). This way code
+ documentation can automatically be generated using tools like
+ phpDocumentor or Doxygen. The "official" tool used is
+ phpDocumentor<footnote>
+ <para>We look into Doxygen as well, currently both tools have problems
+ with using namespaces in PHP.</para>
+ </footnote>, so syntax and documentation usage are chosen to work best
+ with it.</para>
+
+ <section>
+ <title>Documentation blocks</title>
+
+ <para>A file can contain different documentation blocks, relating to the
+ file itself, the class in the file and finally the members of the class.
+ A documentation block is always used for the entity it precedes.</para>
+
+ <section>
+ <title>File documentation</title>
+
+ <para>The first documentation block in the file is essential for
+ defining the package the file and it's contents belong to. Although it
+ would not be strictly needed to have the file level documentation
+ block (because each file contains only one class in FLOW3), we still
+ use it because it</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>avoids warnings when rendering the documentation</para>
+ </listitem>
+
+ <listitem>
+ <para>makes sure that even code outside of classes is assigned to
+ the correct package and documented correctly</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>That means that each file must contain a documentation block
+ like shown below, right below the header stating the license and
+ before any
+ <methodname>require</methodname>/<methodname>include</methodname>
+ calls:</para>
+
+ <example>
+ <title>Standard file level documentation block</title>
+
+ <programlisting language="php">/**
+ * @package [packagename]
+ * @subpackage [subpackage name if necessary]
+ * @version $Id$
+ */</programlisting>
+ </example>
+
+ <para>The package and version tag are mandatory, the subpackage tag is
+ optional.</para>
+
+ <important>
+ <title>$Id$, Subversion and keyword expansion</title>
+
+ <para>The $Id$ in the version tag will be expanded with information
+ about the file version by Subversion. This so-called keyword
+ expansion needs to be explicitly enabled, though! We recommend to
+ put this into your <filename>~.subversion/config</filename>
+ file:</para>
+
+ <example>
+ <title>Suggested configuration for Subversion in
+ <filename>~/.subversion/config</filename></title>
+
+ <para><literallayout>[miscellany]
+global-ignores = #*# *.rej *.orig *.bak *~ .*
+log-encoding = utf-8
+enable-auto-props = yes
+[auto-props]
+*.php = svn:keywords=Id Revision
+*.yaml = svn:keywords=Id Revision</literallayout></para>
+ </example>
+
+ <para>This does a little more than just enable the keyword
+ expansion, it also sets the character encoding for the log messages
+ and makes Subversion ignore some standard backup and metadata
+ filenames.</para>
+ </important>
+ </section>
+
+ <section>
+ <title>Class documentation</title>
+
+ <para>Classes have their own documentation block describing the
+ classes purpose, assigning a package and subpackage. Very often the
+ code within a class is expanded and modified by a number of authors.
+ We therefore recommend to add the names of the developers to the
+ method documentation. An exception should be the documentation for
+ interfaces where you list all authors in the interface documentation.
+ Exceptions itself never have an author annotation.</para>
+
+ <example>
+ <title>Standard class documentation block</title>
+
+ <programlisting language="php">/**
+ * First sentence is short description. Then you can write more, just as you like
+ *
+ * Here may follow some detailed description about what the class is for.
+ *
+ * Paragraphs are seperated by a empty line.
+ *
+ * @package [packagename]
+ * @subpackage [subpackage name if necessary]
+ * @version $Id$
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public ↩
+ License, version 3 or later
+ */
+class SomeClass {
+ ...</programlisting>
+ </example>
+
+ <example>
+ <title>Standard interface documentation block</title>
+
+ <programlisting language="php">/**
+ * First sentence is short description. Then you can write more, just as you like
+ *
+ * Here may follow some detailed description about what the interface is for.
+ *
+ * Paragraphs are seperated by a empty line.
+ *
+ * @package [packagename]
+ * @subpackage [subpackage name if necessary]
+ * @version $Id$
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public ↩
+ License, version 3 or later
+ * @author Your Name <your@email.here>
+ */
+interface SomeInterface {
+ ...</programlisting>
+ </example>
+
+ <example>
+ <title>Standard exception documentation block</title>
+
+ <programlisting language="php">/**
+ * First sentence is short description. Then you can write more, just as you like
+ *
+ * Here may follow some detailed description about what the interface is for.
+ *
+ * Paragraphs are seperated by a empty line.
+ *
+ * @package [packagename]
+ * @subpackage [subpackage name if necessary]
+ * @version $Id$
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public ↩
+ License, version 3 or later
+ */
+class SomeException extends \Exception {
+ ...</programlisting>
+ </example>
+
+ <para>Additional tags or annotations, such as @see or @aspect, can be
+ added as needed.</para>
+ </section>
+
+ <section>
+ <title>Documenting variables, constants, includes</title>
+
+ <para>Properties of a class should be documented as well. We use the
+ short version for documenting them:</para>
+
+ <example>
+ <title>Standard variable documentation block</title>
+
+ <programlisting language="php">/**
+ * A short description, very much recommended
+ * @var string
+ */
+protected $title = 'Untitled';</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Method documentation</title>
+
+ <para>For a method, at least all parameters and the return value must
+ be documented. Please also add your name by using the @author tag. The
+ @access tag must not be used as it makes no sense (we're using PHP
+ >= 5 for some reason, don't we?)</para>
+
+ <example>
+ <title>Standard method documentation block</title>
+
+ <programlisting language="php">/**
+ * A description for this method
+ *
+ * Paragraphs are seperated by a empty line.
+ *
+ * @param \F3\FLOW3\Log\LoggerInterface $logger A logger
+ * @param string $someString This parameter should contain some string
+ * @return void
+ * @author Your Name <your@email.here>
+ */
+public function __construct(\F3\FLOW3\Log\LoggerInterface $logger, $someString) {
+ ...</programlisting>
+ </example>
+
+ <para>A special note about the @param tags: The parameter type and
+ name are seperated by one space, not aligned. Do not put a colon after
+ the parameter name. Always document the return type, even if it is
+ void - that way it is clearly visible it hasn't just been
+ forgotten.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Documentation tags</title>
+
+ <para>There are quite a few documentation tags that can be used. Here is
+ a list of tags that can and should be used within the TYPO3
+ project:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>@author</para>
+ </listitem>
+
+ <listitem>
+ <para>@copyright</para>
+ </listitem>
+
+ <listitem>
+ <para>@deprecated</para>
+ </listitem>
+
+ <listitem>
+ <para>@example</para>
+ </listitem>
+
+ <listitem>
+ <para>@filesource</para>
+ </listitem>
+
+ <listitem>
+ <para>@global</para>
+ </listitem>
+
+ <listitem>
+ <para>@ignore</para>
+ </listitem>
+
+ <listitem>
+ <para>@internal</para>
+ </listitem>
+
+ <listitem>
+ <para>@license</para>
+ </listitem>
+
+ <listitem>
+ <para>@link</para>
+ </listitem>
+
+ <listitem>
+ <para>@package</para>
+ </listitem>
+
+ <listitem>
+ <para>@param</para>
+ </listitem>
+
+ <listitem>
+ <para>@return</para>
+ </listitem>
+
+ <listitem>
+ <para>@see</para>
+ </listitem>
+
+ <listitem>
+ <para>@since</para>
+ </listitem>
+
+ <listitem>
+ <para>@subpackage</para>
+ </listitem>
+
+ <listitem>
+ <para>@todo</para>
+ </listitem>
+
+ <listitem>
+ <para>@uses</para>
+ </listitem>
+
+ <listitem>
+ <para>@var</para>
+ </listitem>
+
+ <listitem>
+ <para>@version</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Some are useless for PHP5 and PHP6, such as the tag for declaring
+ a variable or method private:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>@access</para>
+ </listitem>
+ </itemizedlist>
+
+ <important>
+ <para>If you are unsure about the meaning or ose of those tags, look
+ them up in the phpDocumentor manual, rather than doing
+ guesswork.</para>
+ </important>
+
+ <note>
+ <para>There are more tags which are used in FLOW3, however their
+ purpose is not documention but configuration. Currently annotations
+ are also used for defining aspects and advices for the AOP framework
+ as well as for giving instructions to the Persistence
+ framework.</para>
+ </note>
+ </section>
+ </section>
+
+ <section>
+ <title>Coding</title>
+
+ <section>
+ <title>Overview</title>
+
+ <para>This section gives you an overview of FLOW3's coding rules and
+ best practices.</para>
+ </section>
+
+ <section>
+ <title>General PHP best practices</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>All code should be object oriented. This means there should be
+ no functions outside classes if not absolutely necessary. If you
+ need a "container" for some helper methods, consider creating a
+ static class.</para>
+ </listitem>
+
+ <listitem>
+ <para>All code must make use of PHP5 / PHP6 advanced features for
+ object oriented programming.<itemizedlist>
+ <listitem>
+ <para>Use PHP namespaces (see <link
+ xl:href="http://www.php.net/manual/language.namespaces.php">http://www.php.net/manual/language.namespaces.php</link>)</para>
+ </listitem>
+
+ <listitem>
+ <para>Always declare the scope (public, protected, private) of
+ methods and member variables</para>
+ </listitem>
+
+ <listitem>
+ <para>Make use of iterators and exceptions, have a look at the
+ SPL (see <link
+ xl:href="http://www.php.net/manual/ref.spl.php">http://www.php.net/manual/ref.spl.php</link>
+ and <link
+ xl:href="http://www.php.net/~helly/php/ext/spl/">http://www.php.net/~helly/php/ext/spl/</link>)</para>
+ </listitem>
+
+ <listitem>
+ <para>Make use of type-hinting wherever possible (see <link
+ xl:href="http://www.php.net/manual/language.oop5.typehinting.php">http://www.php.net/manual/language.oop5.typehinting.php</link>)</para>
+ </listitem>
+ </itemizedlist></para>
+ </listitem>
+
+ <listitem>
+ <para>Always use <code><?php</code> as opening tags (never only
+ <code><?</code>)</para>
+ </listitem>
+
+ <listitem>
+ <para>Add an encoding declaration as the first line of your PHP
+ code, followed by the namespace declaration. For TYPO3 the encoding
+ must be <acronym>UTF-8</acronym></para>
+
+ <example>
+ <title>Encoding statement for .php files</title>
+
+ <programlisting language="php"><?php
+declare(ENCODING = 'utf-8');
+namespace F3\Your\Stuff\Here;
+
+...</programlisting>
+ </example>
+ </listitem>
+
+ <listitem>
+ <para>Prefer strict comparisons whenever possible, to avoid problems
+ with truthy and falsy <sidebar>
+ <figure>
+ <title>Truthy and falsy are fuzzy...</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="AppendixCodingGuidelines_TrueFalse.jpg"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </sidebar>values that might behave different than what you expect.
+ Here are some examples:<example>
+ <title>Examples of good and bad comparisons</title>
+
+ <para><programlisting language="php">if ($template) // BAD
+if (isset($template)) // GOOD
+if ($template !== NULL)) // GOOD
+if ($template !== '')) // GOOD
+
+if (strlen($template) > 0) // BAD! strlen("-1") is greater than 0
+if (is_string($template) && strlen($template) >0) // BETTER
+
+if ($foo == $bar) // BAD, avoid truthy comparisons
+if ($foo != $bar) // BAD, avoid falsy comparisons
+if ($foo === $bar)) // GOOD
+if ($foo !== $bar)) // GOOD</programlisting></para>
+ </example></para>
+ </listitem>
+
+ <listitem>
+ <para>Order of methods in classes. To gain a better overview, it
+ helps if methods in classes are always ordered in a certain way. We
+ prefer the following:<orderedlist>
+ <listitem>
+ <para>constructor</para>
+ </listitem>
+
+ <listitem>
+ <para>injection methods</para>
+ </listitem>
+
+ <listitem>
+ <para>initialization methods (including
+ initializeObject())</para>
+ </listitem>
+
+ <listitem>
+ <para>public methods</para>
+ </listitem>
+
+ <listitem>
+ <para>protected methods</para>
+ </listitem>
+
+ <listitem>
+ <para>private methods</para>
+ </listitem>
+
+ <listitem>
+ <para>shutdown methods</para>
+ </listitem>
+
+ <listitem>
+ <para>destructor</para>
+ </listitem>
+ </orderedlist></para>
+ </listitem>
+
+ <listitem>
+ <para>Avoid double-negation. Instead of
+ <literal>exportSystemView(..., $noRecurse)</literal> use
+ <literal>exportSystemView(..., $recurse)</literal>. It is more
+ logical to pass TRUE if you want recursion instead of having to pass
+ FALSE. In general, parameters negating things are a bad idea.</para>
+ </listitem>
+ </itemizedlist>
+
+ <section>
+ <title>Comments</title>
+
+ <para>In general, comments are a good thing and we strive for creating
+ a well-documented source code. However, inline comments can often be a
+ sign for a bad code structure or method naming.<footnote>
+ <para>This is also referred to as a bad "smell" in the theory of
+ Refactoring. We highly recommend reading "Refactoring" by Martin
+ Fowler - if you didn't already.</para>
+ </footnote>As an example, consider the following code:<example>
+ <title>Bad coding smell: Comments</title>
+
+ <programlisting language="php"> // We only allow valid persons:
+if (is_object($p) && strlen($p->lastN) > 0 && $p->hidden === FALSE && ↩
+ $this->environment->moonPhase === MOON_LIB::CRESCENT) {
+ $xmM = $thd;
+}</programlisting>
+ </example></para>
+
+ <para>This is a perfect case for the refactoring technique "extract
+ method": In order to avoid the comment, create a new method which is
+ as explanatory as the comment:</para>
+
+ <example>
+ <title>Smells better!</title>
+
+ <programlisting language="php">if ($this->isValidPerson($person) {
+ $xmM = $thd;
+}</programlisting>
+ </example>
+
+ <para>Bottom line is: You may (and are encouraged to) use inline
+ comments if they support the readability of your code. But always be
+ aware of possible design flaws you probably try to hide with
+ them.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Error handling and exceptions</title>
+
+ <para>FLOW3 makes use of a hierarchy for its exception classes. The
+ general rule is to throw preferably specific exceptions and usually let
+ them bubble up until a place where more general exceptions are catched.
+ Consider the following example:</para>
+
+ <para>Some method tried to retrieve an object from the object manager.
+ However, instead of providing a string containing the object name, the
+ method passed an object (of course not on purpose - something went
+ wrong). The object manager now throws an
+ <classname>InvalidObjectName</classname> exception. In order to catch
+ this exception you can, of course, catch it specifically - or only
+ consider a more general <classname>Object</classname> exception (or an
+ even more general <classname>FLOW3</classname> exception). This all
+ works because we have the following hierarchy:</para>
+
+ <literallayout>+ \F3\FLOW3\Exception
+ + \F3\FLOW3\Object\Exception
+ + \F3\FLOW3\Object\Exception\InvalidObjectName</literallayout>
+
+ <section>
+ <title>Throwing an exception</title>
+
+ <para>When throwing an exception, make sure to provide a clear error
+ message and an error code being the unix timestamp of when you write
+ the <function>throw</function> statement. That error code must be
+ unique, so watch out when doing copy and paste!</para>
+
+ <para>For every exception there should be a page on the TYPO3 wiki, as
+ exception messages link to that page, identified by the error code
+ (unix timestamp).</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Cross platform issues</title>
+
+ <para/>
+ </section>
+ </section>
+</appendix>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<book version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:xl="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:ns="http://docbook.org/ns/docbook"
+ xmlns:mathml="http://www.w3.org/1998/Math/MathML">
+
+ <title>FLOW3 Framework</title>
+
+ <!-- Meta information -->
+
+ <info>
+ <abstract>
+ <para>FLOW3 is a modern application framework for enterprise-grade PHP
+ applications. This reference describes FLOW3's main features.</para>
+ </abstract>
+
+ <author>
+ <personname>
+ <firstname>Robert</firstname>
+
+ <surname>Lemke</surname>
+ </personname>
+
+ <email>robert@typo3.org</email>
+ </author>
+
+ <author>
+ <personname>
+ <firstname>Karsten</firstname>
+
+ <surname>Dambekalns</surname>
+ </personname>
+
+ <email>karsten@typo3.org</email>
+ </author>
+
+ <copyright>
+ <year>2007</year>
+
+ <year>2008</year>
+
+ <year>2009</year>
+
+ <holder>Robert Lemke</holder>
+
+ <holder>Karsten Dambekalns</holder>
+ </copyright>
+ </info>
+
+ <!-- Chapters -->
+
+ <xi:include href="Introduction.xml" />
+
+ <xi:include href="MVCFramework.xml" />
+
+ <xi:include href="PersistenceFramework.xml" />
+
+ <!-- Appendixes -->
+
+ <xi:include href="AppendixCodingGuidelines.xml" />
+
+</book>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:ns6="http://www.w3.org/1999/xlink"
+ xmlns:ns5="http://www.w3.org/2000/svg"
+ xmlns:ns4="http://www.w3.org/1999/xhtml"
+ xmlns:ns3="http://www.w3.org/1998/Math/MathML"
+ xmlns:ns="http://docbook.org/ns/docbook">
+ <title>Introduction</title>
+
+ <para>FLOW3 is a PHP-based application framework. It is especially
+ well-suited for enterprise-grade applications and explicitly supports
+ Domain-Driven Design, a powerful software design philosophy. Convention over
+ configuration, Test-Driven Development, Continuous Integration and an
+ easy-to-read source code are other important principles we follow for the
+ development of FLOW3.</para>
+
+ <para>Although we created FLOW3 as the foundation for the TYPO3 Content
+ Management System, its approach is general enough to be useful as a basis
+ for any other PHP application. We're happy to share the FLOW3 framework with
+ the whole PHP community and are looking forward to the hundreds of new
+ features and enhancements contributed as packages by other enthusiastic
+ developers. In fact most of the packages which will be developed for the
+ TYPO3 CMS can be used in any other FLOW3-based application. In essence this
+ reflects the vision of the TYPO3 project: "Inspiring People to
+ Share".</para>
+
+ <para>This reference describes all features of FLOW3 and provides you with
+ in-depth information. If you'd like to get a feeling for FLOW3 and get
+ started quickly, we suggest that you try out our Getting Started tutorial
+ first.</para>
+
+ <note>
+ <para>Please note that FLOW3 is still under heavy development. Although we
+ hope that the documentation is at least accurate and up to date, it is by
+ no means complete and most likely not proof-read. If you find errors or
+ would like to help us improving the documentation, we're happy to hear
+ from you on our mailing list!</para>
+ </note>
+
+ <section>
+ <title>Overview</title>
+
+ <para>The FLOW3 framework is composed of the following submodules:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The <emphasis>FLOW3</emphasis> bootstrap takes care of
+ configuring and initializing the whole framework.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Package</emphasis> Manager allows you to download,
+ install, configure and uninstall packages.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Object</emphasis> Manager is in charge of
+ building, caching and combining objects.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Configuration Framework</emphasis> reads and
+ cascades various kinds of configuration from different sources and
+ provides access to it.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Resource</emphasis> Manager contains functions for
+ providing, caching, securing and retrieving resources.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>MVC</emphasis> Framework takes care of requests
+ and responses and provides you with a powerful, easy-to use
+ Model-View-Controller implementation.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Cache</emphasis> framework provides different
+ kinds of caches with can be combined with a selection of cache
+ backends.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Error</emphasis> module handles errors and
+ exceptions and provides utility classes for this purpose.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Log</emphasis> module provides simple but powerful
+ means to log any kind of event or signal into different types of
+ backends.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Signal Slot</emphasis> module implements the
+ event-driven concept of signals and slots through AOP aspects.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Validation</emphasis> module provides a validation
+ and filtering framework with built-in rules as well as support for
+ custom validation of any object.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Property</emphasis> module implements the concept
+ of property editors and is used for setting and retrieving object
+ properties.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Reflection</emphasis> API complements PHP's
+ built-in reflection support by advanced annotation handling and a
+ cached reflection service.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>AOP</emphasis> Framework enables you to use the
+ powerful techniques of <firstterm>Aspect Oriented
+ Programming</firstterm>.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Persistence</emphasis> module allows you to
+ transparently persist your objects following principles of
+ <emphasis>Domain Driven Design</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Security</emphasis> Framework enforces security
+ policies and provides an API for managing those.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Session</emphasis> Framework takes care of session
+ handling and storing session information in different backends</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Locale</emphasis> service manages languages and
+ other regional settings and makes them accessible to other packages
+ and FLOW3 sub packages.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>Utility</emphasis> module is a library of useful
+ general-purpose functions for file handling, algorithms, environment
+ abstraction and more.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>If you are overwhelmed by the amount of information in this
+ reference, just keep in mind that you don't need to know all of it to
+ write your own FLOW3 packages. You can always come back and look up a
+ specific topic once you need to know about it - that's what references are
+ for. But even if you don't need to know everything, we recommend that you
+ get familiar with the concepts of each module and read the whole manual.
+ This way you make sure that you don't miss any of the great features FLOW3
+ provides and hopefully feel inspired to produce clean and
+ easy-maintainable code.</para>
+
+ <tip>
+ <para>A strong coffee helps most people over even the longest
+ documentation.</para>
+ </tip>
+ </section>
+</chapter>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:ns52="http://www.w3.org/1998/Math/MathML"
+ xmlns:ns5="http://www.w3.org/1999/xlink"
+ xmlns:ns4="http://www.w3.org/2000/svg"
+ xmlns:ns3="http://www.w3.org/1999/xhtml"
+ xmlns:ns="http://docbook.org/ns/docbook">
+ <title>MVC Framework</title>
+
+ <section>
+ <title>Introduction</title>
+
+ <section>
+ <title>Model-View-Controller</title>
+
+ <para>In the design of FLOW3's architecture we have taken great care to
+ separate concerns and assign each part of the framework with
+ well-defined tasks. The separation of concerns is an important principle
+ of good software design and its most prominent representative probably
+ is the Model-View-Controller pattern. MVC separates the business logic
+ from the presentation by splitting up user interaction into three
+ roles:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The <emphasis>model</emphasis> is an object which contains
+ data and business logic of a certain domain. It doesn't contain any
+ information about the presentation of that data, but rather defines
+ the behaviour. In the FLOW3 project we prefer a special kind of
+ model, the <link
+ ns5:href="http://martinfowler.com/eaaCatalog/domainModel.html">Domain
+ Model</link>.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>view</emphasis> represents the display of the
+ model on the web or another output channel. Views only display data,
+ they don't build or modify it.</para>
+ </listitem>
+
+ <listitem>
+ <para>The <emphasis>controller</emphasis> reacts on user input,
+ selects and manipulates the model as accordingly, selects a view and
+ passes it the prepared model for rendering.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This diagram outlines the collaboration between model, view and
+ controller:</para>
+
+ <figure>
+ <title>Model-View-Controller Pattern</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata contentdepth="100%"
+ fileref="MVCFramework_ModelViewController.png"
+ scalefit="1" width="100%"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+ </section>
+
+ <section>
+ <title>Other Patterns Used</title>
+
+ <para>Design Patterns (and MVC is one of them) are not only great for
+ solving reoccuring design problems in a structured manner - they also
+ help you communicating software designs. The following patterns play an
+ important role in FLOW3's MVC mechanism and might give you a better idea
+ of the overall design:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Incoming requests are handled by a Request Handler which takes
+ the role of a <link ns5:href="???">Front Controller</link>.</para>
+ </listitem>
+
+ <listitem>
+ <para><link ns5:href="???">Template View</link> is the most commonly
+ used pattern for views, but <link ns5:href="???">Transform
+ Views</link> and <link ns5:href="???">Two-Step Views</link> are
+ equally supported.</para>
+ </listitem>
+
+ <listitem>
+ <para>The preferred type of model is the <link ns5:href="???">Domain
+ Model</link>.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Hello World!</title>
+
+ <para>Let's start with an example before we go into greater detail of
+ request handling and the internals of the MVC framework. The minimal
+ approach is to create an Action Controller which just returns
+ <quote>Hello World!</quote>. To begin with, we need to create some
+ directories which contain the code of our FLOW3 package and eventually
+ the controller class:</para>
+
+ <literallayout>Packages/
+ Demo/
+ Classes/
+ Controller/
+ DefaultController.php</literallayout>
+
+ <para>The DefaultController class looks as simple as this (leaving out
+ the very recommended comments):</para>
+
+ <example>
+ <title>Hello World! controller</title>
+
+ <programlisting language="PHP">namespace F3\Demo\Controller;
+
+class DefaultController extends \F3\FLOW3\MVC\Controller\ActionController {
+ public function indexAction() {
+ return "Hello World!";
+ }
+}</programlisting>
+ </example>
+
+ <para>Provided that the document root of your local server points to
+ FLOW3's <filename>Public/</filename> directory, you will get the
+ following output when calling the URI
+ <uri>http://localhost/demo/</uri>:</para>
+
+ <screen>Hello World!</screen>
+
+ <para>Great, that was easy - but didn't we say that it's the view's
+ responsibility to take care of the presentation? Let's create a simple
+ PHP-based view for that purpose:</para>
+
+ <literallayout>Packages/
+ Demo/
+ Classes/
+ Controller/
+ DefaultController.php
+ View/
+ DefaultIndex.php</literallayout>
+
+ <para>The view's code is equally trivial:</para>
+
+ <example>
+ <title>Hello World! view</title>
+
+ <programlisting language="php">namespace F3\Demo\View;
+
+class DefaultIndex extends \F3\FLOW3\MVC\View\AbstractView {
+ public function render() {
+ return "Hello World!";
+ }
+}</programlisting>
+ </example>
+
+ <para>Finally our action controller needs a little tweak to return the
+ rendered view instead of shouting <quote>Hello World!</quote>
+ itself:</para>
+
+ <example>
+ <title>Improved Hello World! controller</title>
+
+ <programlisting language="php">namespace F3\Demo\Controller;
+
+class DefaultController extends \F3\FLOW3\MVC\Controller\ActionController {
+ public function indexAction() {
+ return $this->view->render();
+ }
+}</programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>Recommended File Structure</title>
+
+ <para>As you have seen in the hello world example, conventions for the
+ directory layout simplify your development a lot. There's no need to
+ register controllers, actions or views if you follow our recommended
+ file structure. These are the rules:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Controllers</emphasis> are located in their own
+ directory <filename>Controller</filename> just below the
+ <filename>Classes</filename> directory of your package. They can
+ have arbitrary names while the
+ <classname>DefaultController</classname> has a special meaning: If
+ the package was specified in the request but no controller, the
+ <classname>DefaultController</classname> will be used.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>View</emphasis> classes are situated below a
+ <filename>View</filename> directory. The classname of the view is a
+ combination of the name of the controller and the name of the
+ action.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This sample directory layout demonstrates the above rules:</para>
+
+ <example>
+ <title>Sample file structure</title>
+
+ <literallayout>Packages/
+ Demo/
+ Classes/
+ Controller/
+ DefaultController.php
+ CustomerController.php
+ OrderController.php
+ View/
+ DefaultIndex.php
+ CustomerIndex.php
+ CustomerList.php
+ CustomerDetails.php
+ OrderList.php</literallayout>
+ </example>
+
+ <para>Adhering to these conventions has the advantage that the classname
+ of the view for example is resolved automatically. However it is
+ possible (and not really difficult) to deviate from this layout and have
+ a completely different structure.</para>
+ </section>
+
+ <section>
+ <title>From the URI to the view</title>
+
+ <caution>
+ <para>For the example URIs we assume that the web root directory of
+ your local server points to FLOW3's <filename>public/</filename>
+ directory. If that's not the case you have to extend the URI
+ accordingly.</para>
+ </caution>
+
+ <para>FLOW3 provides a standard way of resolving the URI to your
+ MVC-Objects.</para>
+
+ <para>Say, you want to see the list of customers (based on the
+ file-structure-example above). The URI to get the list would be:
+ <uri>http://localhost/demo/customer/list.html</uri> or just
+ <uri>http://localhost/demo/customer/list</uri>.</para>
+
+ <para>This URI will be resolved into the package-name
+ (<emphasis>Demo</emphasis>), controller-name
+ (<emphasis>Customer</emphasis>), action-name(<emphasis>list</emphasis>)
+ and format-name (<emphasis>html</emphasis> - which is the default
+ format).</para>
+
+ <para>Depending on that, the controller
+ <classname>\F3\Demo\Controller\CustomerController</classname> (Pattern:
+ '<code>F3\@package\Controller\@controllerController'</code>) and its
+ method <methodname>listAction()</methodname> will be used. The
+ corresponding view is <classname>\F3\Demo\View\CustomerList</classname>
+ (Pattern:
+ <code>'F3\@package\View\@controller@action@format'</code>).</para>
+
+ <para>If you have a look at the view pattern, you see, that you can
+ easily add a view that creates an xml-output by creating the class
+ <classname>\F3\Demo\View\CustomerListXML</classname>. You will get the
+ xml-output by calling the URI
+ <uri>http://localhost/demo/customer/list.xml</uri>.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Request and Response</title>
+
+ <para>No matter if a FLOW3 application runs in a web context or is
+ launched from the command line, the basic workflow is always the same: The
+ user request is analyzed and forwarded to an appropriate controller which
+ decides on which actions to take and finally returns a response which is
+ handed over to the user. This section highlights the flow and the
+ collaborators in the request-response machinery.</para>
+
+ <section>
+ <title>Request Processing Overview</title>
+
+ <para>A sequence diagram is worth a thousand words said my grandma, so
+ let's take a look at the standard request-response workflow in
+ FLOW3:</para>
+
+ <figure>
+ <title>Example of a Web Request-Response Workflow</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata contentdepth="100%"
+ fileref="MVCFramework_RequestResponseWorkflow.png"
+ scalefit="1" width="100%"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>As you see, there are a lot of parts of the framework involved for
+ answering a request - and the diagram doesn't even consider caching or
+ forwarding of requests. But we didn't create this structure just for the
+ fun of it - each object plays an important role as you'll see in the
+ next sections.</para>
+ </section>
+
+ <section>
+ <title>Request Handler</title>
+
+ <para>The request handler takes the important task to handle and respond
+ to a request. There exists exactly one request handler for each request
+ type. By default web and command line requests are supported, but more
+ specialized request handlers can be developed, too.</para>
+
+ <para>Before one of the request handlers comes to play, the framework
+ needs to determine which of them is the most suitable for the current
+ request. The request handler resolver asks all of the registered request
+ handlers to rate on a scale how well they can handle the current raw
+ request. The resolver then chooses the request handler with the most
+ points and passes over the control.</para>
+
+ <para>Custom request handlers for special purposes just need to
+ implement the
+ <interfacename>\F3\FLOW3\MVC\RequestHandlerInterface</interfacename>.
+ All classes implementing that interface are automatically registered and
+ will be considered while resolving a suitable request handler.</para>
+ </section>
+
+ <section>
+ <title>Request Builder</title>
+
+ <para>When a request handler receives a raw request, it needs to build a
+ request object which can be passed to the dispatcher and later to the
+ controller. The request building delegated to a request builder which
+ can build the required request type (ie. web, CLI etc.).</para>
+
+ <para>The building process mainly consists of</para>
+
+ <procedure>
+ <step>
+ <para>create a new request object</para>
+ </step>
+
+ <step>
+ <para>set some request-type specific parameters (like the request
+ URI for a web request)</para>
+ </step>
+
+ <step>
+ <para>determine and set the responsible controller, action and
+ action arguments</para>
+ </step>
+ </procedure>
+
+ <para>Especially the last step is important and requires some more or
+ less complex routing in case of web requests.</para>
+ </section>
+
+ <section>
+ <title>Request Processors</title>
+
+ <para>Requests which were built by the request builder usually fit the
+ most common needs. For special demands it is possible to postprocess the
+ request object before it is sent to the dispatcher. Request processors
+ can be registered through the Request Processor Chain Manager and are -
+ as the name suggests - invoked in a chain.</para>
+ </section>
+
+ <section>
+ <title>Request Dispatcher</title>
+
+ <para>The final task of the MVC framework consists in dispatching the
+ request to the controller specified in the request object. The request
+ dispatcher will try to call the action specified in the request object
+ and if none was specified fall back on a default action.</para>
+
+ <note>
+ <para>There are more features planned for the dispatcher, but at the
+ time of this writing they have not yet been implemented.</para>
+ </note>
+ </section>
+
+ <section>
+ <title>Request Types</title>
+
+ <para>FLOW3 supports the most important request types out of the box.
+ Additional request types can easily be implemented by extending the
+ <classname>\F3\FLOW3\MVC\Request</classname> class and registering a
+ request handling which can handle the new request type (and takes care
+ of building the request object). Here are the request types which come
+ with the default FLOW3 distribution:</para>
+
+ <section>
+ <title>Web Request / Response</title>
+
+ <para>Web requests are the most common request types. Currently only
+ the basic features are implemented, but further options - especially
+ for the web response - are in the pipeline.</para>
+ </section>
+
+ <section>
+ <title>CLI Request / Response</title>
+
+ <para>Requests from the command line are recognized by the used SAPI
+ (Server Application Programming Interface). This request type is
+ basically the same as the generic request type and mainly exists as a
+ marker.</para>
+ </section>
+
+ <section>
+ <title>AJAX Request / Response</title>
+
+ <note>
+ <para>This request type has not yet been implemented</para>
+ </note>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Controller</title>
+
+ <para></para>
+
+ <section>
+ <title>Action Controller</title>
+
+ <para>Setting $this->viewObjectName to a view object name overrides
+ the automatic resolving of the view name. Can be used for definining a
+ standard view, for example \F3\Fluid\View\TemplateView.</para>
+
+ <para></para>
+
+ <section>
+ <title>Initialization Methods</title>
+
+ <para>initializeController</para>
+
+ <para>initializeAction</para>
+
+ <para>initializeView</para>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Supported Request Types</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Arguments</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Action Methods</title>
+
+ <para>$this->indexActionMethodName</para>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Action View</title>
+
+ <para>- $this->initializeView = TRUE | FALSE</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Other Controllers</title>
+
+ <section>
+ <title>Abstract Controller</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Request Handling Controller</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Default Controller</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Not Found Controller</title>
+
+ <para>The
+ <classname>F3\FLOW3\MVC\Controller\NotFoundController</classname> is
+ used whenever no other controller could be resolved which would match
+ the current request. It displays a generic "404 Page Not Found"
+ message.</para>
+
+ <para>It is possible to define your own custom controller which is
+ used in these cases. Just specify the object name in the FLOW3
+ settings.</para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>View</title>
+
+ <para></para>
+
+ <section>
+ <title>Template View</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Special Views</title>
+
+ <section>
+ <title>Default View</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Empty View</title>
+
+ <para></para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Helpers</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Model</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Routing</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>CLI request handling</title>
+
+ <para>FLOW3's CLI request handling offers a comfortable and flexible way
+ of calling code from the command line:</para>
+
+ <para><command>php index.php [<replaceable>command</replaceable>]
+ [<replaceable>options</replaceable>] [--]
+ [<replaceable>arguments</replaceable>]</command></para>
+
+ <para><replaceable>command</replaceable>,
+ <replaceable>options</replaceable> and
+ <replaceable>arguments</replaceable> are optional, with varying results.
+ The command structure follows what is commonly accpeted on unixoid systems
+ for CLI programs:<variablelist>
+ <varlistentry>
+ <term>command</term>
+
+ <listitem>
+ <para>If not given, the default controller of the FLOW3 package is
+ used and it's index action is called. While this is an allowed
+ call, it hardly makes sense (other than checking if FLOW basically
+ works). If command is given then it is defined as
+ <emphasis><replaceable>package</replaceable>
+ [[<replaceable>sub1..N</replaceable>]
+ <replaceable>controller</replaceable>
+ <replaceable>action</replaceable>]</emphasis></para>
+
+ <para>First part is always the package. If only the package is
+ given, it's default controller's index action is called.</para>
+
+ <para>If at least three command parts are given, the last two
+ sepcify controller and action. Anything in between specifys a sub
+ package structure.<example>
+ <title>Some FLOW3 CLI command specifications</title>
+
+ <para><literal>testing cli run</literal> would call the "run"
+ action of the "cli" controller in the "Testing" package</para>
+
+ <para><literal>typo3cr admin setup default</literal> would
+ call the "setup" controller's "default" action in the
+ subpackage "admin" of the package "TYPO3CR"</para>
+ </example></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>options</term>
+
+ <listitem>
+ <para>Options are either short- or long-style. The first option
+ detected ends collecting command parts. Here are some
+ examples:<example>
+ <title>Giving options to FLOW3 CLI requests</title>
+
+ <para><literal>-o -f=value --a-long-option --with-spaces="is
+ possible" --input file1 -o=file2 --event-this =
+ works</literal></para>
+ </example></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>arguments</term>
+
+ <listitem>
+ <para>Arguments can follow and will be available to the called
+ controller in the request object. To distinguish between
+ <replaceable>command</replaceable> and
+ <replaceable>arguments</replaceable> in cases where no
+ <replaceable>options</replaceable> are given the seperator
+ <literal>--</literal> must be used.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist></para>
+
+ <example>
+ <title>Some FLOW3 CLI commands</title>
+
+ <para>Calling the TYPO3CR setup:</para>
+
+ <para><code>php index.php typo3cr admin setup setup
+ --dsn=sqlite:/tmp/typo3cr.db --indexlocation=/tmp/lucene/</code></para>
+
+ <para>Running FLOW3 unit tests:</para>
+
+ <para><code>php index.php testing cli run --package-key=FLOW3
+ --output-directory=./</code></para>
+
+ <para>Rendering the FLOW3 documentation to HTML:</para>
+
+ <para><code>php index.php doctools render render -p FLOW3 -o
+ flow3-manual/</code></para>
+ </example>
+ </section>
+</chapter>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter version="5.0" xmlns="http://docbook.org/ns/docbook"
+ xmlns:xl="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:ns="http://docbook.org/ns/docbook"
+ xmlns:mathml="http://www.w3.org/1998/Math/MathML">
+ <title>Persistence Framework</title>
+
+ <section>
+ <title>Introductory Example</title>
+
+ <para>Let's look at the following example as an introduction to how FLOW3
+ handles persistence. We have a domain model of a Blog, consisting of Blog,
+ Post, Comment and Tag objects:<figure>
+ <title>The objects of the Blog domain model</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata contentdepth="100%"
+ fileref="PersistenceFramework_BlogDomainModel.png"
+ scalefit="1" width="100%"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure></para>
+
+ <para>Connections between those objects are built by simple references in
+ PHP, as a look at the <methodname>addPost()</methodname> method of the
+ <classname>Blog</classname> class shows:<example>
+ <title>The Blog's addPost() method</title>
+
+ <para><programlisting language="php">/**
+ * @param \F3\Blog\Domain\Post $post
+ * @return void
+ */
+public function addPost(\F3\Blog\Domain\Post $post) {
+ $this->posts[$post->getIdentifier()] = $post;
+}</programlisting></para>
+ </example></para>
+
+ <para>The same principles are applied to the rest of the classes,
+ resulting in an object tree of a blog object holding several posts, those
+ in turn having references to their associated comments and tags. But now
+ we need to make sure the Blog and the data in it are still available the
+ next time we need them. In the good old days of programming you might have
+ added some ugly database calls all over the system at this point. In the
+ currently widespread practice of loving Active Record you'd still add
+ save() methods to all or most of your objects. But can it be even
+ easier?</para>
+
+ <para>To access an object you need to hold some reference to it. You can
+ get that reference by creating an object or by following some reference to
+ it from some object you already have. This leaves you at a point where you
+ need to find that "first object". This is done by using a Repository. A
+ Repository is the librarian of your system, knowing about all the objects
+ it manages. In our model the Blog is the entry point to our object tree,
+ so we will add a BlogRepository, allowing us to find Blogs by the criteria
+ we need.</para>
+
+ <para>Now, before we can find a Blog, we need to create and save one. What
+ we do is create the object (using FLOW3's object factory) and add it to
+ the BlogRepository. This will automagically persist your Blog and you can
+ retrieve it again later. No save() call needed. Oh, and the posts,
+ comments and tags in your Blog are persisted as well, of course.</para>
+
+ <para>For all that magic to work as expected, you need to give some hints.
+ This doesn't mean you need to write tons of XML, a few annotations in your
+ code are enough:<example>
+ <title>Persistence-related annotations in the Blog class</title>
+
+ <para><programlisting language="php">/**
+ * A Blog object
+ *
+ * @package Blog
+ * @entity
+ */
+class Blog {
+
+ /**
+ * @var string
+ */
+ protected $title;
+
+ /**
+ * @var array
+ */
+ protected $posts = array();
+
+ ...
+
+}</programlisting></para>
+ </example>The first annotation to note is the
+ <emphasis>@entity</emphasis> annotation, which tells the persistence
+ framework it needs to persist Blog instances if they have been added to a
+ Repository. In the Blog class we have some member variables, they are
+ persisted as well by default. The persistence framework knows their types
+ by looking at the <emphasis>@var</emphasis> annotation you use anyway when
+ documenting your code (you do document your code, right?). In case of the
+ $posts array the persistence framework persists the objects held in that
+ array as independent objects. Apart from those annotations your domain
+ object's code is completely unaware of the persistence
+ infrastructure.</para>
+
+ <para>Let's conclude by taking a look at the BlogRepository code:<example>
+ <title>Code of a simple BlogRepository</title>
+
+ <programlisting language="php">/**
+ * A BlogRepository
+ *
+ * @package Blog
+ */
+class BlogRepository extends \F3\FLOW3\Persistence\Repository {
+
+ /**
+ * Finds Blogs with a matching name.
+ *
+ * @param string $name
+ * @return array
+ */
+ public function findByName($name) {
+ $query = $this->createQuery();
+ return $query->matching($query->equals('name', $name))->execute();
+ }
+}</programlisting>
+ </example>As you can see we get away with very little code by simply
+ extending the FLOW3-provided repository class. Nice, eh? If you like to do
+ things the hard way you can get away with implementing
+ <interfacename>\F3\FLOW3\Persistence\RepositoryInterface</interfacename>
+ yourself.</para>
+ </section>
+
+ <section>
+ <title>On the priciples of DDD</title>
+
+ <para>From Evans, the rules we need to enforce include:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>The root Entity has global identity and is ultimately
+ responsible for checking invariants.</para>
+ </listitem>
+
+ <listitem>
+ <para>Root Entities have global identity. Entities inside the boundary
+ have local identity, unique only within the Aggregate.</para>
+ </listitem>
+
+ <listitem>
+ <para>Nothing outside the Aggregate boundary can hold a reference to
+ anything inside, except to the root Entity. The root Entity can hand
+ references to the internal Entities to other objects, but they can
+ only use them transiently (within a single method or block).</para>
+ </listitem>
+
+ <listitem>
+ <para>Only Aggregate Roots can be obtained directly with database
+ queries. Everything else must be done through traversal.</para>
+ </listitem>
+
+ <listitem>
+ <para>Objects within the Aggregate can hold references to other
+ Aggregate roots.</para>
+ </listitem>
+
+ <listitem>
+ <para>A delete operation must remove everything within the Aggregate
+ boundary all at once.</para>
+ </listitem>
+
+ <listitem>
+ <para>When a change to any object within the Aggregate boundary is
+ committed, all invariants of the whole Aggregate must be
+ satisfied.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Persistence-related annotations</title>
+
+ <para>The following table lists all annotations used by the persistence
+ framework with their name, scope and meaning:<table>
+ <title>Persistence-related code annotations</title>
+
+ <tgroup cols="3">
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="4*" />
+
+ <thead>
+ <row>
+ <entry>Annotation</entry>
+
+ <entry>Scope</entry>
+
+ <entry>Meaning</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>@entity</entry>
+
+ <entry>Class</entry>
+
+ <entry>Declares a class as an Entity.</entry>
+ </row>
+
+ <row>
+ <entry>@valueobject</entry>
+
+ <entry>Class</entry>
+
+ <entry>Declares a class as a Value Object, allowing the
+ persistence framework to reuse an existing object if one
+ exists.</entry>
+ </row>
+
+ <row>
+ <entry>@var</entry>
+
+ <entry>Variable</entry>
+
+ <entry>Is used to detect the type a variable has.</entry>
+ </row>
+
+ <row>
+ <entry>@transient</entry>
+
+ <entry>Variable</entry>
+
+ <entry>Makes the persistence framework ignore the variable.
+ Neither will it's value be persisted, nor will it be touched
+ during reconstitution.</entry>
+ </row>
+
+ <row>
+ <entry>@uuid</entry>
+
+ <entry>Variable</entry>
+
+ <entry>Marks the variable as being the object uuid. This makes
+ the persistence backend use the value of this variable as
+ identifier for the internal representation of the object.
+ <emphasis>You must make sure your identifier is an
+ UUID.</emphasis></entry>
+ </row>
+
+ <row>
+ <entry>@identity</entry>
+
+ <entry>Variable</entry>
+
+ <entry>Marks the variable as being relevant for determining the
+ identity of an object in the domain.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table></para>
+ </section>
+
+ <section>
+ <title>Inside the Persistence Framework</title>
+
+ <para>To the domain code the persistence handling transparent, aside from
+ the need to add a few annotations. The custom repositories are a little
+ closer to the inner workings of the framework, but still the inner
+ workings are very invisible. This is how it is supposed to be, but a
+ little understanding of how persistence works internally can help
+ understand problems and develop more efficient client code.</para>
+
+ <section>
+ <title>Persisting a domain object</title>
+
+ <para>After an object has been added to a repository it will be seen
+ when FLOW3 calls <methodname>persistAll()</methodname> at the end of a
+ script run. Internally all instances implementing the
+ <interfacename>\F3\FLOW3\Persistence\RepositoryInterface</interfacename>
+ will be fetched and asked for the objects they hold. Those will then be
+ handed to the persistence backend in use and processed by it.</para>
+
+ <para>FLOW3 defines interfaces for persistence backends and queries, the
+ details of how objects are persisted and queried are up to the
+ persistence backend implementation. Have a look at the documentatoin of
+ the respective package for more information. The following diagram shows
+ (most of) the way an object takes from creation until it is persisted
+ when using the TYPO3 Content Repository:</para>
+
+ <para><figure>
+ <title>Object persistence process</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata contentdepth="100%"
+ fileref="PersistenceFramework_PersistenceProcess.png"
+ scalefit="1" width="100%"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>Keep in mind that the diagram omits some details like dirty
+ checking on objects and how exactly objects and their properties are
+ stored in the Content Repository.</para>
+ </section>
+
+ <section>
+ <title>Querying the storage backend</title>
+
+ <para>As we saw in the introductory example there is a query mechanism
+ available that provides easy fetching of objects through the persistence
+ framework. You ask for instances of a specific class that match certain
+ filters and get back an array of those reconstituted objects. Here is a
+ diagram of the internal process when using the TYPO3 Content Repository
+ as persistence backend:<figure>
+ <title>Object querying and reconstitution process</title>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata contentdepth="100%"
+ fileref="PersistenceFramework_QueryProcess.png"
+ scalefit="1" width="100%"></imagedata>
+ </imageobject>
+ </mediaobject>
+ </figure>For the developer the complexity is hidden between the
+ query's <methodname>execute()</methodname> method and the array of
+ objects being returned. The <classname>QOMFactory</classname>, "right"
+ <classname>Query</classname> and <classname>QueryResult</classname>
+ objects are part of the standard JSR-283 API, whereas
+ <classname>QueryFactory</classname>, "left" <classname>Query</classname>
+ and <classname>DataMapper</classname> are part of the FLOW3 persistence
+ backend implementation that comes with the TYPO3 Content
+ Repository.</para>
+ </section>
+ </section>
+</chapter>
-PLEASE USE THE TODO LIST AT http://forge.typo3.org/wiki/typo3v4-mvc/ToDo_List
\ No newline at end of file
+PLEASE USE THE TODO LIST AT http://forge.typo3.org/wiki/typo3v4-mvc/ToDo_List
+
+public function render($view, $arguments, $templateSource, $variables) {
+ $this->initializeLocalization($view);
+ // SF first replace variables and then translate
+ $key = $arguments['key'];
+ $view->replaceReferencesWithValues($key, $variables);
+ $translation = $this->translate($key);
+ // SF default values wasn't returned
+ $default = $arguments['default'];
+ $view->replaceReferencesWithValues($default, $variables);
+ return (is_string($translation) && !empty($translation)) ? $translation : $default;
+}
+
+
+
+public function render($view, $arguments, $templateSource, $variables) {
+ $condition = FALSE;
+ $keys = array_keys($arguments);
+ $key = $keys[0];
+ $value = $arguments[$key];
+ switch ($key) {
+ case 'istrue':
+ if (($value != '' AND $value != 'false') OR $value > 0) {
+ $condition = TRUE;
+ }
+ break;
+ case 'isfalse':
+ if (empty($value) OR $value == 'false') {
+ $condition = TRUE;
+ }
+ #debug(array($key, $value, $condition), 'isfalse');
+ break;
+ case 'equals':
+ if ($value == $arguments['value']) {
+ $conditon = TRUE;
+ }
+ break;
+ case 'islessthan':
+ if ($value > $arguments['value']) {
+ $condition = TRUE;
+ }
+ break;
+ case 'isgreaterthan':
+ if ($value < $arguments['value']) {
+ $condition = TRUE;
+ }
+ break;
+ }
+#debug(array($key, $value, $condition));
+ if ($condition) {
+ return $view->renderTemplate($templateSource, $variables);
+ }
+
+ return '';
+}
\ No newline at end of file
try {
$controller->processRequest($request, $response);
} catch (Tx_ExtBase_Exception_StopAction $ignoredException) {
+ } catch (Tx_ExtBase_Exception_InvalidArgumentValue $exception) {
+ $persistenceSession->clear();
+ return '';
}
// var_dump($persistenceSession);
$persistenceSession->commit();
if ($classNameParts[0] === 'ux') {
array_shift($classNameParts);
}
+ $className = implode('_', $classNameParts);
if (count($classNameParts) > 2 && $classNameParts[0] === 'Tx') {
$classFilePathAndName = t3lib_extMgm::extPath(strtolower($classNameParts[1])) . 'Classes/';
$classFilePathAndName .= implode(array_slice($classNameParts, 2, -1), '/') . '/';
$EM_CONF[$_EXTKEY] = array(
'title' => 'MVC Framework for Extensions',
- 'description' => 'A MVC framework to build extensions: It\'s based on the MVC framework of FLOW3.',
+ 'description' => 'A framework to build extensions upon: It\'s based on the MVC framework of FLOW3.',
'category' => 'plugin',
'author' => 'Jochen Rau',
'author_email' => 'jochen.rau@typoplanet.de',
'conflicts' => '',
'priority' => '',
'module' => '',
- 'state' => 'beta',
+ 'state' => 'alpha',
'internal' => '',
'uploadfolder' => 0,
'createDirs' => '',
'constraints' => array(
'depends' => array(
'php' => '5.2.0-0.0.0',
- 'typo3' => '4.3.dev-4.3.99',
+ 'typo3' => '4.2.0-4.3.99',
),
'conflicts' => array(
),