如何在实体symfony中显示最后一个数组?

I don't know if this is possible in symfony, that is getting the last array when using respository. In my controller a have this function

/**
 * @param $id
 * @return Food
 */
public function getFood($id)
{

    $em = $this->getDoctrine()->getManager();
    $food = $em->getRepository("AppBundle:Food")->findById($id);
    if (!$food) {
        throw $this->createNotFoundException("Invalid Food");
    }

    return $food;
}

this will show the single food that I need. In my repository I have this code

/**
     * Display Food and get the last transaction
     * @param $id
     */
    public function findById($id){

        $query =  $this->createQueryBuilder(f)
            ->where('f.id = :id')
            ->setParameter('id', $id)
            ->getQuery()
            ->getResult()[0];

        return $query;
    }

This code successfully displaying the data of food Foods

 - id
 - name
 - price
 - packages
     - id
     - name_package
     - category
 - User
     - id
     - username
     - password
     - email
- transaction []
    1 - {
         - id
         - date
         - emailStatus
         - email
     }
    2 - {
         - id
         - date
         - emailStatus
         - email
     }
    3 - {
         - id
         - date
         - emailStatus
         - email
     }

How can I get the last transaction of food? I just want to display the last part of transaction that is like this one.

update

     - id
     - name
     - price
     - packages
         - id
         - name_package
         - category
     - User
         - id
         - username
         - password
         - email
    - transaction []
         3 - {
             - id
             - date
             - emailStatus
             - email
         }

Thanks everyone here. I have an idea now how to solve. What I did is just a simple way. In my Food entity class, I add this method

/**
     * @return Transactions
     */
    public function getLastTransactions()
    {
        $this->transactions = $this->getTransactions()->last();

        return $this->transactions;
    }

and then in my Food controller

 /**
     * @param $id
     * @return Food
     */
    public function getFood($id)
    {

        $em = $this->getDoctrine()->getManager();
        $food = $em->getRepository("AppBundle:Food")->find($id);
        $food->getLastTransactions();


        return $food;
    }

I can now control the transaction and then you can see the full info of my food entity.

You could slice your transaction array and retrieve a new one with only the last item in it. Then you can reset the indices for the array and fetch the only item with the index 0.

$transaction = array_values(array_slice($food, -1))[0];

I assume that transation field (containing transactions) in Food is an ArrayCollection

If so, there's a method last() which returns last element from the collection.

So you can do something like this, if you have getter for transactions:

$food->getTransaction()->last();

Also you can add method to Food class

/**
 * @return Transaction|null
 */
public function getLastTransaction()
{
    $transactions = $this->getTransaction();

    return !empty($transactions) ? end($transactions) : null;
}

There are several ways to get what you need.

First, update your findById() method. Since you look for Id, I assume you'd like to get only one record, right ?

/**
     * Display Food and get the last transaction
     * @param $id
     * @return Food|null
     */

public function findById($id){

  $query =  $this->createQueryBuilder('f')
            ->where('f.id = :id')
            ->setParameter('id', $id)
            ->getQuery()
            ->getOneOrNullResult();     
            // returns single Object instead of an array of Objects 

  return $query;
}

then navigate to your Food entity an extend your relation to transaction => add fetch="EXTRA_LAZY" This is a important Part for later "filtering"

/**
* @ORM\OneToMany(targetEntity="...", mappedBy="...", fetch="EXTRA_LAZY")
*/
private $transaction;

then stay in your Food entity add additional method(s) for transaction depending on your current usecase(s).

for example:

that would be your regular transactions getter which gives you all transaction for current Food as ArrayCollection

public function getTransaction()
{
  return $this->transaction;
}

so the easy way would be to use first()/last() methods

like

public function getOnlyLastTransaction()
{
  return $this->transaction->last();
}

now you have two (or even more) separate method(s) for a different task(s)

but... first() and last() are handy wrappers for php's native reset() and end() functions, so if your Food have say 100 transaction, doctine will fetch all from DB and hydrate to Transaction entity just only to get first. Not the best way.

at this point you can make use of Doctrine's Criteria

so now you can update your getOnlyLastTransaction() method with following

/**
 * @return ArrayCollection
 */
public function getOnlyLastTransaction ()
{
    // here you filter your transactions at SQL level
    // so you could sa, get all transaction of current food ordered by ID in desc order and get only ONE of them by LIMIT 1
    $criteria = Criteria::create();
    $criteria->orderBy( [ 'id' => Criteria::DESC ] ); // id of transaction Entity
    // $criteria->orderBy(['date' => Criteria::DESC ]); // to get last by date
    $criteria->setMaxResults( 1 ); // LIMIT 1

    return $this->transaction->matching( $criteria );
}

the best part of it -> you get still ArrayCollection back so all methods like first(), last() and isEmpty() are still available, the only difference is you have a collection of one

so my fav is to extend method with param $as_object like

public function getOnlyLastTransaction ( $as_object = TRUE )
{
    // here you filter your transactions at SQL level
    // so you could sa, get all transaction of current food ordered by ID in desc order and get only ONE of them by LIMIT 1
    $criteria = Criteria::create();
    $criteria->orderBy( [ 'id' => Criteria::DESC ] ); // id of transaction Entity
    // $criteria->orderBy(['date' => Criteria::DESC ]); // to get last by date
    $criteria->setMaxResults( 1 ); // LIMIT 1
    $found = $this->transaction->matching( $criteria );
    return ($as_object ? $found->first() : $found);
}

Now you have full controll and only one transaction in a separate method, so if you still want all of then, you can use your regular getter

usage: in your controller

/** * @param $id * @return Food */ public function getFood($id) {

$em = $this->getDoctrine()->getManager();
$food = $em->getRepository("AppBundle:Food")->findById($id);
if (fasle === $food instanceof Food ) {
    throw $this->createNotFoundException("Invalid Food");
}
$lastTrans = $food->getOnlyLastTransaction();
dump($lastTrans);


return $food;

}

GOTCHAS

last() and first() could lead to a confusing if someone changed default sorting of your relation via @ORM\OrderBy({...}) For Example. If your relation looks like this

/**
 * @ORM\OneToMany(targetEntity="...", mappedBy="...", fetch="EXTRA_LAZY")
 * @ORM\OrderBy({"date"="DESC"})
 */
private $transaction;

So now when you call

$food->getTransaction()->last() and awaiting the last record, you get the last entry of colllection which in this case actualy the first record from DB