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