How to get object by "id" from propel object collection?
Asked Answered
E

5

9

I'm using Propel 1.6 and I'm not sure how to get an object (given its "id" attribute value) from a propel object collection. I could not find a straight answer in Propel's documentation (PropelCollection methods do not seem applicable?). For example: Lets say I have a "Person" table with the following schema:

<table name="person">
  <column name="id" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
  <column name="name" type="VARCHAR" size="100" required="true"/>
</table>

I do the following query to get a collection of "Person" objects:

$persons = PersonQuery::create()->find();

Then, I want to find a "Person" object with a given "id" (e.g. "Person" with "id=3"), without making a new query to the database. How can I do it?

$persons->get(...?)?

In other words, I DO NOT want to do:

$personX = PersonQuery::create()->findOneById(3);

Context:

I would like to prevent making a database query to improve performance. The statement is to be inserted inside a foreach statement that would otherwise lead to numerous database connections, like the following:

foreach ($books as $book) {
    $book['author_name'] = PersonQuery::create()->findOneById($book['author_id'])->getName();
}
Erme answered 3/9, 2012 at 16:30 Comment(0)
L
4

Well, that won't be very efficient, but you can go through the collection to find it.

$persons = PersonQuery::create()->find();
foreach ($persons as $person)
{
  if (3 == $person->getId())
  {
    break;
  }
}

// now you have your person with id = 3
var_dump($person->getId());
Lonnalonnard answered 3/9, 2012 at 16:34 Comment(3)
You can do it in a more elegant way with array_filter() :-)Disputation
@j0k: I was trying to avoid a foreach loop, but I guess, as you suggest, I cannot avoid it. I think going with the loop would still be more efficient than making multiple database connections. Thanks for your answer!Erme
@Florent: I'm not sure how to implement the array_filter function in this case, but I'll investigate... thanks!Erme
I
9

Another alternative, especially if you need to search several times is to get array of objects by id with $collection->getArrayCopy('Id').

$persons = PersonQuery::create()->find();
$personsById = $persons->getArrayCopy('Id');

Then you can do

$person = $personsById[3];

or

if (isset($personsById[3])) {
  $person = $personsById[3];
  ...
}
Idou answered 25/7, 2014 at 20:4 Comment(0)
L
4

Well, that won't be very efficient, but you can go through the collection to find it.

$persons = PersonQuery::create()->find();
foreach ($persons as $person)
{
  if (3 == $person->getId())
  {
    break;
  }
}

// now you have your person with id = 3
var_dump($person->getId());
Lonnalonnard answered 3/9, 2012 at 16:34 Comment(3)
You can do it in a more elegant way with array_filter() :-)Disputation
@j0k: I was trying to avoid a foreach loop, but I guess, as you suggest, I cannot avoid it. I think going with the loop would still be more efficient than making multiple database connections. Thanks for your answer!Erme
@Florent: I'm not sure how to implement the array_filter function in this case, but I'll investigate... thanks!Erme
D
3

Since Propel don't cache properly query result, you need to iterate the collection (as @j0k said). Instead of using a foreach loop, you can call array_filter passing a closure (with PHP 5.3).

// Request the persons
$persons = PersonQuery::create()->find();

// Filter the persons whose ID equals 3
$filteredPersons = array_filter($persons, function ($person) {
    return 3 === $person->getId();
});

// Get the first result
$person = empty($filteredPersons) ? null : $filteredPersons[0];

If you are sure that the person will be found, you also can write (with PHP 5.4) the following lines:

// Filter the person whose ID equals 3
$person = array_filter($persons, function ($person) {
    return 3 === $person->getId();
})[0];
Disputation answered 4/9, 2012 at 8:12 Comment(2)
thanks for sharing an alternative solution using array_filter! Would this solution be better from a performance stand point, as compared to using a foreach loop? If so, could you share the intuition behind?Erme
With PHP 5.4, foreach is 3x faster than array_filter(). Moreover using foreach you can break when your entry is found. But in my opinion array_filter() is more aesthetic.Disputation
R
2

if you set Propel::isInstancePoolingEnabled() is true(it's true by default),then you can

// Request the persons
$persons = PersonQuery::create()->find();
// get person from pool
$person = PersonPeer::getInstanceFromPool(3);

sorry about my english.

Retrograde answered 26/8, 2013 at 9:41 Comment(0)
C
1

The alternative with Propel >=1.5 to user2663223's answer would be:

$persons = PersonQuery::create()->find()

$person = PersonQuery::create()->findPk(3);

This takes advantage of the instance pool. Internally it uses: getInstanceFromPool, if the sql query was done before.

For more info, consult:

http://propelorm.org/documentation/03-basic-crud.html#propel-instance-pool

Clypeate answered 11/7, 2014 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.