[TASK] Functional tests for persisting relations in Extbase 92/27492/4
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Sat, 8 Feb 2014 20:33:13 +0000 (21:33 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Wed, 5 Mar 2014 21:17:56 +0000 (22:17 +0100)
Add functional tests for persisting 1:M and M:M relations
in Extbase.
This patch adds blog_example as an fixture extension.

Resolves: #55786
Releases: 6.2
Change-Id: If90c854c9cb86fd45dcdbc14319a0a416e9447a0
Reviewed-on: https://review.typo3.org/27492
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
Reviewed-by: Stefan Neufeind
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
37 files changed:
typo3/sysext/core/Build/FunctionalTests.xml
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Administrator.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Comment.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Person.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Post.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Tag.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/AdministratorRepository.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/BlogRepository.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PersonRepository.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/FlexForms/flexform_list.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Blog.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Comment.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Person.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Post.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Tag.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/DefaultStyles/setup.txt [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/constants.txt [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/setup.txt [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_csh.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_emconf.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_icon.gif [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/blogs.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/post-tag-mm.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/posts.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/tags.xml [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Relations/RelationTest.php [new file with mode: 0644]

index 8c966e9..a38851a 100644 (file)
@@ -33,5 +33,8 @@
                <testsuite name="EXT:workspaces tests">
                        <directory>../../../../typo3/sysext/workspaces/Tests/Functional/</directory>
                </testsuite>
+               <testsuite name="EXT:extbase tests">
+                       <directory>../../../../typo3/sysext/extbase/Tests/Functional/Relations</directory>
+               </testsuite>
        </testsuites>
 </phpunit>
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Administrator.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Administrator.php
new file mode 100644 (file)
index 0000000..dc1ce73
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * An Administrator of a Blog
+ */
+class Administrator extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser {
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php
new file mode 100644 (file)
index 0000000..b707b31
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A blog
+ */
+class Blog extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
+
+       /**
+        * The blog's title.
+        *
+        * @var string
+        * @validate StringLength(minimum = 1, maximum = 80)
+        */
+       protected $title = '';
+
+       /**
+        * A short description of the blog
+        *
+        * @var string
+        * @validate StringLength(maximum = 150)
+        */
+       protected $description = '';
+
+       /**
+        * A relative path to a logo image
+        *
+        * @var string
+        */
+       protected $logo = '';
+
+       /**
+        * The posts of this blog
+        *
+        * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\ExtbaseTeam\BlogExample\Domain\Model\Post>
+        * @lazy
+        * @cascade remove
+        */
+       protected $posts = NULL;
+
+       /**
+        * The blog's administrator
+        *
+        * @var \ExtbaseTeam\BlogExample\Domain\Model\Administrator
+        * @lazy
+        */
+       protected $administrator = NULL;
+
+       /**
+        * Constructs a new Blog
+        *
+        */
+       public function __construct() {
+               $this->posts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+       }
+
+       /**
+        * Sets this blog's title
+        *
+        * @param string $title The blog's title
+        * @return void
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+       }
+
+       /**
+        * Returns the blog's title
+        *
+        * @return string The blog's title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * @param string $logo
+        * @return void
+        */
+       public function setLogo($logo) {
+               $this->logo = $logo;
+       }
+
+       /**
+        * @return string
+        */
+       public function getLogo() {
+               return $this->logo;
+       }
+
+       /**
+        * Sets the description for the blog
+        *
+        * @param string $description
+        * @return void
+        */
+       public function setDescription($description) {
+               $this->description = $description;
+       }
+
+       /**
+        * Returns the description
+        *
+        * @return string
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+
+       /**
+        * Adds a post to this blog
+        *
+        * @param Post $post
+        * @return void
+        */
+       public function addPost(Post $post) {
+               $this->posts->attach($post);
+       }
+
+       /**
+        * Remove a post from this blog
+        *
+        * @param Post $postToRemove The post to be removed
+        * @return void
+        */
+       public function removePost(Post $postToRemove) {
+               $this->posts->detach($postToRemove);
+       }
+
+       /**
+        * Remove all posts from this blog
+        *
+        * @return void
+        */
+       public function removeAllPosts() {
+               $this->posts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+       }
+
+       /**
+        * Returns all posts in this blog
+        *
+        * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
+        */
+       public function getPosts() {
+               return $this->posts;
+       }
+
+       /**
+        * Sets the administrator value
+        *
+        * @param Administrator $administrator The Administrator of this Blog
+        * @return void
+        */
+       public function setAdministrator(Administrator $administrator) {
+               $this->administrator = $administrator;
+       }
+
+       /**
+        * Returns the administrator value
+        *
+        * @return Administrator
+        */
+       public function getAdministrator() {
+               return $this->administrator;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Comment.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Comment.php
new file mode 100644 (file)
index 0000000..bb68258
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A blog post comment
+ */
+class Comment extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
+
+       /**
+        * @var \DateTime
+        */
+       protected $date;
+
+       /**
+        * @var string
+        * @validate NotEmpty
+        */
+       protected $author = '';
+
+       /**
+        * @var string
+        * @validate EmailAddress
+        */
+       protected $email = '';
+
+       /**
+        * @var string
+        * @validate StringLength(maximum = 500)
+        */
+       protected $content = '';
+
+       /**
+        * Constructs this post
+        */
+       public function __construct() {
+               $this->date = new \DateTime();
+       }
+
+       /**
+        * Setter for date
+        *
+        * @param \DateTime $date
+        * @return void
+        */
+       public function setDate(\DateTime $date) {
+               $this->date = $date;
+       }
+
+       /**
+        * Getter for date
+        *
+        * @return \DateTime
+        */
+       public function getDate() {
+               return $this->date;
+       }
+
+       /**
+        * Sets the author for this comment
+        *
+        * @param string $author
+        * @return void
+        */
+       public function setAuthor($author) {
+               $this->author = $author;
+       }
+
+       /**
+        * Getter for author
+        *
+        * @return string
+        */
+       public function getAuthor() {
+               return $this->author;
+       }
+
+       /**
+        * Sets the authors email for this comment
+        *
+        * @param string $email email of the author
+        * @return void
+        */
+       public function setEmail($email) {
+               $this->email = $email;
+       }
+
+       /**
+        * Getter for authors email
+        *
+        * @return string
+        */
+       public function getEmail() {
+               return $this->email;
+       }
+
+       /**
+        * Sets the content for this comment
+        *
+        * @param string $content
+        * @return void
+        */
+       public function setContent($content) {
+               $this->content = $content;
+       }
+
+       /**
+        * Getter for content
+        *
+        * @return string
+        */
+       public function getContent() {
+               return $this->content;
+       }
+
+       /**
+        * Returns this comment as a formatted string
+        *
+        * @return string
+        */
+       public function __toString() {
+               return $this->author . ' (' . $this->email . ') said on ' . $this->date->format('Y-m-d') . ':' . chr(10) .
+                       $this->content . chr(10);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Person.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Person.php
new file mode 100644 (file)
index 0000000..7c24212
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A person - acting as author
+ */
+class Person extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
+
+       /**
+        * @var string
+        */
+       protected $firstname = '';
+
+       /**
+        * @var string
+        */
+       protected $lastname = '';
+
+       /**
+        * @var string
+        */
+       protected $email = '';
+
+       /**
+        * Constructs a new Person
+        *
+        */
+       public function __construct($firstname, $lastname, $email) {
+               $this->setFirstname($firstname);
+               $this->setLastname($lastname);
+               $this->setEmail($email);
+       }
+
+       /**
+        * Sets this persons's firstname
+        *
+        * @param string $firstname The person's firstname
+        * @return void
+        */
+       public function setFirstname($firstname) {
+               $this->firstname = $firstname;
+       }
+
+       /**
+        * Returns the person's firstname
+        *
+        * @return string The persons's firstname
+        */
+       public function getFirstname() {
+               return $this->firstname;
+       }
+
+       /**
+        * Sets this persons's lastname
+        *
+        * @param string $lastname The person's lastname
+        * @return void
+        */
+       public function setLastname($lastname) {
+               $this->lastname = $lastname;
+       }
+
+       /**
+        * Returns the person's lastname
+        *
+        * @return string The persons's lastname
+        */
+       public function getLastname() {
+               return $this->lastname;
+       }
+
+       /**
+        * Returns the person's full name
+        *
+        * @return string The persons's lastname
+        */
+       public function getFullName() {
+               return $this->firstname . ' ' . $this->lastname;
+       }
+
+       /**
+        * Sets this persons's email adress
+        *
+        * @param string $email The person's email adress
+        * @return void
+        */
+       public function setEmail($email) {
+               $this->email = $email;
+       }
+
+       /**
+        * Returns the person's email address
+        *
+        * @return string The persons's email address
+        */
+       public function getEmail() {
+               return $this->email;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Post.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Post.php
new file mode 100644 (file)
index 0000000..ccf1274
--- /dev/null
@@ -0,0 +1,333 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A blog post
+ */
+class Post extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
+
+       /**
+        * @var \ExtbaseTeam\BlogExample\Domain\Model\Blog
+        */
+       protected $blog = NULL;
+
+       /**
+        * @var string
+        * @validate StringLength(minimum = 3, maximum = 50)
+        */
+       protected $title = '';
+
+       /**
+        * @var \DateTime
+        */
+       protected $date = NULL;
+
+       /**
+        * @var \ExtbaseTeam\BlogExample\Domain\Model\Person
+        */
+       protected $author = NULL;
+
+       /**
+        * @var string
+        * @validate StringLength(minimum = 3)
+        */
+       protected $content = '';
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\ExtbaseTeam\BlogExample\Domain\Model\Tag>
+        */
+       protected $tags = NULL;
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\ExtbaseTeam\BlogExample\Domain\Model\Comment>
+        * @lazy
+        * @cascade remove
+        */
+       protected $comments = NULL;
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\ExtbaseTeam\BlogExample\Domain\Model\Post>
+        * @lazy
+        */
+       protected $relatedPosts = NULL;
+
+       /**
+        * Constructs this post
+        */
+       public function __construct() {
+               $this->tags = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+               $this->comments = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+               $this->relatedPosts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+               $this->date = new \DateTime();
+       }
+
+       /**
+        * Sets the blog this post is part of
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Blog $blog The blog
+        * @return void
+        */
+       public function setBlog(\ExtbaseTeam\BlogExample\Domain\Model\Blog $blog) {
+               $this->blog = $blog;
+       }
+
+       /**
+        * Returns the blog this post is part of
+        *
+        * @return \ExtbaseTeam\BlogExample\Domain\Model\Blog The blog this post is part of
+        */
+       public function getBlog() {
+               return $this->blog;
+       }
+
+       /**
+        * Setter for title
+        *
+        * @param string $title
+        * @return void
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+       }
+
+       /**
+        * Getter for title
+        *
+        * @return string
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Setter for date
+        *
+        * @param \DateTime $date
+        * @return void
+        */
+       public function setDate(\DateTime $date) {
+               $this->date = $date;
+       }
+
+       /**
+        * Getter for date
+        *
+        *
+        * @return \DateTime
+        */
+       public function getDate() {
+               return $this->date;
+       }
+
+       /**
+        * Setter for tags
+        *
+        * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $tags One or more Tag objects
+        * @return void
+        */
+       public function setTags(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $tags) {
+               $this->tags = $tags;
+       }
+
+       /**
+        * Adds a tag to this post
+        *
+        * @param Tag $tag
+        * @return void
+        */
+       public function addTag(Tag $tag) {
+               $this->tags->attach($tag);
+       }
+
+       /**
+        * Removes a tag from this post
+        *
+        * @param Tag $tag
+        * @return void
+        */
+       public function removeTag(Tag $tag) {
+               $this->tags->detach($tag);
+       }
+
+       /**
+        * Remove all tags from this post
+        *
+        * @return void
+        */
+       public function removeAllTags() {
+               $this->tags = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+       }
+
+       /**
+        * Getter for tags
+        * Note: We return a clone of the tags because they must not be modified as they are Value Objects
+        *
+        * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage A storage holding objects
+        */
+       public function getTags() {
+               return clone $this->tags;
+       }
+
+       /**
+        * Sets the author for this post
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Person $author
+        * @return void
+        */
+       public function setAuthor(\ExtbaseTeam\BlogExample\Domain\Model\Person $author) {
+               $this->author = $author;
+       }
+
+       /**
+        * Getter for author
+        *
+        * @return \ExtbaseTeam\BlogExample\Domain\Model\Person
+        */
+       public function getAuthor() {
+               return $this->author;
+       }
+
+       /**
+        * Sets the content for this post
+        *
+        * @param string $content
+        * @return void
+        */
+       public function setContent($content) {
+               $this->content = $content;
+       }
+
+       /**
+        * Getter for content
+        *
+        * @return string
+        */
+       public function getContent() {
+               return $this->content;
+       }
+
+       /**
+        * Setter for the comments to this post
+        *
+        * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $comments An Object Storage of related Comment instances
+        * @return void
+        */
+       public function setComments(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $comments) {
+               $this->comments = $comments;
+       }
+
+       /**
+        * Adds a comment to this post
+        *
+        * @param Comment $comment
+        * @return void
+        */
+       public function addComment(Comment $comment) {
+               $this->comments->attach($comment);
+       }
+
+       /**
+        * Removes Comment from this post
+        *
+        * @param Comment $commentToDelete
+        * @return void
+        */
+       public function removeComment(Comment $commentToDelete) {
+               $this->comments->detach($commentToDelete);
+       }
+
+       /**
+        * Remove all comments from this post
+        *
+        * @return void
+        */
+       public function removeAllComments() {
+               $comments = clone $this->comments;
+               $this->comments->removeAll($comments);
+       }
+
+       /**
+        * Returns the comments to this post
+        *
+        * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage holding instances of Comment
+        */
+       public function getComments() {
+               return $this->comments;
+       }
+
+       /**
+        * Setter for the related posts
+        *
+        * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relatedPosts An Object Storage containing related Posts instances
+        * @return void
+        */
+       public function setRelatedPosts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relatedPosts) {
+               $this->relatedPosts = $relatedPosts;
+       }
+
+       /**
+        * Adds a related post
+        *
+        * @param Post $post
+        * @return void
+        */
+       public function addRelatedPost(Post $post) {
+               $this->relatedPosts->attach($post);
+       }
+
+       /**
+        * Remove all related posts
+        *
+        * @return void
+        */
+       public function removeAllRelatedPosts() {
+               $relatedPosts = clone $this->relatedPosts;
+               $this->relatedPosts->removeAll($relatedPosts);
+       }
+
+       /**
+        * Returns the related posts
+        *
+        * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage holding instances of Post
+        */
+       public function getRelatedPosts() {
+               return $this->relatedPosts;
+       }
+
+       /**
+        * Returns this post as a formatted string
+        *
+        * @return string
+        */
+       public function __toString() {
+               return $this->title . chr(10) .
+                       ' written on ' . $this->date->format('Y-m-d') . chr(10) .
+                       ' by ' . $this->author->getFullName() . chr(10) .
+                       wordwrap($this->content, 70, chr(10)) . chr(10) .
+                       implode(', ', $this->tags->toArray());
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Tag.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Tag.php
new file mode 100644 (file)
index 0000000..597274a
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A blog post tag
+ */
+class Tag extends \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject {
+
+       /**
+        * @var string
+        */
+       protected $name = '';
+
+       /**
+        * Constructs this tag
+        *
+        * @param $name
+        */
+       public function __construct($name) {
+               $this->name = $name;
+       }
+
+       /**
+        * Returns this tag's name
+        *
+        * @return string This tag's name
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * Returns this tag as a formatted string
+        *
+        * @return string
+        */
+       public function __toString() {
+               return $this->getName();
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/AdministratorRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/AdministratorRepository.php
new file mode 100644 (file)
index 0000000..f433bbf
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Repository;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for administrators
+ */
+class AdministratorRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository {
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/BlogRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/BlogRepository.php
new file mode 100644 (file)
index 0000000..e4b12f6
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Repository;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for blogs
+ */
+class BlogRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
+
+       protected $defaultOrderings = array(
+               'crdate' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING,
+               'uid' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING
+       );
+
+       /**
+        * Life cycle method.
+        *
+        * @return void
+        */
+       public function initializeObject() {
+               /*
+               $querySettings = $this->objectManager->create('\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings');
+               $querySettings->setRespectStoragePage(FALSE);
+               $this->setDefaultQuerySettings($querySettings);
+                */
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PersonRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PersonRepository.php
new file mode 100644 (file)
index 0000000..286de53
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Repository;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for persons
+ */
+class PersonRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/PostRepository.php
new file mode 100644 (file)
index 0000000..de192c5
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Repository;
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+ *  (c) 2011 Bastian Waidelich <bastian@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for blog posts
+ */
+class PostRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
+
+       protected $defaultOrderings = array('date' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING);
+
+       /**
+        * Finds all posts by the specified blog
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Blog $blog The blog the post must refer to
+        * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface The posts
+        */
+       public function findAllByBlog(\ExtbaseTeam\BlogExample\Domain\Model\Blog $blog) {
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->equals('blog', $blog)
+                       )
+                       ->execute();
+       }
+
+       /**
+        * Finds posts by the specified tag and blog
+        *
+        * @param string $tag
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Blog $blog The blog the post must refer to
+        * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface The posts
+        */
+       public function findByTagAndBlog($tag, \ExtbaseTeam\BlogExample\Domain\Model\Blog $blog) {
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->logicalAnd(
+                                       $query->equals('blog', $blog),
+                                       $query->equals('tags.name', $tag)
+                               )
+                       )
+                       ->execute();
+       }
+
+       /**
+        * Finds all remaining posts of the blog
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Post $post The reference post
+        * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface The posts
+        */
+       public function findRemaining(\ExtbaseTeam\BlogExample\Domain\Model\Post $post) {
+               $blog = $post->getBlog();
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->logicalAnd(
+                                       $query->equals('blog', $blog),
+                                       $query->logicalNot(
+                                               $query->equals('uid', $post->getUid())
+                                       )
+                               )
+                       )
+                       ->execute();
+       }
+
+       /**
+        * Finds the previous of the given post
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Post $post The reference post
+        * @return \ExtbaseTeam\BlogExample\Domain\Model\Post
+        */
+       public function findPrevious(\ExtbaseTeam\BlogExample\Domain\Model\Post $post) {
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->lessThan('date', $post->getDate())
+                       )
+                       ->execute()
+                       ->getFirst();
+       }
+
+       /**
+        * Finds the post next to the given post
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Post $post The reference post
+        * @return \ExtbaseTeam\BlogExample\Domain\Model\Post
+        */
+       public function findNext(\ExtbaseTeam\BlogExample\Domain\Model\Post $post) {
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->greaterThan('date', $post->getDate())
+                       )
+                       ->execute()
+                       ->getFirst();
+       }
+
+       /**
+        * Finds most recent posts by the specified blog
+        *
+        * @param \ExtbaseTeam\BlogExample\Domain\Model\Blog $blog The blog the post must refer to
+        * @param integer $limit The number of posts to return at max
+        * @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface The posts
+        */
+       public function findRecentByBlog(\ExtbaseTeam\BlogExample\Domain\Model\Blog $blog, $limit = 5) {
+               $query = $this->createQuery();
+               return $query
+                       ->matching(
+                               $query->equals('blog', $blog)
+                       )
+                       ->setLimit((integer)$limit)
+                       ->execute();
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/FlexForms/flexform_list.xml b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/FlexForms/flexform_list.xml
new file mode 100644 (file)
index 0000000..288096a
--- /dev/null
@@ -0,0 +1,25 @@
+<T3DataStructure>
+       <sheets>
+               <sDEF>
+                       <ROOT>
+                               <TCEforms>
+                                       <sheetTitle>Options</sheetTitle>
+                               </TCEforms>
+                               <type>array</type>
+                               <el>
+                                       <settings.postsPerPage>
+                                               <TCEforms>
+                                                       <label>Max. number of posts to display per page</label>
+                                                       <config>
+                                                               <type>input</type>
+                                                               <size>2</size>
+                                                               <eval>int</eval>
+                                                               <default>3</default>
+                                                       </config>
+                                               </TCEforms>
+                                       </settings.postsPerPage>
+                               </el>
+                       </ROOT>
+               </sDEF>
+       </sheets>
+</T3DataStructure>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Blog.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Blog.php
new file mode 100644 (file)
index 0000000..972a224
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+$TCA['tx_blogexample_domain_model_blog'] = array(
+       'ctrl' => $TCA['tx_blogexample_domain_model_blog']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'title, posts, administrator'
+       ),
+       'columns' => array(
+               'sys_language_uid' => Array (
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.language',
+                       'config' => Array (
+                               'type' => 'select',
+                               'foreign_table' => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => Array(
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.allLanguages',-1),
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.default_value',0)
+                               )
+                       )
+               ),
+               'l18n_parent' => Array (
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.l18n_parent',
+                       'config' => Array (
+                               'type' => 'select',
+                               'items' => Array (
+                                       Array('', 0),
+                               ),
+                               'foreign_table' => 'tx_blogexample_domain_model_blog',
+                               'foreign_table_where' => 'AND tx_blogexample_domain_model_blog.uid=###REC_FIELD_l18n_parent### AND tx_blogexample_domain_model_blog.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => Array(
+                       'config'=>array(
+                               'type'=>'passthrough'
+                       )
+               ),
+               't3ver_label' => Array (
+                       'displayCond' => 'FIELD:t3ver_label:REQ:true',
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.versionLabel',
+                       'config' => Array (
+                               'type'=>'none',
+                               'cols' => 27
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check'
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim,required',
+                               'max' => 256
+                       )
+               ),
+               'description' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.description',
+                       'config' => array(
+                               'type' => 'text',
+                               'eval' => 'required',
+                               'rows' => 30,
+                               'cols' => 80,
+                       )
+               ),
+               'logo' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.logo',
+                       'config' => array(
+                               'type' => 'group',
+                               'internal_type' => 'file',
+                               'allowed' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
+                               'max_size' => 3000,
+                               'uploadfolder' => 'uploads/pics',
+                               'show_thumbs' => 1,
+                               'size' => 1,
+                               'maxitems' => 1,
+                               'minitems' => 0
+                       )
+               ),
+               'posts' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.posts',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_blogexample_domain_model_post',
+                               'foreign_field' => 'blog',
+                               'foreign_sortby' => 'sorting',
+                               'maxitems' => 999999,
+                               'appearance' => array(
+                                       'collapseAll' => 1,
+                                       'expandSingle' => 1,
+                               ),
+                       )
+               ),
+               'administrator' => Array (
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog.administrator',
+                       'config' => Array (
+                               'type' => 'select',
+                               'foreign_table' => 'fe_users',
+                               'foreign_table_where' => "AND fe_users.tx_extbase_type='Tx_BlogExample_Domain_Model_Administrator'",
+                               'items' => array(
+                                       array('--none--', 0),
+                                       ),
+                               'wizards' => Array(
+                                        '_PADDING' => 1,
+                                        '_VERTICAL' => 1,
+                                        'edit' => Array(
+                                                'type' => 'popup',
+                                                'title' => 'Edit',
+                                                'script' => 'wizard_edit.php',
+                                                'icon' => 'edit2.gif',
+                                                'popup_onlyOpenIfSelected' => 1,
+                                                'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
+                                        ),
+                                        'add' => Array(
+                                                'type' => 'script',
+                                                'title' => 'Create new',
+                                                'icon' => 'add.gif',
+                                                'params' => Array(
+                                                        'table'=>'fe_users',
+                                                        'pid' => '###CURRENT_PID###',
+                                                        'setValue' => 'prepend'
+                                                ),
+                                                'script' => 'wizard_add.php',
+                                        ),
+                                )
+                       )
+               ),
+       ),
+       'types' => array(
+               '1' => array('showitem' => 'sys_language_uid, hidden, title, description, logo, posts, administrator')
+       ),
+       'palettes' => array(
+               '1' => array('showitem' => '')
+       )
+);
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Comment.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Comment.php
new file mode 100644 (file)
index 0000000..2e0ff92
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+$TCA['tx_blogexample_domain_model_comment'] = array(
+       'ctrl' => $TCA['tx_blogexample_domain_model_comment']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'hidden, date, author, email, content'
+       ),
+       'columns' => array(
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check'
+                       )
+               ),
+               'date' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_comment.date',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 12,
+                               'checkbox' => 1,
+                               'eval' => 'datetime, required',
+                               'default' => time()
+                       )
+               ),
+               'author' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_comment.author',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim, required',
+                               'max' => 256
+                       )
+               ),
+               'email' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_comment.email',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim, required',
+                               'max' => 256
+                       )
+               ),
+               'content' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_comment.content',
+                       'config' => array(
+                               'type' => 'text',
+                               'rows' => 30,
+                               'cols' => 80
+                       )
+               ),
+               'post' => array(
+                       'config' => array(
+                               'type' => 'passthrough',
+                       )
+               ),
+       ),
+       'types' => array(
+               '1' => array('showitem' => 'hidden, date, author, email, content')
+       ),
+       'palettes' => array(
+               '1' => array('showitem' => '')
+       )
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Person.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Person.php
new file mode 100644 (file)
index 0000000..2f8aeb8
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+$TCA['tx_blogexample_domain_model_person'] = array(
+       'ctrl' => $TCA['tx_blogexample_domain_model_person']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'firstname, lastname, email, avatar'
+       ),
+       'columns' => array(
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check'
+                       )
+               ),
+               'firstname' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_person.firstname',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim,required',
+                               'max' => 256
+                       )
+               ),
+               'lastname' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_person.lastname',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim,required',
+                               'max' => 256
+                       )
+               ),
+               'email' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_person.email',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim, required',
+                               'max' => 256
+                       )
+               )
+       ),
+       'types' => array(
+               '1' => array('showitem' => 'firstname, lastname, email, avatar')
+       ),
+       'palettes' => array(
+               '1' => array('showitem' => '')
+       )
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Post.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Post.php
new file mode 100644 (file)
index 0000000..6583212
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+$TCA['tx_blogexample_domain_model_post'] = array(
+       'ctrl' => $TCA['tx_blogexample_domain_model_post']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'title, date, author',
+               'maxDBListItems' => 100,
+               'maxSingleDBListItems' => 500
+       ),
+       'types' => array(
+               '1' => array('showitem' => 'sys_language_uid, hidden, blog, title, date, author, content, tags, comments, related_posts')
+       ),
+       'columns' => array(
+               'sys_language_uid' => Array (
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.language',
+                       'config' => Array (
+                               'type' => 'select',
+                               'foreign_table' => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => Array(
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.allLanguages',-1),
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.default_value',0)
+                               )
+                       )
+               ),
+               'l18n_parent' => Array (
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.l18n_parent',
+                       'config' => Array (
+                               'type' => 'select',
+                               'items' => Array (
+                                       Array('', 0),
+                               ),
+                               'foreign_table' => 'tx_blogexample_domain_model_post',
+                               'foreign_table_where' => 'AND tx_blogexample_domain_model_post.uid=###REC_FIELD_l18n_parent### AND tx_blogexample_domain_model_post.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => Array(
+                       'config'=>array(
+                               'type'=>'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check'
+                       )
+               ),
+               'blog' => Array (
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.blog',
+                       'config' => Array (
+                               'type' => 'select',
+                               'foreign_table' => 'tx_blogexample_domain_model_blog',
+                               'maxitems' => 1,
+                       )
+               ),
+               'title' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.title',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim, required',
+                               'max' => 256
+                       )
+               ),
+               'date' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.date',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 12,
+                               'checkbox' => 1,
+                               'eval' => 'datetime, required',
+                               'default' => time()
+                       )
+               ),
+               'author' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.author',
+                       'config' => array(
+                               'type' => 'select',
+                               'foreign_table' => 'tx_blogexample_domain_model_person',
+                               'wizards' => Array(
+                                        '_PADDING' => 1,
+                                        '_VERTICAL' => 1,
+                                        'edit' => Array(
+                                                'type' => 'popup',
+                                                'title' => 'Edit',
+                                                'script' => 'wizard_edit.php',
+                                                'icon' => 'edit2.gif',
+                                                'popup_onlyOpenIfSelected' => 1,
+                                                'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
+                                        ),
+                                        'add' => Array(
+                                                'type' => 'script',
+                                                'title' => 'Create new',
+                                                'icon' => 'add.gif',
+                                                'params' => Array(
+                                                        'table'=>'tx_blogexample_domain_model_person',
+                                                        'pid' => '###CURRENT_PID###',
+                                                        'setValue' => 'prepend'
+                                                ),
+                                                'script' => 'wizard_add.php',
+                                        ),
+                                )
+                       )
+               ),
+               'content' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.content',
+                       'config' => array(
+                               'type' => 'text',
+                               'rows' => 30,
+                               'cols' => 80
+                       )
+               ),
+               'tags' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.tags',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_blogexample_domain_model_tag',
+                               'MM' => 'tx_blogexample_post_tag_mm',
+                               'maxitems' => 9999,
+                               'appearance' => array(
+                                       'useCombination' => 1,
+                                       'useSortable' => 1,
+                                       'collapseAll' => 1,
+                                       'expandSingle' => 1,
+                               )
+                       )
+               ),
+               'comments' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.comments',
+                       'config' => array(
+                               'type' => 'inline',
+                               'foreign_table' => 'tx_blogexample_domain_model_comment',
+                               'foreign_field' => 'post',
+                               'size' => 10,
+                               'maxitems' => 9999,
+                               'autoSizeMax' => 30,
+                               'multiple' => 0,
+                               'appearance' => array(
+                                       'collapseAll' => 1,
+                                       'expandSingle' => 1,
+                               )
+                       )
+               ),
+               'related_posts' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post.related',
+                       'config' => array(
+                               'type' => 'select',
+                               'size' => 10,
+                               'maxitems' => 9999,
+                               'autoSizeMax' => 30,
+                               'multiple' => 0,
+                               'foreign_table' => 'tx_blogexample_domain_model_post',
+                               'foreign_table_where' => 'AND ###THIS_UID### != tx_blogexample_domain_model_post.uid',
+                               'MM' => 'tx_blogexample_post_post_mm',
+                               'MM_opposite_field' => 'related_posts',
+                       )
+               ),
+       )
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Tag.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TCA/Tag.php
new file mode 100644 (file)
index 0000000..957a649
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+if (!defined ('TYPO3_MODE')) {
+       die ('Access denied.');
+}
+
+$TCA['tx_blogexample_domain_model_tag'] = array(
+       'ctrl' => $TCA['tx_blogexample_domain_model_tag']['ctrl'],
+       'interface' => array(
+               'showRecordFieldList' => 'hidden, name, posts'
+       ),
+       'columns' => array(
+               'sys_language_uid' => Array (
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.language',
+                       'config' => Array (
+                               'type' => 'select',
+                               'foreign_table' => 'sys_language',
+                               'foreign_table_where' => 'ORDER BY sys_language.title',
+                               'items' => Array(
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.allLanguages',-1),
+                                       Array('LLL:EXT:lang/locallang_general.php:LGL.default_value',0)
+                               )
+                       )
+               ),
+               'l18n_parent' => Array (
+                       'displayCond' => 'FIELD:sys_language_uid:>:0',
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.php:LGL.l18n_parent',
+                       'config' => Array (
+                               'type' => 'select',
+                               'items' => Array (
+                                       Array('', 0),
+                               ),
+                               'foreign_table' => 'tx_blogexample_domain_model_tag',
+                               'foreign_table_where' => 'AND tx_blogexample_domain_model_tag.uid=###REC_FIELD_l18n_parent### AND tx_blogexample_domain_model_tag.sys_language_uid IN (-1,0)',
+                       )
+               ),
+               'l18n_diffsource' => Array(
+                       'config'=>array(
+                               'type'=>'passthrough'
+                       )
+               ),
+               'hidden' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
+                       'config' => array(
+                               'type' => 'check'
+                       )
+               ),
+               'name' => array(
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_tag.name',
+                       'config' => array(
+                               'type' => 'input',
+                               'size' => 20,
+                               'eval' => 'trim, required',
+                               'max' => 256
+                       )
+               ),
+               'posts' => array(
+                       'exclude' => 1,
+                       'label' => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_tag.posts',
+                       'config' => array(
+                               'type' => 'select',
+                               'size' => 10,
+                               'minitems' => 0,
+                               'maxitems' => 9999,
+                               'autoSizeMax' => 30,
+                               'multiple' => 0,
+                               'foreign_table' => 'tx_blogexample_domain_model_post',
+                               'MM' => 'tx_blogexample_post_tag_mm',
+                               'MM_opposite_field' => 'tags',
+                       )
+               ),
+       ),
+       'types' => array(
+               '1' => array('showitem' => 'sys_language_uid, hidden, name, posts')
+       ),
+       'palettes' => array(
+               '1' => array('showitem' => '')
+       )
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/DefaultStyles/setup.txt b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/DefaultStyles/setup.txt
new file mode 100644 (file)
index 0000000..51b049c
--- /dev/null
@@ -0,0 +1,3 @@
+ # Include BlogExample default styles
+
+page.includeCSS.tx_blogexample = EXT:blog_example/Resources/Public/Css/BlogExample.css
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/constants.txt b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/constants.txt
new file mode 100644 (file)
index 0000000..0790585
--- /dev/null
@@ -0,0 +1,30 @@
+plugin.tx_blogexample {
+       settings {
+                # cat=plugin.tx_blogexample/a; type=int+; label=Editor FE Usergroup uid:Enter the uid of the FE Usergroup that should be allowed to edit Blogs and Post in the frontend
+               editorUsergroupUid = 1
+                # cat=plugin.tx_blogexample/a; type=int+; label=Plaintext page type:If the default plaintext page typenum (778) conflicts with your setup, you can override this setting here
+               plaintextPageType = 778
+       }
+       view {
+                # cat=plugin.tx_blogexample/file; type=string; label=Path to template root (FE)
+               templateRootPath = EXT:blog_example/Resources/Private/Templates/
+                # cat=plugin.tx_blogexample/file; type=string; label=Path to template partials (FE)
+               partialRootPath = EXT:blog_example/Resources/Private/Partials/
+                # cat=plugin.tx_blogexample/file; type=string; label=Path to template layouts (FE)
+               layoutRootPath = EXT:blog_example/Resources/Private/Layouts/
+       }
+       persistence {
+                # cat=plugin.tx_blogexample//a; type=int+; label=Default storage PID
+               storagePid =
+       }
+}
+module.tx_blogexample {
+       view {
+                # cat=module.tx_blogexample/file; type=string; label=Path to template root (BE)
+               templateRootPath = EXT:blog_example/Resources/Private/Backend/Templates/
+                # cat=module.tx_blogexample/file; type=string; label=Path to template partials (BE)
+               partialRootPath = EXT:blog_example/Resources/Private/Partials/
+                # cat=module.tx_blogexample/file; type=string; label=Path to template layouts (BE)
+               layoutRootPath = EXT:blog_example/Resources/Private/Backend/Layouts/
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/setup.txt b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/setup.txt
new file mode 100644 (file)
index 0000000..2716b1a
--- /dev/null
@@ -0,0 +1,72 @@
+ # Plugin configuration
+plugin.tx_blogexample {
+       settings {
+                # maximum number of posts to display per page
+               postsPerPage = 3
+                # Editor FE Usergroup uid
+               editorUsergroupUid = {$plugin.tx_blogexample.settings.editorUsergroupUid}
+                # Plaintext page type number
+               plaintextPageType = {$plugin.tx_blogexample.settings.plaintextPageType}
+       }
+       persistence {
+               storagePid = {$plugin.tx_blogexample.persistence.storagePid}
+       }
+       view {
+               templateRootPath = {$plugin.tx_blogexample.view.templateRootPath}
+               partialRootPath = {$plugin.tx_blogexample.view.partialRootPath}
+               layoutRootPath = {$plugin.tx_blogexample.view.layoutRootPath}
+               defaultPid = auto
+       }
+       # This is an example how to modify the translation
+       _LOCAL_LANG {
+               default {
+                       someUnusedKey = foo
+               }
+       }
+}
+
+ # Module configuration
+module.tx_blogexample {
+       settings < plugin.tx_blogexample.settings
+       persistence < plugin.tx_blogexample.persistence
+       view < plugin.tx_blogexample.view
+       view {
+               templateRootPath = {$module.tx_blogexample.view.templateRootPath}
+               partialRootPath = {$module.tx_blogexample.view.partialRootPath}
+               layoutRootPath = {$module.tx_blogexample.view.layoutRootPath}
+       }
+}
+
+ # plaintext rendering
+tx_blogexample_plaintext = PAGE
+tx_blogexample_plaintext {
+       typeNum = {$plugin.tx_blogexample.settings.plaintextPageType}
+       10 = USER
+       10 {
+               userFunc = tx_extbase_core_bootstrap->run
+               extensionName = BlogExample
+               pluginName = PostList
+               switchableControllerActions {
+                       Post {
+                               1 = index
+                       }
+               }
+       }
+       config {
+               admPanel = 0
+               no_cache = 1
+               disableAllHeaderCode = 1
+               additionalHeaders = Content-type:text/plain
+               defaultGetVars {
+                       tx_blogexample_postlist.format = txt
+               }
+       }
+}
+
+ # Adjust plaintext rendering, if blog_example runs as single, fully fledged plugin
+[globalVar = TYPO3_CONF_VARS|EXTCONF|blog_example|registerSinglePlugin > 0]
+       tx_blogexample_plaintext {
+               10.pluginName = Pi1
+               #config.defaultGetVars =
+       }
+[end]
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_csh.xml b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_csh.xml
new file mode 100644 (file)
index 0000000..c5fdcc7
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3locallang>
+       <meta type="array">
+               <type>CSH</type>
+               <description>Language labels for the blog_example context sensitive help (CSH)</description>
+               <csh_table>_MOD_txblogexampleM1</csh_table>
+       </meta>
+       <data type="array">
+               <languageKey index="default" type="array">
+                       <label index=".alttitle">Blog Example</label>
+                       <label index=".description">This is some dummy help. But it's context sensitive!</label>
+                       <label index=".seeAlso">_MOD_web_func:tx_wizardcrpages, _MOD_web_func:tx_wizardsortpages</label>
+               </languageKey>
+       </data>
+</T3locallang>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Private/Language/locallang_db.xml
new file mode 100644 (file)
index 0000000..01899a0
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3locallang>
+       <meta type="array">
+               <type>database</type>
+               <description>Language labels for database tables/fields belonging to extension 'blog_example'</description>
+       </meta>
+       <data type="array">
+               <languageKey index="default" type="array">
+                       <label index="tx_blogexample_domain_model_blog">Blog</label>
+                       <label index="tx_blogexample_domain_model_blog.title">Blog title</label>
+                       <label index="tx_blogexample_domain_model_blog.description">Short description</label>
+                       <label index="tx_blogexample_domain_model_blog.logo">Logo</label>
+                       <label index="tx_blogexample_domain_model_blog.posts">Posts</label>
+                       <label index="tx_blogexample_domain_model_blog.administrator">Administrator</label>
+                       <label index="tx_blogexample_domain_model_post">Post</label>
+                       <label index="tx_blogexample_domain_model_post.blog">Related to</label>
+                       <label index="tx_blogexample_domain_model_post.title">Title</label>
+                       <label index="tx_blogexample_domain_model_post.date">Date</label>
+                       <label index="tx_blogexample_domain_model_post.author">Author</label>
+                       <label index="tx_blogexample_domain_model_post.content">Content</label>
+                       <label index="tx_blogexample_domain_model_post.votes">Votes</label>
+                       <label index="tx_blogexample_domain_model_post.published">Published</label>
+                       <label index="tx_blogexample_domain_model_post.tags">Tags</label>
+                       <label index="tx_blogexample_domain_model_post.comments">Comments</label>
+                       <label index="tx_blogexample_domain_model_post.related">Related posts</label>
+                       <label index="tx_blogexample_domain_model_person">Person</label>
+                       <label index="tx_blogexample_domain_model_person.firstname">Firstname</label>
+                       <label index="tx_blogexample_domain_model_person.lastname">Lastname</label>
+                       <label index="tx_blogexample_domain_model_person.email">E-Mail</label>
+                       <label index="tx_blogexample_domain_model_person.avatar">Avatar</label>
+                       <label index="tx_blogexample_domain_model_comment">Comment</label>
+                       <label index="tx_blogexample_domain_model_comment.date">Date</label>
+                       <label index="tx_blogexample_domain_model_comment.author">Author</label>
+                       <label index="tx_blogexample_domain_model_comment.email">Email</label>
+                       <label index="tx_blogexample_domain_model_comment.content">Content</label>
+                       <label index="tx_blogexample_domain_model_tag">Tag</label>
+                       <label index="tx_blogexample_domain_model_tag.name">Name</label>
+                       <label index="tx_blogexample_domain_model_tag.posts">Related posts</label>
+                       <label index="fe_users.tx_extbase_type.Tx_BlogExample_Domain_Model_Administrator">Blog Admin (BlogExample)</label>
+               </languageKey>
+       </data>
+</T3locallang>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif
new file mode 100644 (file)
index 0000000..87c8b61
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif
new file mode 100644 (file)
index 0000000..6c46bfe
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif
new file mode 100644 (file)
index 0000000..fb089de
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif
new file mode 100644 (file)
index 0000000..3b8fa46
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif
new file mode 100644 (file)
index 0000000..bc373bf
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_emconf.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_emconf.php
new file mode 100644 (file)
index 0000000..07e8438
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+########################################################################
+# Extension Manager/Repository config file for ext "blog_example".
+#
+# Auto generated 15-02-2011 19:01
+#
+# Manual updates:
+# Only the data in the array - everything else is removed by next
+# writing. "version" and "dependencies" must not be touched!
+########################################################################
+
+$EM_CONF[$_EXTKEY] = array(
+       'title' => 'A Blog Example for the Extbase Framework',
+       'description' => 'An example extension demonstrating the features of the Extbase Framework. It is the back-ported and tweaked Blog Example package of FLOW3. Have fun playing with it!',
+       'category' => 'example',
+       'author' => 'TYPO3 core team',
+       'author_company' => '',
+       'author_email' => '',
+       'shy' => '',
+       'dependencies' => 'extbase,fluid',
+       'conflicts' => '',
+       'priority' => '',
+       'module' => '',
+       'state' => 'stable',
+       'internal' => '',
+       'uploadfolder' => 0,
+       'createDirs' => '',
+       'modify_tables' => '',
+       'clearCacheOnLoad' => 1,
+       'lockType' => '',
+       'version' => '1.4.0-devel',
+       'constraints' => array(
+               'depends' => array(
+                       'php' => '5.2.0-0.0.0',
+                       'typo3' => '4.5.0-0.0.0',
+                       'extbase' => '1.3.0-0.0.0',
+                       'fluid' => '1.3.0-0.0.0',
+               ),
+               'conflicts' => array(
+               ),
+               'suggests' => array(
+               ),
+       ),
+       '_md5_values_when_last_written' => 'a:77:{s:16:"ext_autoload.php";s:4:"91f9";s:21:"ext_conf_template.txt";s:4:"9b9c";s:12:"ext_icon.gif";s:4:"e922";s:17:"ext_localconf.php";s:4:"e7f7";s:14:"ext_tables.php";s:4:"b3b3";s:14:"ext_tables.sql";s:4:"33b2";s:41:"Classes/Controller/AbstractController.php";s:4:"44c4";s:37:"Classes/Controller/BlogController.php";s:4:"4f84";s:40:"Classes/Controller/CommentController.php";s:4:"fbc0";s:37:"Classes/Controller/PostController.php";s:4:"c44f";s:38:"Classes/Domain/Model/Administrator.php";s:4:"67d5";s:29:"Classes/Domain/Model/Blog.php";s:4:"1c30";s:32:"Classes/Domain/Model/Comment.php";s:4:"a01a";s:31:"Classes/Domain/Model/Person.php";s:4:"7fac";s:29:"Classes/Domain/Model/Post.php";s:4:"1285";s:28:"Classes/Domain/Model/Tag.php";s:4:"c0e8";s:53:"Classes/Domain/Repository/AdministratorRepository.php";s:4:"dd2e";s:44:"Classes/Domain/Repository/BlogRepository.php";s:4:"b84b";s:46:"Classes/Domain/Repository/PersonRepository.php";s:4:"58b9";s:44:"Classes/Domain/Repository/PostRepository.php";s:4:"58a3";s:38:"Classes/Domain/Service/BlogFactory.php";s:4:"643c";s:42:"Classes/Domain/Validator/BlogValidator.php";s:4:"e8bb";s:42:"Classes/ViewHelpers/GravatarViewHelper.php";s:4:"662a";s:41:"Configuration/FlexForms/flexform_list.xml";s:4:"11b7";s:25:"Configuration/TCA/tca.php";s:4:"875b";s:38:"Configuration/TypoScript/constants.txt";s:4:"0b87";s:34:"Configuration/TypoScript/setup.txt";s:4:"11cd";s:48:"Configuration/TypoScript/DefaultStyles/setup.txt";s:4:"ece4";s:46:"Resources/Private/Backend/Layouts/Default.html";s:4:"8b03";s:50:"Resources/Private/Backend/Templates/Blog/Edit.html";s:4:"9011";s:51:"Resources/Private/Backend/Templates/Blog/Index.html";s:4:"f4ca";s:49:"Resources/Private/Backend/Templates/Blog/New.html";s:4:"e68c";s:50:"Resources/Private/Backend/Templates/Post/Edit.html";s:4:"905a";s:51:"Resources/Private/Backend/Templates/Post/Index.html";s:4:"2247";s:50:"Resources/Private/Backend/Templates/Post/Index.txt";s:4:"ac46";s:49:"Resources/Private/Backend/Templates/Post/New.html";s:4:"ed51";s:50:"Resources/Private/Backend/Templates/Post/Show.html";s:4:"ab24";s:40:"Resources/Private/Language/locallang.xml";s:4:"0618";s:44:"Resources/Private/Language/locallang_csh.xml";s:4:"5e95";s:43:"Resources/Private/Language/locallang_db.xml";s:4:"e603";s:44:"Resources/Private/Language/locallang_mod.xml";s:4:"cd5d";s:38:"Resources/Private/Layouts/Default.html";s:4:"4ed3";s:40:"Resources/Private/Partials/BlogForm.html";s:4:"721f";s:43:"Resources/Private/Partials/CommentForm.html";s:4:"6606";s:42:"Resources/Private/Partials/FormErrors.html";s:4:"a141";s:40:"Resources/Private/Partials/PostForm.html";s:4:"04f6";s:44:"Resources/Private/Partials/PostMetaData.html";s:4:"9215";s:40:"Resources/Private/Partials/PostTags.html";s:4:"5d24";s:42:"Resources/Private/Templates/Blog/Edit.html";s:4:"8fab";s:43:"Resources/Private/Templates/Blog/Index.html";s:4:"69cc";s:41:"Resources/Private/Templates/Blog/New.html";s:4:"caaf";s:42:"Resources/Private/Templates/Post/Edit.html";s:4:"4dcf";s:43:"Resources/Private/Templates/Post/Index.html";s:4:"b81d";s:42:"Resources/Private/Templates/Post/Index.txt";s:4:"c3e6";s:41:"Resources/Private/Templates/Post/New.html";s:4:"9e3d";s:42:"Resources/Private/Templates/Post/Show.html";s:4:"bf64";s:36:"Resources/Public/Css/BlogExample.css";s:4:"9b2b";s:43:"Resources/Public/Icons/default_gravatar.gif";s:4:"6087";s:37:"Resources/Public/Icons/icon_close.gif";s:4:"31ee";s:38:"Resources/Public/Icons/icon_delete.gif";s:4:"90c6";s:36:"Resources/Public/Icons/icon_edit.gif";s:4:"3248";s:35:"Resources/Public/Icons/icon_new.gif";s:4:"5098";s:36:"Resources/Public/Icons/icon_next.gif";s:4:"6add";s:41:"Resources/Public/Icons/icon_plaintext.gif";s:4:"af96";s:40:"Resources/Public/Icons/icon_populate.gif";s:4:"500c";s:40:"Resources/Public/Icons/icon_previous.gif";s:4:"50c0";s:40:"Resources/Public/Icons/icon_relation.gif";s:4:"9e5c";s:64:"Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif";s:4:"50a3";s:67:"Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif";s:4:"53ba";s:66:"Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif";s:4:"0bef";s:64:"Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif";s:4:"cf99";s:63:"Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif";s:4:"3731";s:46:"Resources/Public/Icons/FlashMessages/error.png";s:4:"1c8f";s:52:"Resources/Public/Icons/FlashMessages/information.png";s:4:"6235";s:47:"Resources/Public/Icons/FlashMessages/notice.png";s:4:"813d";s:43:"Resources/Public/Icons/FlashMessages/ok.png";s:4:"e36c";s:48:"Resources/Public/Icons/FlashMessages/warning.png";s:4:"dada";}',
+       'suggests' => array(
+       ),
+);
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_icon.gif b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_icon.gif
new file mode 100644 (file)
index 0000000..1a832d4
Binary files /dev/null and b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_icon.gif differ
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.php
new file mode 100644 (file)
index 0000000..0df4283
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+if (!defined ('TYPO3_MODE')) die ('Access denied.');
+
+/**
+ * Add labels for context sensitive help (CSH)
+ */
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addLLrefForTCAdescr('_MOD_web_BlogExampleTxBlogexampleM1', 'EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_csh.xml');
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript', 'BlogExample setup');
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile($_EXTKEY, 'Configuration/TypoScript/DefaultStyles', 'BlogExample CSS Styles (optional)');
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_blogexample_domain_model_blog');
+$TCA['tx_blogexample_domain_model_blog'] = array (
+       'ctrl' => array (
+               'title'    => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_blog',
+               'label' => 'title',
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'versioningWS' => 2,
+               'versioning_followPages' => true,
+               'origUid' => 't3_origuid',
+               'languageField' => 'sys_language_uid',
+               'transOrigPointerField' => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden'
+                       ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Configuration/TCA/Blog.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Icons/icon_tx_blogexample_domain_model_blog.gif'
+       )
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_blogexample_domain_model_post');
+$TCA['tx_blogexample_domain_model_post'] = array (
+       'ctrl' => array (
+               'title'    => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_post',
+               'label' => 'title',
+               'label_alt' => 'author',
+               'label_alt_force' => TRUE,
+               'tstamp'   => 'tstamp',
+               'crdate'   => 'crdate',
+               'versioningWS' => 2,
+               'versioning_followPages' => true,
+               'origUid' => 't3_origuid',
+               'languageField' => 'sys_language_uid',
+               'transOrigPointerField' => 'l18n_parent',
+               'transOrigDiffSourceField' => 'l18n_diffsource',
+               'delete'   => 'deleted',
+               'enablecolumns'  => array(
+                       'disabled' => 'hidden'
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Configuration/TCA/Post.php',
+               'iconfile'   => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Icons/icon_tx_blogexample_domain_model_post.gif'
+       )
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_blogexample_domain_model_comment');
+$TCA['tx_blogexample_domain_model_comment'] = array (
+       'ctrl' => array (
+               'title'    => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_comment',
+               'label' => 'date',
+               'label_alt' => 'author',
+               'label_alt_force' => TRUE,
+               'tstamp'   => 'tstamp',
+               'crdate'   => 'crdate',
+               'delete'   => 'deleted',
+               'enablecolumns'  => array (
+                       'disabled' => 'hidden'
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Configuration/TCA/Comment.php',
+               'iconfile'   => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Icons/icon_tx_blogexample_domain_model_comment.gif'
+       )
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_blogexample_domain_model_person');
+$TCA['tx_blogexample_domain_model_person'] = array (
+       'ctrl' => array (
+               'title'    => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_person',
+               'label' => 'lastname',
+               'label_alt' => 'firstname',
+               'label_alt_force' => TRUE,
+               'tstamp' => 'tstamp',
+               'crdate' => 'crdate',
+               'versioningWS' => 2,
+               'versioning_followPages' => true,
+               'origUid' => 't3_origuid',
+               'prependAtCopy' => 'LLL:EXT:lang/locallang_general.xml:LGL.prependAtCopy',
+               'delete' => 'deleted',
+               'enablecolumns' => array(
+                       'disabled' => 'hidden'
+                       ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Configuration/TCA/Person.php',
+               'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Icons/icon_tx_blogexample_domain_model_person.gif'
+       )
+);
+
+\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_blogexample_domain_model_tag');
+$TCA['tx_blogexample_domain_model_tag'] = array (
+       'ctrl' => array (
+               'title'    => 'LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:tx_blogexample_domain_model_tag',
+               'label' => 'name',
+               'tstamp'   => 'tstamp',
+               'crdate'   => 'crdate',
+               'delete'   => 'deleted',
+               'enablecolumns'  => array (
+                       'disabled' => 'hidden'
+               ),
+               'dynamicConfigFile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($_EXTKEY) . 'Configuration/TCA/Tag.php',
+               'iconfile'   => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'Resources/Public/Icons/icon_tx_blogexample_domain_model_tag.gif'
+       )
+);
+
+if (is_array($TCA['fe_users']['columns']['tx_extbase_type'])) {
+       $TCA['fe_users']['types']['Tx_BlogExample_Domain_Model_Administrator'] = $TCA['fe_users']['types']['0'];
+       array_push($TCA['fe_users']['columns']['tx_extbase_type']['config']['items'], array('LLL:EXT:blog_example/Resources/Private/Language/locallang_db.xml:fe_users.tx_extbase_type.Tx_BlogExample_Domain_Model_Administrator', 'Tx_BlogExample_Domain_Model_Administrator'));
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_tables.sql
new file mode 100644 (file)
index 0000000..54c183e
--- /dev/null
@@ -0,0 +1,185 @@
+#
+# Table structure for table 'tx_blogexample_domain_model_blog'
+#
+CREATE TABLE tx_blogexample_domain_model_blog (
+       uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+
+       title varchar(255) DEFAULT '' NOT NULL,
+       description text NOT NULL,
+       logo tinyblob NOT NULL,
+       administrator varchar(255) DEFAULT '',
+
+       posts varchar(255) DEFAULT '' NOT NULL,
+
+       tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+       crdate int(11) unsigned DEFAULT '0' NOT NULL,
+       deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid),
+       KEY t3ver_oid (t3ver_oid,t3ver_wsid),
+);
+
+#
+# Table structure for table 'tx_blogexample_domain_model_post'
+#
+CREATE TABLE tx_blogexample_domain_model_post (
+       uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+
+       blog int(11) DEFAULT '0' NOT NULL,
+
+       title varchar(255) DEFAULT '' NOT NULL,
+       date int(11) DEFAULT '0' NOT NULL,
+       author int(255) DEFAULT '0' NOT NULL,
+       content text NOT NULL,
+       tags int(11) unsigned DEFAULT '0' NOT NULL,
+       comments int(11) unsigned DEFAULT '0' NOT NULL,
+       related_posts int(11) unsigned DEFAULT '0' NOT NULL,
+
+       tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+       crdate int(11) unsigned DEFAULT '0' NOT NULL,
+       deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       sorting tinyint(4) unsigned DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid),
+       KEY t3ver_oid (t3ver_oid,t3ver_wsid),
+);
+
+#
+# Table structure for table 'tx_blogexample_domain_model_comment'
+#
+CREATE TABLE tx_blogexample_domain_model_comment (
+       uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+
+       post int(11) DEFAULT '0' NOT NULL,
+
+       date int(11) DEFAULT '0' NOT NULL,
+       author varchar(255) DEFAULT '' NOT NULL,
+       email varchar(255) DEFAULT '' NOT NULL,
+       content text NOT NULL,
+
+       tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+       crdate int(11) unsigned DEFAULT '0' NOT NULL,
+       deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid),
+);
+
+#
+# Table structure for table 'tx_blogexample_domain_model_person'
+#
+CREATE TABLE tx_blogexample_domain_model_person (
+       uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+
+       firstname varchar(255) DEFAULT '' NOT NULL,
+       lastname varchar(255) DEFAULT '' NOT NULL,
+       email varchar(255) DEFAULT '' NOT NULL,
+
+       tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+       crdate int(11) unsigned DEFAULT '0' NOT NULL,
+       deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
+
+       t3ver_oid int(11) DEFAULT '0' NOT NULL,
+       t3ver_id int(11) DEFAULT '0' NOT NULL,
+       t3ver_wsid int(11) DEFAULT '0' NOT NULL,
+       t3ver_label varchar(30) DEFAULT '' NOT NULL,
+       t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
+       t3ver_count int(11) DEFAULT '0' NOT NULL,
+       t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
+       t3ver_move_id int(11) DEFAULT '0' NOT NULL,
+       t3_origuid int(11) DEFAULT '0' NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid),
+       KEY t3ver_oid (t3ver_oid,t3ver_wsid),
+);
+
+#
+# Table structure for table 'tx_blogexample_domain_model_tag'
+#
+CREATE TABLE tx_blogexample_domain_model_tag (
+       uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
+       pid int(11) DEFAULT '0' NOT NULL,
+
+       name varchar(255) DEFAULT '' NOT NULL,
+       posts int(11) unsigned DEFAULT '0' NOT NULL,
+
+       tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+       crdate int(11) unsigned DEFAULT '0' NOT NULL,
+       deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
+       hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,
+
+       sys_language_uid int(11) DEFAULT '0' NOT NULL,
+       l18n_parent int(11) DEFAULT '0' NOT NULL,
+       l18n_diffsource mediumblob NOT NULL,
+
+       PRIMARY KEY (uid),
+       KEY parent (pid),
+);
+
+#
+# Table structure for table 'tx_blogexample_post_tag_mm'
+#
+CREATE TABLE tx_blogexample_post_tag_mm (
+       uid_local int(11) unsigned DEFAULT '0' NOT NULL,
+       uid_foreign int(11) unsigned DEFAULT '0' NOT NULL,
+       sorting int(11) unsigned DEFAULT '0' NOT NULL,
+       sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL,
+
+       KEY uid_local (uid_local),
+       KEY uid_foreign (uid_foreign)
+);
+
+#
+# Table structure for table 'tx_blogexample_post_post_mm'
+#
+CREATE TABLE tx_blogexample_post_post_mm (
+       uid_local int(11) unsigned DEFAULT '0' NOT NULL,
+       uid_foreign int(11) unsigned DEFAULT '0' NOT NULL,
+       sorting int(11) unsigned DEFAULT '0' NOT NULL,
+       sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL,
+
+       KEY uid_local (uid_local),
+       KEY uid_foreign (uid_foreign)
+);
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt
new file mode 100644 (file)
index 0000000..c3f0d3a
--- /dev/null
@@ -0,0 +1,19 @@
+ # global configuration
+
+config.tx_extbase {
+       persistence{
+               classes {
+                       Extbase\Domain\ModelFrontendUser {
+                               subclasses {
+                                       ExtbaseTeam\BlogExample\Domain\Model\Administrator = ExtbaseTeam\BlogExample\Domain\Model\Administrator
+                               }
+                       }
+                       ExtbaseTeam\BlogExample\Domain\Model\Administrator {
+                               mapping {
+                                       tableName = fe_users
+                                       recordType = ExtbaseTeam\BlogExample\Domain\Model\Administrator
+                               }
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/blogs.xml b/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/blogs.xml
new file mode 100644 (file)
index 0000000..b1eb201
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+       <tx_blogexample_domain_model_blog>
+               <uid>1</uid>
+               <pid>0</pid>
+               <title>Blog1</title>
+               <deleted>0</deleted>
+               <posts>10</posts>
+       </tx_blogexample_domain_model_blog>
+</dataset>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/post-tag-mm.xml b/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/post-tag-mm.xml
new file mode 100644 (file)
index 0000000..fa85b38
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset><!-- foregin == tag-->
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>2</uid_foreign>
+               <sorting>2</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>3</uid_foreign>
+               <sorting>3</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>4</uid_foreign>
+               <sorting>4</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>5</uid_foreign>
+               <sorting>5</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>6</uid_foreign>
+               <sorting>6</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>7</uid_foreign>
+               <sorting>7</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>8</uid_foreign>
+               <sorting>8</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>9</uid_foreign>
+               <sorting>9</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>1</uid_local>
+               <uid_foreign>10</uid_foreign>
+               <sorting>10</sorting>
+               <sorting_foreign>1</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+
+       <!-- tag id 1 has 10 posts -->
+
+       <tx_blogexample_post_tag_mm>
+               <uid_local>2</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>2</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>3</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>3</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>4</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>4</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>5</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>5</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>6</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>6</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>7</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>7</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>8</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>8</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>9</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>9</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+       <tx_blogexample_post_tag_mm>
+               <uid_local>10</uid_local>
+               <uid_foreign>1</uid_foreign>
+               <sorting>1</sorting>
+               <sorting_foreign>10</sorting_foreign>
+       </tx_blogexample_post_tag_mm>
+</dataset>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/posts.xml b/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/posts.xml
new file mode 100644 (file)
index 0000000..e41e115
--- /dev/null
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+       <tx_blogexample_domain_model_post>
+               <uid>1</uid>
+               <pid>0</pid>
+               <tstamp>121319</tstamp>
+               <blog>1</blog>
+               <tags>10</tags>
+               <title>Post1</title>
+               <sorting>1</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>2</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post2</title>
+               <sorting>2</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>3</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post3</title>
+               <sorting>3</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>4</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post4</title>
+               <sorting>4</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>5</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post5</title>
+               <sorting>5</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>6</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post6</title>
+               <sorting>6</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>7</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post7</title>
+               <sorting>7</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>8</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post8</title>
+               <sorting>8</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>9</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post9</title>
+               <sorting>9</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+       <tx_blogexample_domain_model_post>
+               <uid>10</uid>
+               <pid>0</pid>
+               <blog>1</blog>
+               <tags>1</tags>
+               <title>Post10</title>
+               <sorting>10</sorting>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_post>
+</dataset>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/tags.xml b/typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/tags.xml
new file mode 100644 (file)
index 0000000..e7af7ac
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+       <tx_blogexample_domain_model_tag>
+               <uid>1</uid>
+               <pid>0</pid>
+               <posts>10</posts>
+               <name>Tag1</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>2</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag2</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>3</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag3</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>4</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag4</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>5</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag5</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>6</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag6</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>7</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag7</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>8</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag8</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>9</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag9</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+       <tx_blogexample_domain_model_tag>
+               <uid>10</uid>
+               <pid>0</pid>
+               <posts>1</posts>
+               <name>Tag10</name>
+               <deleted>0</deleted>
+       </tx_blogexample_domain_model_tag>
+</dataset>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Relations/RelationTest.php b/typo3/sysext/extbase/Tests/Functional/Relations/RelationTest.php
new file mode 100644 (file)
index 0000000..8ffee53
--- /dev/null
@@ -0,0 +1,439 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Functional\Relations;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2014 Tymoteusz Motylewski <t.motylewski@gmail.com>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
+
+class RelationTest extends \TYPO3\CMS\Core\Tests\FunctionalTestCase {
+
+       /**
+        * @var \ExtbaseTeam\BlogExample\Domain\Model\Blog
+        */
+       protected $blog;
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
+        */
+       protected $persistentManager;
+
+       protected $testExtensionsToLoad = array('typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example');
+
+       protected $coreExtensionsToLoad = array('extbase', 'fluid');
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface The object manager
+        */
+       protected $objectManager;
+
+       /**
+        * Sets up this test suite.
+        */
+       public function setUp() {
+               parent::setUp();
+
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/pages.xml');
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/blogs.xml');
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/posts.xml');
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/tags.xml');
+               $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Relations/Fixtures/post-tag-mm.xml');
+
+               $this->objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
+               $this->persistentManager = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager');
+               /* @var $blogRepository \TYPO3\CMS\Extbase\Persistence\Repository */
+               $blogRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\BlogRepository');
+               $this->blog = $blogRepository->findByUid(1);
+       }
+
+       /**
+        * Tests adding object at the end of sorted 1:M relation (Blog:Posts)
+        *
+        * @test
+        */
+       public function attachPostToBlogAtTheEnd() {
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(10, $countPosts);
+
+               $newPostTitle = 'sdufhisdhuf';
+               $newPost = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Model\\Post');
+               $newPost->setBlog($this->blog);
+               $newPost->setTitle($newPostTitle);
+               $newPost->setContent('Bla Bla Bla');
+
+               $this->blog->addPost($newPost);
+               $this->updateAndPersistBlog();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(11, $countPosts);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'blog =' . $this->blog->getUid(), '', 'sorting DESC');
+               $this->assertSame($newPostTitle, $post['title']);
+               $this->assertSame('11', $post['sorting']);
+       }
+
+       /**
+        * Tests removing object from the end of sorted 1:M relation (Blog:Posts)
+        *
+        * @test
+        */
+       public function removeLastPostFromBlog() {
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(10, $countPosts);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('sorting', 'tx_blogexample_domain_model_post', 'blog =' . $this->blog->getUid(), '', 'sorting DESC');
+               $this->assertEquals(10, $post['sorting']);
+
+               $posts = $this->blog->getPosts();
+               $postsArray = $posts->toArray();
+               $latestPost = array_pop($postsArray);
+
+               $this->assertEquals(10, $latestPost->getUid());
+
+               $this->blog->removePost($latestPost);
+               $this->updateAndPersistBlog();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post', 'deleted=0');
+               $this->assertEquals(9, $countPosts);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('uid', 'tx_blogexample_domain_model_post', 'uid =' . $latestPost->getUid() . ' AND deleted=0');
+               $this->assertSame(NULL, $post['uid']);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'blog =' . $this->blog->getUid(), '', 'sorting DESC');
+               $this->assertSame('Post9', $post['title']);
+               $this->assertSame('9', $post['sorting']);
+       }
+
+       /**
+        * Tests adding object in the middle of the sorted 1:M relation (Blog:Posts)
+        *
+        * @test
+        */
+       public function addPostToBlogInTheMiddle() {
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(10, $countPosts);
+
+               $posts = clone $this->blog->getPosts();
+               $this->blog->getPosts()->removeAll($posts);
+               $counter = 1;
+               $newPostTitle = 'INSERTED POST at position 6';
+               foreach ($posts as $post) {
+                       $this->blog->addPost($post);
+                       if ($counter == 5) {
+                               $newPost = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Model\\Post');
+                               $newPost->setBlog($this->blog);
+                               $newPost->setTitle($newPostTitle);
+                               $newPost->setContent('Bla Bla Bla');
+                               $this->blog->addPost($newPost);
+                       }
+                       $counter++;
+               }
+               $this->updateAndPersistBlog();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post',  'deleted=0');
+               $this->assertSame(11, $countPosts);
+
+               //last post
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'blog =' . $this->blog->getUid(), '', 'sorting DESC');
+               $this->assertSame('Post10', $post['title']);
+               $this->assertSame('11', $post['sorting']);
+
+               // check sorting of the post added in the middle
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'uid=11');
+               $this->assertSame($newPostTitle, $post['title']);
+               $this->assertSame('6', $post['sorting']);
+       }
+
+       /**
+        * Tests removing object from the middle of sorted 1:M relation (Blog:Posts)
+        *
+        * @test
+        */
+       public function removeMiddlePostFromBlog() {
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(10, $countPosts);
+
+               $posts = clone $this->blog->getPosts();
+               $counter = 1;
+               foreach ($posts as $post) {
+                       if ($counter == 5) {
+                               $this->blog->removePost($post);
+                       }
+                       $counter++;
+               }
+               $this->updateAndPersistBlog();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post', 'deleted=0');
+               $this->assertSame(9, $countPosts);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'blog ='.$this->blog->getUid(), '', 'sorting DESC');
+               $this->assertSame('Post10', $post['title']);
+               $this->assertSame('10', $post['sorting']);
+       }
+
+       /**
+        * Tests moving object from the end to the middle of the sorted 1:M relation (Blog:Posts)
+        *
+        * @test
+        */
+       public function movePostFromEndToTheMiddle() {
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post');
+               $this->assertSame(10, $countPosts);
+
+               $posts = clone $this->blog->getPosts();
+               $postsArray = $posts->toArray();
+               $latestPost = array_pop($postsArray);
+
+               $this->blog->getPosts()->removeAll($posts);
+               $counter = 0;
+               $postCount = $posts->count();
+               foreach ($posts as $post) {
+                       if ($counter != ($postCount - 1)) {
+                               $this->blog->addPost($post);
+                       }
+                       if ($counter == 4) {
+                               $latestPost->setTitle('MOVED POST ' . $latestPost->getTitle());
+                               $this->blog->addPost($latestPost);
+                       }
+                       $counter++;
+               }
+               $this->updateAndPersistBlog();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_post', 'deleted=0');
+               $this->assertSame(10, $countPosts);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,sorting', 'tx_blogexample_domain_model_post', 'blog ='.$this->blog->getUid(), '', 'sorting DESC');
+               $this->assertSame('Post9', $post['title']);
+               $this->assertSame('10', $post['sorting']);
+
+               $post = $this->getDatabase()->exec_SELECTgetSingleRow('title,uid', 'tx_blogexample_domain_model_post', 'blog ='.$this->blog->getUid().' AND sorting=6');
+               $this->assertSame('MOVED POST Post10', $post['title']);
+               $this->assertSame('10', $post['uid']);
+       }
+
+       /**
+        * Tests adding object at the end of sorted M:M relation (Post:Tag)
+        *
+        * @test
+        */
+       public function attachTagToPostAtTheEnd() {
+               $count = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_tag');
+               $this->assertSame(10, $count);
+
+               $newTagTitle = 'sdufhisdhuf';
+               $newTag = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Model\\Tag', $newTagTitle);
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $post->addTag($newTag);
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $count = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_tag');
+               $this->assertSame(11, $count);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid(), '', 'sorting DESC');
+               $this->assertSame('11', $tag['uid_foreign']);
+       }
+
+
+       /**
+        * Tests removing object from the end of sorted M:M relation (Post:Tag)
+        *
+        * @test
+        */
+       public  function removeLastTagFromPost() {
+               $count = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_tag');
+               $this->assertSame(10, $count);
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $tags = $post->getTags();
+               $tagsArray = $tags->toArray();
+               $latestTag = array_pop($tagsArray);
+
+               $this->assertEquals(10, $latestTag->getUid());
+
+               $post->removeTag($latestTag);
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $countPosts = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_domain_model_tag', 'deleted=0' );
+               $this->assertEquals(10, $countPosts);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid(), '', 'sorting DESC');
+               $this->assertSame('9', $tag['uid_foreign']);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid().' AND uid_foreign='.$latestTag->getUid());
+               $this->assertSame(NULL, $tag['uid_foreign']);
+       }
+
+       /**
+        * Tests adding object in the middle of sorted M:M relation (Post:Tag)
+        *
+        * @test
+        */
+       public  function addTagToPostInTheMiddle() {
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(10, $countTags);
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $tags = clone $post->getTags();
+               $post->setTags(new ObjectStorage());
+
+               $counter = 1;
+               foreach ($tags as $tag) {
+                       $post->addTag($tag);
+                       if ($counter == 5) {
+                               $newTag = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Model\\Tag', 'INSERTED TAG at position 6 : ' . strftime(''));
+                               $post->addTag($newTag);
+                       }
+                       $counter++;
+               }
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(11, $countTags);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid(), '', 'sorting DESC');
+               $this->assertSame('10', $tag['uid_foreign']);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid().' AND sorting=6');
+               $this->assertSame('11', $tag['uid_foreign']);
+       }
+
+
+       /**
+        * Tests removing object from the middle of the sorted M:M relation (Post:Tag)
+        *
+        * @test
+        */
+       public function removeMiddleTagFromPost() {
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(10, $countTags);
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $tags = clone $post->getTags();
+               $counter = 1;
+               foreach ($tags as $tag) {
+                       if ($counter == 5) {
+                               $post->removeTag($tag);
+                       }
+                       $counter++;
+               }
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(9, $countTags);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign,sorting', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid(), '', 'sorting DESC');
+               $this->assertSame('10', $tag['uid_foreign']);
+               $this->assertSame('10', $tag['sorting']);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid().' AND sorting=5');
+               $this->assertSame(NULL, $tag['uid_foreign']);
+       }
+
+       /**
+        * Tests moving object from the end to the middle of sorted M:M relation (Post:Tag)
+        *
+        * @test
+        */
+       public function moveTagFromEndToTheMiddle() {
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(10, $countTags);
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $tags = clone $post->getTags();
+               $tagsArray = $tags->toArray();
+               $latestTag = array_pop($tagsArray);
+               $post->removeTag($latestTag);
+               $post->setTags(new ObjectStorage());
+
+               $counter = 1;
+               $tagCount = $tags->count();
+               foreach ($tags as $tag) {
+                       if ($counter != $tagCount) {
+                               $post->addTag($tag);
+                       }
+                       if ($counter == 5) {
+                               $post->addTag($latestTag);
+                       }
+                       $counter++;
+               }
+               $post->addTag($latestTag);
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $countTags = $this->getDatabase()->exec_SELECTcountRows('*', 'tx_blogexample_post_tag_mm', 'uid_local=1');
+               $this->assertSame(10, $countTags);
+
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign,sorting', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid(), '', 'sorting DESC');
+               $this->assertSame('9', $tag['uid_foreign']);
+               $this->assertSame('10', $tag['sorting']);
+
+               $sorting = '6';
+               $tag = $this->getDatabase()->exec_SELECTgetSingleRow('uid_foreign', 'tx_blogexample_post_tag_mm', 'uid_local ='.$post->getUid().' AND sorting='.$sorting);
+               $this->assertSame('10', $tag['uid_foreign']);
+       }
+
+       /**
+        * Test if timestamp field is updated when updating a record
+        *
+        * @test
+        */
+       public function timestampFieldIsUpdatedOnPostSave() {
+               $rawPost = $this->getDatabase()->exec_SELECTgetSingleRow('*', 'tx_blogexample_domain_model_post', 'uid=1');
+
+               $postRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\PostRepository');
+               $post = $postRepository->findByUid(1);
+               $post->setTitle("newTitle");
+
+               $postRepository->update($post);
+               $this->persistentManager->persistAll();
+
+               $rawPost2 = $this->getDatabase()->exec_SELECTgetSingleRow('*', 'tx_blogexample_domain_model_post', 'uid=1');
+               $this->assertTrue($rawPost2['tstamp'] > $rawPost['tstamp']);
+       }
+
+       /**
+        * Helper method for persisting blog
+        */
+       protected function updateAndPersistBlog() {
+               /** @var \ExtbaseTeam\BlogExample\Domain\Repository\BlogRepository $blogRepository */
+               $blogRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\BlogRepository');
+               $blogRepository->update($this->blog);
+               $this->persistentManager->persistAll();
+       }
+}
\ No newline at end of file