Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merging with trunk

  • Loading branch information...
commit 6636c512eb3fc36f678e0111dcec9664a30c4d65 2 parents 0c920a2 + 7e9e119
@chdemko authored
View
3  docs/manual/en-US/chapters/packages.xml
@@ -15,5 +15,8 @@
<xi:include href="packages/log.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="packages/database.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
<xi:include href="packages/filesystem.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
</chapter>
View
33 docs/manual/en-US/chapters/packages/database.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "../../Developer_Manual.ent">
+%BOOK_ENTITIES;
+]>
+<section id="chap-Joomla_Platform_Manual-Database">
+ <title>Database</title>
+
+ <section>
+ <title>Introduction</title>
+
+ <para>The <emphasis>Database</emphasis> package is designed to manage the operations of data management through the use of a generic database engine.</para>
+
+ </section>
+
+ <section>
+ <title>Iterating on results</title>
+
+ <para>The <code language="PHP (HTML)">JDatabaseIterator</code> class allows iteration over database results
+ <programlisting language="PHP (HTML)"><![CDATA[$dbo = JFactory::getDbo();
+$iterator = $dbo->getIterator($dbo->getQuery(true)->select('*')->from('#__content')->execute());
+foreach ($iterator as $row)
+{
+ // Deal with $row
+}]]></programlisting>
+ </para>
+ <para>It allows also to count the results.
+ <programlisting language="PHP (HTML)"><![CDATA[$count = count($iterator);]]></programlisting>
+ </para>
+ </section>
+</section>
+
View
29 libraries/joomla/database/driver.php
@@ -675,6 +675,33 @@ public function getQuery($new = false)
}
/**
+ * Get a new iterator on the current query.
+ *
+ * @param string $column An option column to use as the iterator key.
+ * @param string $class The class of object that is returned.
+ *
+ * @return JDatabaseIterator A new database iterator.
+ *
+ * @since 12.1
+ * @throws RuntimeException
+ */
+ public function getIterator($column = null, $class = 'stdClass')
+ {
+ // Derive the class name from the driver.
+ $iteratorClass = 'JDatabaseIterator' . ucfirst($this->name);
+
+ // Make sure we have an iterator class for this driver.
+ if (!class_exists($iteratorClass))
+ {
+ // If it doesn't exist we are at an impasse so throw an exception.
+ throw new RuntimeException(sprintf('class *%s* is not defined', $iteratorClass));
+ }
+
+ // Return a new iterator
+ return new $iteratorClass($this->execute(), $column, $class);
+ }
+
+ /**
* Retrieves field information about the given tables.
*
* @param string $table The name of the database table.
@@ -967,6 +994,7 @@ public function loadColumn($offset = 0)
*/
public function loadNextObject($class = 'stdClass')
{
+ JLog::add(__METHOD__ . '() is deprecated. Use JDatabase::getIterator() instead.', JLog::WARNING, 'deprecated');
$this->connect();
static $cursor = null;
@@ -1003,6 +1031,7 @@ public function loadNextObject($class = 'stdClass')
*/
public function loadNextRow()
{
+ JLog::add('JDatabase::loadNextRow() is deprecated. Use JDatabase::getIterator() instead.', JLog::WARNING, 'deprecated');
$this->connect();
static $cursor = null;
View
205 libraries/joomla/database/iterator.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * Joomla Platform Database Driver Class
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+abstract class JDatabaseIterator implements Countable, Iterator
+{
+ /**
+ * The database cursor.
+ *
+ * @var mixed
+ * @since 12.1
+ */
+ protected $cursor;
+
+ /**
+ * The class of object to create.
+ *
+ * @var string
+ * @since 12.1
+ */
+ protected $class;
+
+ /**
+ * The name of the column to use for the key of the database record.
+ *
+ * @var mixed
+ * @since 12.1
+ */
+ private $_column;
+
+ /**
+ * The current database record.
+ *
+ * @var mixed
+ * @since 12.1
+ */
+ private $_current;
+
+ /**
+ * A numeric or string key for the current database record.
+ *
+ * @var scalar
+ * @since 12.1
+ */
+ private $_key;
+
+ /**
+ * The number of fetched records.
+ *
+ * @var integer
+ * @since 12.1
+ */
+ private $_fetched = 0;
+
+ /**
+ * Database iterator constructor.
+ *
+ * @param mixed $cursor The database cursor.
+ * @param string $column An option column to use as the iterator key.
+ * @param string $class The class of object that is returned.
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($cursor, $column = null, $class = 'stdClass')
+ {
+ if (!class_exists($class))
+ {
+ throw new InvalidArgumentException(sprintf('new %s(*%s*, cursor)', get_class($this), gettype($class)));
+ }
+
+ $this->cursor = $cursor;
+ $this->class = $class;
+ $this->_column = $column;
+ $this->_fetched = 0;
+ $this->next();
+ }
+
+ /**
+ * Database iterator destructor.
+ *
+ * @since 12.1
+ */
+ public function __destruct()
+ {
+ if ($this->cursor)
+ {
+ $this->freeResult($this->cursor);
+ }
+ }
+
+ /**
+ * The current element in the iterator.
+ *
+ * @return object
+ *
+ * @see Iterator::current()
+ * @since 12.1
+ */
+ public function current()
+ {
+ return $this->_current;
+ }
+
+ /**
+ * The key of the current element in the iterator.
+ *
+ * @return scalar
+ *
+ * @see Iterator::key()
+ * @since 12.1
+ */
+ public function key()
+ {
+ return $this->_key;
+ }
+
+ /**
+ * Moves forward to the next result from the SQL query.
+ *
+ * @return void
+ *
+ * @see Iterator::next()
+ * @since 12.1
+ */
+ public function next()
+ {
+ // Set the default key as being the number of fetched object
+ $this->_key = $this->_fetched;
+
+ // Try to get an object
+ $this->_current = $this->fetchObject();
+
+ // If an object has been found
+ if ($this->_current)
+ {
+ // Set the key as being the indexed column (if it exists)
+ if (isset($this->_current->{$this->_column}))
+ {
+ $this->_key = $this->_current->{$this->_column};
+ }
+
+ // Update the number of fetched object
+ $this->_fetched++;
+ }
+ }
+
+ /**
+ * Rewinds the iterator.
+ *
+ * This iterator cannot be rewound.
+ *
+ * @return void
+ *
+ * @see Iterator::rewind()
+ * @since 12.1
+ */
+ public function rewind()
+ {
+ }
+
+ /**
+ * Checks if the current position of the iterator is valid.
+ *
+ * @return boolean
+ *
+ * @see Iterator::valid()
+ * @since 12.1
+ */
+ public function valid()
+ {
+ return (boolean) $this->_current;
+ }
+
+ /**
+ * Method to fetch a row from the result set cursor as an object.
+ *
+ * @return mixed Either the next row from the result set or false if there are no more rows.
+ *
+ * @since 12.1
+ */
+ abstract protected function fetchObject();
+
+ /**
+ * Method to free up the memory used for the result set.
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ abstract protected function freeResult();
+}
View
21 libraries/joomla/database/iterator/azure.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * SQL azure database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorAzure extends JDatabaseIteratorSqlsrv
+{
+}
View
58 libraries/joomla/database/iterator/mysql.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * MySQL database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @see http://dev.mysql.com/doc/
+ * @since 12.1
+ */
+class JDatabaseIteratorMysql extends JDatabaseIterator
+{
+ /**
+ * Get the number of rows in the result set for the executed SQL given by the cursor.
+ *
+ * @return integer The number of rows in the result set.
+ *
+ * @since 12.1
+ * @see Countable::count()
+ */
+ public function count()
+ {
+ return mysql_num_rows($this->cursor);
+ }
+
+ /**
+ * Method to fetch a row from the result set cursor as an object.
+ *
+ * @return mixed Either the next row from the result set or false if there are no more rows.
+ *
+ * @since 12.1
+ */
+ protected function fetchObject()
+ {
+ return mysql_fetch_object($this->cursor, $this->class);
+ }
+
+ /**
+ * Method to free up the memory used for the result set.
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ protected function freeResult()
+ {
+ mysql_free_result($this->cursor);
+ }
+}
View
57 libraries/joomla/database/iterator/mysqli.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * MySQLi database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorMysqli extends JDatabaseIterator
+{
+ /**
+ * Get the number of rows in the result set for the executed SQL given by the cursor.
+ *
+ * @return integer The number of rows in the result set.
+ *
+ * @since 12.1
+ * @see Countable::count()
+ */
+ public function count()
+ {
+ return mysqli_num_rows($this->cursor);
+ }
+
+ /**
+ * Method to fetch a row from the result set cursor as an object.
+ *
+ * @return mixed Either the next row from the result set or false if there are no more rows.
+ *
+ * @since 12.1
+ */
+ protected function fetchObject()
+ {
+ return mysqli_fetch_object($this->cursor, $this->class);
+ }
+
+ /**
+ * Method to free up the memory used for the result set.
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ protected function freeResult()
+ {
+ mysqli_free_result($this->cursor);
+ }
+}
View
21 libraries/joomla/database/iterator/oracle.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * Oracle database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorOracle extends JDatabaseIteratorPdo
+{
+}
View
74 libraries/joomla/database/iterator/pdo.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * PDO database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorPdo extends JDatabaseIterator
+{
+ /**
+ * Get the number of rows in the result set for the executed SQL given by the cursor.
+ *
+ * @return integer The number of rows in the result set.
+ *
+ * @since 12.1
+ * @see Countable::count()
+ */
+ public function count()
+ {
+ if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
+ {
+ return $this->cursor->rowCount();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Method to fetch a row from the result set cursor as an object.
+ *
+ * @return mixed Either the next row from the result set or false if there are no more rows.
+ *
+ * @since 12.1
+ */
+ protected function fetchObject()
+ {
+ if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
+ {
+ return $this->cursor->fetchObject($this->class);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Method to free up the memory used for the result set.
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ protected function freeResult()
+ {
+ if (!empty($this->cursor) && $this->cursor instanceof PDOStatement)
+ {
+ $this->cursor->closeCursor();
+ }
+ }
+}
View
21 libraries/joomla/database/iterator/sqlite.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * SQLite database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorSqlite extends JDatabaseIteratorPdo
+{
+}
View
57 libraries/joomla/database/iterator/sqlsrv.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @package Joomla.Platform
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+defined('JPATH_PLATFORM') or die;
+
+/**
+ * SQL server database iterator.
+ *
+ * @package Joomla.Platform
+ * @subpackage Database
+ * @since 12.1
+ */
+class JDatabaseIteratorSqlsrv extends JDatabaseIterator
+{
+ /**
+ * Get the number of rows in the result set for the executed SQL given by the cursor.
+ *
+ * @return integer The number of rows in the result set.
+ *
+ * @since 12.1
+ * @see Countable::count()
+ */
+ public function count()
+ {
+ return sqlsrv_num_rows($this->cursor);
+ }
+
+ /**
+ * Method to fetch a row from the result set cursor as an object.
+ *
+ * @return mixed Either the next row from the result set or false if there are no more rows.
+ *
+ * @since 12.1
+ */
+ protected function fetchObject()
+ {
+ return sqlsrv_fetch_object($this->cursor, $this->class);
+ }
+
+ /**
+ * Method to free up the memory used for the result set.
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ protected function freeResult()
+ {
+ sqlsrv_free_stmt($this->cursor);
+ }
+}
View
189 tests/suites/database/driver/mysql/iterator/JDatabaseIteratorMySQLTest.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * @package Joomla.UnitTest
+ * @subpackage Database
+ *
+ * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
+ * @license GNU General Public License version 2 or later; see LICENSE
+ */
+
+require_once JPATH_PLATFORM . '/joomla/log/log.php';
+require_once JPATH_PLATFORM . '/joomla/database/iterator.php';
+require_once JPATH_PLATFORM . '/joomla/database/iterator/mysql.php';
+require_once JPATH_PLATFORM . '/joomla/database/driver.php';
+require_once JPATH_PLATFORM . '/joomla/database/driver/mysql.php';
+require_once JPATH_PLATFORM . '/joomla/database/query.php';
+
+/**
+ * Test class for JDatabaseResults using MySQL engine.
+ *
+ * @package Joomla.UnitTest
+ * @subpackage Database
+ *
+ * @since 12.1
+ */
+class JDatabaseIteratorMySQLTest extends TestCaseDatabaseMysql
+{
+ /**
+ * Gets the data set to be loaded into the database during setup
+ *
+ * @return xml dataset
+ *
+ * @since 12.1
+ */
+ protected function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__DIR__) . '/stubs/database.xml');
+ }
+
+ /**
+ * Data provider for the testForEach method
+ *
+ * @return array
+ *
+ * @since 12.1
+ */
+ public function casesForEachData()
+ {
+ return array(
+ // Testing 'stdClass' type without specific index, offset or limit
+ array(
+ 'title',
+ '#__dbtest',
+ null,
+ 'stdClass',
+ 0,
+ 0,
+ array(
+ (object) array('title' => 'Testing'),
+ (object) array('title' => 'Testing2'),
+ (object) array('title' => 'Testing3'),
+ (object) array('title' => 'Testing4')
+ ),
+ null
+ ),
+
+ // Testing 'stdClass' type, limit=2 without specific index or offset
+ array(
+ 'title',
+ '#__dbtest',
+ null,
+ 'stdClass',
+ 2,
+ 0,
+ array(
+ (object) array('title' => 'Testing'),
+ (object) array('title' => 'Testing2')
+ ),
+ null
+ ),
+
+ // Testing 'stdClass' type, offset=2 without specific index or limit
+ array(
+ 'title',
+ '#__dbtest',
+ null,
+ 'stdClass',
+ 20,
+ 2,
+ array(
+ (object) array('title' => 'Testing3'),
+ (object) array('title' => 'Testing4')
+ ),
+ null
+ ),
+
+ // Testing 'stdClass' type, index='title' without specific offset or limit
+ array(
+ 'title, id',
+ '#__dbtest',
+ 'title',
+ 'stdClass',
+ 0,
+ 0,
+ array(
+ 'Testing' => (object) array('title' => 'Testing', 'id' => '1'),
+ 'Testing2' => (object) array('title' => 'Testing2', 'id' => '2'),
+ 'Testing3' => (object) array('title' => 'Testing3', 'id' => '3'),
+ 'Testing4' => (object) array('title' => 'Testing4', 'id' => '4')
+ ),
+ null,
+ ),
+
+ // Testing 'UnexistingClass' type, index='title' without specific offset or limit
+ array(
+ 'title',
+ '#__dbtest',
+ 'title',
+ 'UnexistingClass',
+ 0,
+ 0,
+ array(),
+ 'InvalidArgumentException',
+ ),
+ );
+ }
+
+ /**
+ * Test foreach control
+ *
+ * @param array $options Array of options
+ * @param string $select Fields to select
+ * @param string $from Table to search for
+ * @param array $expected Array of expected results
+ * @param boolean|string $exception Exception thrown
+ *
+ * @return void
+ *
+ * @dataProvider casesForEachData
+ *
+ * @since 12.1
+ */
+ public function testForEach($select, $from, $column, $class, $limit, $offset, $expected, $exception)
+ {
+ if ($exception)
+ {
+ $this->setExpectedException($exception);
+ }
+ self::$driver->setQuery(self::$driver->getQuery(true)->select($select)->from($from)->setLimit($limit, $offset));
+ $iterator = new JDatabaseIteratorMysql(self::$driver->execute(), $column, $class);
+
+ // Run the Iterator pattern
+ $this->assertThat(
+ iterator_to_array($iterator),
+ $this->equalTo($expected),
+ __LINE__
+ );
+ }
+
+ /**
+ * Test count
+ *
+ * @return void
+ *
+ * @since 12.1
+ */
+ public function testCount()
+ {
+ self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest'));
+ $this->assertThat(
+ count(new JDatabaseIteratorMysql(self::$driver->execute())),
+ $this->equalTo(4),
+ __LINE__
+ );
+
+ self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest')->setLimit(2));
+ $this->assertThat(
+ count(new JDatabaseIteratorMysql(self::$driver->execute())),
+ $this->equalTo(2),
+ __LINE__
+ );
+
+ self::$driver->setQuery(self::$driver->getQuery(true)->select('title')->from('#__dbtest')->setLimit(2,3));
+ $this->assertThat(
+ count(new JDatabaseIteratorMysql(self::$driver->execute())),
+ $this->equalTo(1),
+ __LINE__
+ );
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.