How to fetch results one by one in Doctrine 1.2? - php

How can I make something similar to classic PHP PDO
while ($obj = $stmt->fetch()) {...}
in Doctrine 1.2.
I've tried
while ($obj = $query->fetchOne()) {...}
but it returns always only the first object found.
Is there any way I could implement this behaviour?
Doesn't really matter my query. It's a plain simple one (note that I am in the *Table class of the model)
$query = $this->createQuery('a');

While working on a migration command in symfony2 I discovered that $query->executes(); fetches the complete result set into RAM before returning it.
This is not a problem with a small amount of data, but with bigger results your process might run OutOfMemory.
To solve the problem you can iterate through the results "one by one" with this statement:
$query->iterate();
I thing its similare to this PDO statement: while ($obj = $stmt->fetch()) {...}
A more complete example might look like this:
$em = $this->getContainer()->get('doctrine');
$iterator = $em->getRepository('AcmeBundle:Entity')
->createQueryBuilder('e')
->getQuery()->iterate();
foreach($iterator as $item){
$item = $item[0];
// Your logic here:
$item->getId();
....
}
Found this in the doctrine documentation.

Have you tried:
while ($obj = $query->execute()) {...}
And if you want to fetch an array instead of objects:
while ($obj = $query->execute(array(), Doctrine_Core::HYDRATE_ARRAY)) {...}

If you got the connection, do it like this:
$stmt = $conn->query($queryString);
while ($obj = $stmt->fetch()) {...}
With fetchOne() you will only get one entry at all.

Use the hydrate mode Doctrine_Core::HYDRATE_ON_DEMAND
$q = Doctrine_Query::create()
->select('...')
->from('...');
// Returns instance of Doctrine_Collection_OnDemand
$result = $q->execute(array(), Doctrine_Core::HYDRATE_ON_DEMAND);
foreach ($result as $obj)
{
// do something with your object
}
More information : Data Hydrators — Doctrine 1.2.4 documentation

Related

How to use ParseObject update field?

How to use Extend to update the field?
Example SQL: UPDATE Empresa SET categorias = 'cat_01' WHERE id_user = 'dlkj83d'
$query = new ParseQuery('Empresa');
$query->equalTo("users", Session::get('user'));
$query->add("categorias", 'cat_01'); <- ERROR
$query->save();
Test
$query = new ParseQuery('Empresa');
$query->equalTo("users", Session::get('user'));
$empresa = new ParseObject($query);
$empresa->add('categorias', array('cat_01'));
$empresa->save();
Does not work.
:(
There is no such ParseQuery::add() function. You are trying to cobble an UPDATE into a SELECT... you have to first find() the resulting ParseObjects and iterate through each one:
$query = new ParseQuery('Empresa');
$query->equalTo('users', Session::get('user'));
$results = $query->find(); // Returns an array of ParseObjects
foreach ($results as $res) {
$res->add('categorias', 'cat_01');
$res->save(); // Make sure you write Exception handling for this in the future
}
There is also a ParseObject::set and setArray function that will achieve the same thing, as add may be getting deprecated.
Perfect.
$query = new ParseQuery('Restaurante');
$query->equalTo("users", Session::get('user'));
$results = $query->first();
$results->add('categorias', array('cat_02'));
$results->save();
I still have some difficulties regarding the method NoSQL. Knowing that the reasoning is different.
Thank you for your attention.
You are part of the development team?

This result is a forward only result set, calling rewind() after moving forward is not supported - Zend

In Zend app, I use Zend\Db\TableGateway and Zend\Db\Sql to retrieve data data from MySQL database as below.
Model -
public function getCandidateEduQualifications($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(function (Sql\Select $select) use ($id)
{
$select->where
->AND->NEST->equalTo('candidate_id', $id)
->AND->equalTo('qualification_category', 'Educational');
});
return $rowset;
}
View -
I just iterate $rowset and echo in view. But it gives error when try to echo two or more times. Single iteration works.
This result is a forward only result set, calling rewind() after
moving forward is not supported
I can solve it by loading it to another array in view. But is it the best way ? Is there any other way to handle this ?
$records = array();
foreach ($edu_qualifications as $result) {
$records[] = $result;
}
EDIT -
$resultSet->buffer(); solved the problem.
You receive this Exception because this is expected behavior. Zend uses PDO to obtain its Zend\Db\ResultSet\Resultset which is returned by Zend\Db\TableGateway\TableGateway. PDO result sets use a forward-only cursor by default, meaning you can only loop through the set once.
For more information about cursors check Wikipedia and this article.
As the Zend\Db\ResultSet\Resultset implements the PHP Iterator you can extract an array of the set using the Zend\Db\ResultSet\Resultset:toArray() method or using the iterator_to_array() function. Do be careful though about using this function on potentially large datasets! One of the best things about cursors is precisely that they avoid bringing in everything in one go, in case the data set is too large, so there are times when you won't want to put it all into an array at once.
Sure, It looks like when we use Mysql and want to iterate $resultSet, this error will happen, b/c Mysqli only does
forward-moving result sets (Refer to this post: ZF2 DB Result position forwarded?)
I came across this problem too. But when add following line, it solved:
$resultSet->buffer();
but in this mentioned post, it suggest use following line. I just wonder why, and what's difference of them:
$resultSet->getDataSource()->buffer();
This worked for me.
public function fetchAll()
{
$select = $this->tableGateway->getSql()->select();
$resultSet = $this->tableGateway->selectWith($select);
$resultSet->buffer();
$resultSet->next();
return $resultSet;
}
$sql = new Zend\Db\Sql($your_adapter);
$select = $sql->select('your_table_name');
$statement = $sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
$resultSet = new ResultSet();
$resultSet->initialize($results);
$result = $resultSet->toArray();

symfony2 doctrine fetch while without creating complete array of results

I am looking to export to a csv file using doctrine. However the data is likely to be quite large. Therefore I dont want to ouput to the results to a complete array. I want to traverse the results iteratively.
I have tried looking here
doctrine docs
The PHP looks something like this
$result = mysql_query("SELECT * FROM bigtable");
while($row = mysql_fetch_assoc($result)) {
// do code iteratively here
}
Not sure how you do the same thing in doctrine for symfony2
This is from the doctrine documentation about batch processing:
$q = $this->_em->createQuery('select u from MyProject\Model\User u');
$iterableResult = $q->iterate();
foreach ($iterableResult AS $row) {
// do stuff with the data in the row, $row[0] is always the object
// detach from Doctrine, so that it can be Garbage-Collected immediately
$this->_em->detach($row[0]);
}
'select u ....is the equivalent to your SELECT * ...
$result = mysql_query("SELECT * FROM bigtable");
while($row = mysql_fetch_assoc($result)) {
// do code iteratively here
}
is Flat PHP and symfony2/doctrine is designed to avoid it. http://symfony.com/doc/2.0/book/from_flat_php_to_symfony2.html
kudos to Dirk his answer is correct. If you want to iterat eover entity models then thats the way to go. Sometimes you may not have a model mapped setup for the sql results you are returning. If you want to do it over a raw sql file then this is how I did it. I would be interested to hear more thoughts.
You pass the doctrine connection into the class via your controller
Controller
function indexAction(){
$className = new ClassName($this->getDoctrine()->getEntityManager());
}
You can then create raw sql lookup
Entity
function __construct($entity){
$this->connection = $entity->getConnection();
}
function saveToCSV
{
$stmt = $this->connection->prepare("SELECT * FROM bitTableExample ");
$stmt->execute();
while($row = $stmt->fetch()){
// append to csv file
}
}

Quicker way of doing this

I'm using PDO to get an array of relations from my DB.
$dbRelaties = $dbh->query("SELECT pkRelatieId,naam,email FROM relaties");
in another function i need to acces one specific row in this array. I've managed to do it like this:
$klant = array();
foreach($dbRelaties as $dbRelatie)
{
if($dbRelatie["pkRelatieId"] == $relatie){ $klant = $dbRelatie; break; }
}
sendMail("Subject",$klant);
The above code works. But i'me looking for a neater solution and a quicker one, the above code is called in a function and that function is called inside a loop. So everytime it executes is has to loop through $dbRelaties to get the correct relation.
Can anyone set me in the right direction?
assuming the pk means primary key, then
while($row = mysql_fetch_assoc($result)) {
$dbRelatie[$row['pkRelatieID']] = $row;
}
would produce an array keyed with your primary key field, so
$dbRelatie[$pk]['naam']
will give you that particular pk's naam value.
To show a PDO specific version of Marc B's answer.
Assuming a query was executed through PDO like so:
$sql = "SELECT pkRelatieId,naam,email FROM relaties";
$resultSet = $pdo->query($sql);
The results can be read into a PHP array using PDO's fetch method.
$dbRelaties = array();
while ($row = $resultSet->fetch(PDO::FETCH_ASSOC)) {
$dbRelaties[$row['pkRelatieID']] = $row;
}
This can then be used to access values based on the PK of the row.
sendMail("Subject", $dbRelaties[$relatie]['naam']);
Furthermore. PDO lets you assign a default fetch mode to each PDO instance, and the PDOStatement class is Traversable, so that you don't actually have to call the fetch() method in a while loop to go through a result set.
If you were to do this to a PDO object before a query: (Ideally only once right after creating the object.)
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
Then you can use a foreach loop on the result set to get row arrays with field names, instead of using a while loop.
$dbRelaties = array();
foreach ($stmt as $row) {
$dbRelaties[$row['pkRelatieID']] = $row;
}

PHP mySQL - Can you return an associated array with a number index?

I have this method in my db class
public function query($queryString)
{
if (!$this->_connected) $this->_connectToDb(); //connect to database
$results = mysql_query($queryString, $this->_dbLink) or trigger_error(mysql_error());
return mysql_num_rows($results) > 0 ? mysql_fetch_assoc($results) : false;
}
This works great for queries that return 1 row, but how can I get an array returned something like this?
$array[0]['name'] = 'jim'
$array[0]['id'] = 120
$array[1]['name'] = 'judith'
$array[1]['ID'] = 121
Now I know I could use a while loop to insert this data into the array like so, but I was wondering if PHP could do this with an internal function? I havn't been able to find on the docs what I'm after.
The reason I don't want to run the while within the method is because I am going to reiterate back over the array when it's returned, and I'd rather not run through the results twice (for performance reasons).
Is there a way to do this? Do I have a problem with my general query method design?
Thank you muchly!
public function query($queryString)
{
if (!$this->_connected) $this->_connectToDb(); //connect to database
$results = mysql_query($queryString, $this->_dbLink) or trigger_error(mysql_error());
$data = array();
while($row = mysql_fetch_assoc($results))
{
$data[] = $row;
}
return $data;
}
this will always return an array.
EDIT:
I didn't read the question well.
If you realy don't want to use the loop then I would do this:
public function query($queryString)
{
if (!$this->_connected) $this->_connectToDb(); //connect to database
return mysql_query($queryString, $this->_dbLink) or trigger_error(mysql_error());
}
then loop over it, however I would just use the loop.
You might also want to look at the PDO extension. You can load the entire result set into an array or you can loop using foreach.
<?php
$db = new PDO($connection_string, $username, $password);
$result = $db->query($queryString);
foreach($result as $row) {
// do something
}
// or
$result = $db->query($queryString);
$result_array = $result->fetchAll(PDO::FETCH_ASSOC);
?>
Most people use a while() loop in the query to do exactly what you want and then loop over the array to process it.
However, you're right: it wastes memory, which could be a problem with a large dataset. An alternative is for your query method to return the resultset resource. Then your while loop can use that to fetch each row as it requires it.
To abstract that away, I would suggest another class to do that for you. Then your query call would return a new instance of that class which has the MySQL resultset resource as an instance variable and packages up the mysql_fetch_assoc() call.
Look at PEAR::MDB2 (Quickstart Cheatsheet). It provides lots of different functions for doing something like this. It also does not tie you down into using MySQL specific functions because it is a database abstraction layer.
$result = $db->queryRow($query, MDB2_FETCHMODE_ASSOC);
There are other abstraction layers such as ADO as well.
thanks for the ideas. I have a function that returns an associative array from the sql (used in Moodle).
$results = get_records_sql($sql);
//to create a numerically indexed array:
$data = array();
foreach ($results as $row)
{
$data[] = $row;
}
return $data;
}

Categories