[TASK] Doctrine: Migrate DatabaseTreeDataProvider 29/49429/2
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Tue, 9 Aug 2016 09:55:05 +0000 (11:55 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Thu, 11 Aug 2016 20:09:26 +0000 (22:09 +0200)
Change-Id: Ibd42487c4a3dc263fd19ded9049460955814fa85
Resolves: #77451
Releases: master
Reviewed-on: https://review.typo3.org/49429
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Bamboo TYPO3com <info@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Tree/TableConfiguration/DatabaseTreeDataProvider.php
typo3/sysext/core/Tests/Unit/Tree/TableConfiguration/DatabaseTreeDataProviderTest.php

index 4f6d766..1540c96 100644 (file)
@@ -15,9 +15,13 @@ namespace TYPO3\CMS\Core\Tree\TableConfiguration;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 
 /**
  * TCA tree data provider
@@ -88,7 +92,7 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
     protected $generatedTSConfig = array();
 
     /**
-     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @var Dispatcher
      */
     protected $signalSlotDispatcher;
 
@@ -325,9 +329,17 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
     {
         $nodeData = null;
         if ($node->getId() !== 0) {
-            $nodeData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', $this->tableName, 'uid=' . $node->getId());
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getQueryBuilderForTable($this->getTableName());
+            $queryBuilder->getRestrictions()->removeAll();
+            $nodeData = $queryBuilder->select('*')
+                ->from($this->getTableName())
+                ->where($queryBuilder->expr()->eq('uid', $node->getId()))
+                ->setMaxResults(1)
+                ->execute()
+                ->fetch();
         }
-        if ($nodeData == null) {
+        if (empty($nodeData)) {
             $nodeData = array(
                 'uid' => 0,
                 $this->getLookupField() => ''
@@ -421,17 +433,31 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
         $value = $row[$this->getLookupField()];
         switch ((string)$this->columnConfiguration['type']) {
             case 'inline':
-
+                // Intentional fall-through
             case 'select':
                 if ($this->columnConfiguration['MM']) {
-                    /** @var $dbGroup \TYPO3\CMS\Core\Database\RelationHandler */
                     $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
-                    $dbGroup->start($value, $this->getTableName(), $this->columnConfiguration['MM'], $uid, $this->getTableName(), $this->columnConfiguration);
+                    $dbGroup->start(
+                        $value,
+                        $this->getTableName(),
+                        $this->columnConfiguration['MM'],
+                        $uid,
+                        $this->getTableName(),
+                        $this->columnConfiguration
+                    );
                     $relatedUids = $dbGroup->tableArray[$this->getTableName()];
                 } elseif ($this->columnConfiguration['foreign_field']) {
-                    $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $this->getTableName(), $this->columnConfiguration['foreign_field'] . '=' . (int)$uid);
-                    foreach ($records as $record) {
-                        $relatedUids[] = $record['uid'];
+                    $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                        ->getQueryBuilderForTable($this->getTableName());
+                    $queryBuilder->getRestrictions()->removeAll();
+                    $records = $queryBuilder->select('uid')
+                        ->from($this->getTableName())
+                        ->where($queryBuilder->expr()->eq($this->columnConfiguration['foreign_field'], (int)$uid))
+                        ->execute()
+                        ->fetchAll();
+
+                    if (!empty($records)) {
+                        $relatedUids = array_column($records, 'uid');
                     }
                 } else {
                     $relatedUids = GeneralUtility::intExplode(',', $value, true);
@@ -452,13 +478,28 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
      */
     protected function listFieldQuery($fieldName, $queryId)
     {
-        $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $this->getTableName(), $GLOBALS['TYPO3_DB']->listQuery($fieldName, (int)$queryId, $this->getTableName()) . ((int)$queryId === 0 ? ' OR CAST(' . $fieldName . ' AS CHAR) = \'\'' : ''));
-        $uidArray = array();
-        if (!empty($records)) {
-            foreach ($records as $record) {
-                $uidArray[] = $record['uid'];
-            }
+        $queryId = (int)$queryId;
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->getTableName());
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $queryBuilder->select('uid')
+            ->from($this->getTableName())
+            ->where($queryBuilder->expr()->inSet($fieldName, $queryId));
+
+        if ($queryId === 0) {
+            $queryBuilder->orWhere(
+                $queryBuilder->expr()->comparison(
+                    'CAST(' . $queryBuilder->quoteIdentifier($fieldName) . ' AS CHAR)',
+                    ExpressionBuilder::EQ,
+                    $queryBuilder->quote('')
+                )
+            );
         }
+
+        $records = $queryBuilder->execute()->fetchAll();
+        $uidArray = is_array($records) ? array_column($records, 'uid') : [];
+
         return $uidArray;
     }
 
@@ -469,21 +510,22 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
      */
     protected function emitPostProcessTreeDataSignal()
     {
-        $this->getSignalSlotDispatcher()->dispatch(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::class,
+        $this->getSignalSlotDispatcher()->dispatch(
+            DatabaseTreeDataProvider::class,
             self::SIGNAL_PostProcessTreeData,
-            array($this, $this->treeData)
+            [$this, $this->treeData]
         );
     }
 
     /**
      * Get the SignalSlot dispatcher
      *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @return Dispatcher
      */
     protected function getSignalSlotDispatcher()
     {
         if (!isset($this->signalSlotDispatcher)) {
-            $this->signalSlotDispatcher = $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+            $this->signalSlotDispatcher = $this->getObjectManager()->get(Dispatcher::class);
         }
         return $this->signalSlotDispatcher;
     }
@@ -491,10 +533,10 @@ class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvide
     /**
      * Get the ObjectManager
      *
-     * @return \TYPO3\CMS\Extbase\Object\ObjectManager
+     * @return ObjectManager
      */
     protected function getObjectManager()
     {
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
+        return GeneralUtility::makeInstance(ObjectManager::class);
     }
 }
index 112466d..88b53d2 100644 (file)
@@ -14,11 +14,18 @@ namespace TYPO3\CMS\Core\Tests\Unit\Tree\TableConfiguration;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\Driver\Statement;
+use Prophecy\Argument;
 use TYPO3\CMS\Backend\Tree\TreeNode;
 use TYPO3\CMS\Backend\Tree\TreeNodeCollection;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
+use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
+use TYPO3\CMS\Core\Database\Query\QueryBuilder;
+use TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface;
 use TYPO3\CMS\Core\Tests\UnitTestCase;
 use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Testcase for \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider
@@ -47,12 +54,66 @@ class DatabaseTreeDataProviderTest extends UnitTestCase
      */
     protected function setUp()
     {
-        $this->database = $this->getMockBuilder(DatabaseConnection::class)
-            ->setMethods(array('exec_SELECTgetSingleRow'))
-            ->getMock();
-        $this->database->expects($this->any())->method('exec_SELECTgetSingleRow')->will($this->returnValue(array('uid' => 0, 'parent' => '')));
         $this->treeData = new TreeNode();
-        $GLOBALS['TYPO3_DB'] = $this->database;
+    }
+
+    /**
+     * Setup prophecies for database stack
+     *
+     * @param int $instanceCount Number of instances of ConnectionPool::class to register
+     * @return \Prophecy\Prophecy\ObjectProphecy|\TYPO3\CMS\Core\Database\Query\QueryBuilder
+     */
+    protected function setupDatabaseMock(int $instanceCount = 1)
+    {
+        // Prophecies and revelations for a lot of the database stack classes
+        $connectionPoolProphecy = $this->prophesize(ConnectionPool::class);
+        $queryRestrictionProphecy = $this->prophesize(QueryRestrictionContainerInterface::class);
+        $queryBuilderProphecy = $this->prophesize(QueryBuilder::class);
+        $expressionBuilderProphecy = $this->prophesize(ExpressionBuilder::class);
+        $statementProphecy = $this->prophesize(Statement::class);
+
+        $expressionBuilderProphecy->eq(Argument::cetera())->willReturn('1=1');
+
+        // Simulate method call flow on database objects and verify correct query is built
+        $connectionPoolProphecy->getQueryBuilderForTable(Argument::cetera())
+            ->shouldBeCalled()
+            ->willReturn($queryBuilderProphecy->reveal());
+        $queryRestrictionProphecy->removeAll()
+            ->shouldBeCalled()
+            ->willReturn($queryRestrictionProphecy->reveal());
+        $queryBuilderProphecy->getRestrictions()
+            ->shouldBeCalled()
+            ->willReturn($queryRestrictionProphecy->reveal());
+        $queryBuilderProphecy->expr()
+            ->shouldBeCalled()
+            ->willReturn($expressionBuilderProphecy->reveal());
+        $queryBuilderProphecy->execute()
+            ->shouldBeCalled()
+            ->willReturn($statementProphecy->reveal());
+
+        $queryBuilderProphecy->select(Argument::cetera())
+            ->shouldBeCalled()
+            ->willReturn($queryBuilderProphecy->reveal());
+        $queryBuilderProphecy->from(Argument::cetera())
+            ->shouldBeCalled()
+            ->willReturn($queryBuilderProphecy->reveal());
+        $queryBuilderProphecy->where(Argument::cetera())
+            ->shouldBeCalled()
+            ->willReturn($queryBuilderProphecy->reveal());
+        $queryBuilderProphecy->setMaxResults(Argument::cetera())
+            ->shouldBeCalled()
+            ->willReturn($queryBuilderProphecy->reveal());
+
+        $statementProphecy->fetch()
+            ->shouldBeCalled()
+            ->willReturn(['uid' => 0, 'parent' => '']);
+
+        // Register connection pool revelation in framework, this is the entry point used by system unter test
+        for ($i = 1; $i <= $instanceCount; $i++) {
+            GeneralUtility::addInstance(ConnectionPool::class, $connectionPoolProphecy->reveal());
+        }
+
+        return $queryBuilderProphecy;
     }
 
     /**
@@ -92,6 +153,8 @@ class DatabaseTreeDataProviderTest extends UnitTestCase
      */
     public function getChildrenOfLevelMaximumSetToOneWorks()
     {
+        $this->setupDatabaseMock();
+
         $expectedTreeNode = new TreeNode();
         $expectedTreeNode->setId(1);
         $expectedStorage = new TreeNodeCollection();
@@ -110,6 +173,8 @@ class DatabaseTreeDataProviderTest extends UnitTestCase
      */
     public function getChildrenOfLevelMaximumSetToTwoWorks()
     {
+        $this->setupDatabaseMock(2);
+
         $expectedStorage = new TreeNodeCollection();
 
         $expectedFirstLevelTreeNode = new TreeNode();