Key "productTitle" for array with keys "0, catTitle" does not exist in EagleShopBundle:global:product.html.twig - symfony

I'm trying to join two tables and print a value in twig template but I'm having this issue.
This is my Controller action.
/**
* #Route("products/display/{id}")
* #Template()
*/
public function displayAction($id) {
$em = $this->container->get('doctrine.orm.entity_manager');
$qb = $em->createQueryBuilder();
$qb->select('p, pc.catTitle')
->from('EagleShopBundle:Products', 'p')
->leftJoin('EagleShopBundle:ProductCategory', 'pc', \Doctrine\ORM\Query\Expr\Join::WITH, 'pc.id = p.category')
->where($qb->expr()->eq('p.id', '?5'))
->setParameter(5, $id);
$product = $qb->getQuery()->getOneOrNullResult();
return $this->render("EagleShopBundle:global:product.html.twig", array(
'product' => $product,
'image_path' => '/bundles/eagleshop/images/'
));
}
This is my twig file line related to the issue,
<h1>{{product.productTitle}}</h1>
I guess issue is related to this line
$qb->select('p, pc.catTitle')
This is the error I get,
Key "productTitle" for array with keys "0, catTitle" does not exist in
EagleShopBundle:global:product.html.twig

You could try next query:
$qb->select('p, partial pc.{id, catTitle}')
// if you need full productCategory object then write just 'p, pc'
->from('EagleShopBundle:Products', 'p')
->leftJoin('p.category', 'pc')
//productCategory is the field
//in product entity which has relation to product category entity,
//paste your field (not column!) name here
//if it is not productCategory
->where('p.id = :productId')
->setParameter('productId', $id);
P.S.
It is better to move queries to entity repositories :)
P.P.S.
Doctrine partial objects
UPD
Fixed query - with right field name

Related

Doctrine Query with Multiple Joins only populating Main Entity

So far I have tried the following but I keep only getting the main Entity information joined entities do not make it to the result:
Option 1(Using ResultSetMapping Builder):
$rsm = new ResultSetMappingBuilder(
$this->_em,
ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT
);
$rsm->addRootEntityFromClassMetadata(
'CountryApp\StoreBundle\Entity\Product', 'p'
);
$rsm->addJoinedEntityFromClassMetadata(
'CountryApp\StoreBundle\Entity\Category', 'c', 'p', 'category'
);
$rsm->addJoinedEntityFromClassMetadata(
'CountryApp\StoreBundle\Entity\CustomerProductPrice', 'cpp', 'p', 'customerPrices'
);
$result = $this->_em
->createNativeQuery(
'
SELECT
p.id,
p.code,
p.name,
p.cost,
p.rrp,
p.status,
p.notes,
p.out_of_stock_since,
p.available_in,
c.id,
c.name,
c.code,
cpp.id,
cpp.price
FROM product as p
JOIN category as c ON c.id = p.category_id AND p.status != "DELETED"
LEFT JOIN customer_product_price as cpp ON cpp.product_id = p.id AND cpp.customer_id = :customer
', $rsm
)
->setParameter('customer', $customerId)
->getResult(Query::HYDRATE_ARRAY)
;
Option 2:(using QueryBuild and FetchMode)
$qb = $this->createQueryBuilder('p');
$result = $qb
->select('p')
->addSelect('c')
->addSelect('cpp')
->join(
'CountryApp\StoreBundle\Entity\Category',
'c',
Join::WITH,
$qb->expr()
->eq('c', 'p.category')
)
->leftJoin(
'CountryApp\StoreBundle\Entity\CustomerProductPrice',
'cpp',
Join::WITH,
$qb->expr()
->andX(
$qb->expr()
->eq('p', 'cpp.product'),
$qb->expr()
->eq('cpp.customer', ':customer')
)
)
->setParameter('customer', $customerId)
->getQuery()
->setFetchMode(
'CountryApp\StoreBundle\Entity\Category', 'product', ClassMetadata::FETCH_EAGER
)
->setFetchMode(
'CountryApp\StoreBundle\Entity\CustomerProductPrice', 'product', ClassMetadata::FETCH_EAGER
)
->getResult(Query::HYDRATE_ARRAY)
;
Please advise your thoughts as to what could make this work. I want to obtain the following structure:
[
0 => [
Product[
..
]
Category[
..
]
CustomerProductPrice[
..
]
],
1 => [
Product[
..
]
Category[
..
]
CustomerProductPrice[
..
]
],
..
.
]
While using Doctrine you define your relationships inside of your entity.
You can read more here https://symfony.com/doc/current/doctrine/associations.html always read the documentation and best practices. I dunno if you are using Symfony or not, but this is a great example and more understandable than Doctrine docs.
/**
* #ORM\Entity()
*/
class Product
{
// ...
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
*/
private $category;
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
}
As you see here you define an entity that holds all associations and properties.
Normally association will be lazy loaded by default if you call $product->getCategory() you category will be lazy loaded. If you do not like lazy loading you can always eager fetch with
/**
* #ManyToOne(targetEntity="Category", cascade={"all"}, fetch="EAGER")
*/
And you will receive an array of products where each product will have a property named category and will contain Category entity inside it.
This is the main difference between CakePHP because in CakePHP you get all associations separately and in Symfony, you get a tree of associations.
And your queries seems too complex and in most cases, you do not have to modify queries like that at all. But be careful with lazy loads if you lazy load data on huge lists you will end up with poor performance.

Doctrine 2 (Symfony) Result set mapping with custom field is always null

I'm performing the following native query in Symfony 2 repository:
$sql = "SELECT f.id, f.title, 'hi' AS custom_field FROM my_feed f";
$em = $this->getEntityManager();
$rsm = new \Doctrine\ORM\Query\ResultSetMapping($em);
$rsm->addEntityResult('MedicalCoreBundle:Feed', 'f');
$rsm->addFieldResult('f', 'id', 'id');
$rsm->addFieldResult('f', 'title', 'title');
$rsm->addFieldResult('f', 'custom_field', 'custom_field');
$query = $em->createNativeQuery($sql, $rsm);
$result = $query->getResult();
I have created the non-mapped property custom_field and its getter and setter getCustomField and setCustomField in the Feed entity.
Mapped fields are hydrated properly but when i add the custom_field RSM i get the following error: Notice: Undefined index: custom_field [...] in symfony\..\AbstractHydrator.php.
Entity code
// non mapped field
private $custom_field;
public function getCustomField()
{
return $this->custom_field;
}
public function setCustomField($number)
{
$this->custom_field = (int) $number;
return $this;
}
What am i doing wrong here ?
You should map custom_field or use addScalarResult instead of addFieldResult
...
$rsm->addScalarResult('custom_field', 'custom_field');
...
result will look like
[
[0=>entity, 'custom_field'=>custom_field value],
[0=>entity, 'custom_field'=>custom_field value],
...
]
Relatvie to your error, you seem to have a F instead of f in custom_Field somewhere.

Key "catTitle" for array with keys "0" does not exist in EagleShopBundle:global:product.html.twig

I'm trying to join two tables and print a value in twig template but I'm having this issue.
This is my Controller action.
/**
* #Route("products/display/{id}")
* #Template()
*/
public function displayAction($id) {
$em = $this->container->get('doctrine.orm.entity_manager');
$qb = $em->createQueryBuilder();
$qb->select('p', 'pc.catTitle')
->from('EagleShopBundle:Products', 'p')
->leftJoin('EagleShopBundle:ProductCategory', 'pc', \Doctrine\ORM\Query\Expr\Join::WITH, 'pc.id = p.category')
->where($qb->expr()->eq('p.id', '?5'))
->setParameter(5, $id);
$product = $qb->getQuery()->getResult();
return $this->render("EagleShopBundle:global:product.html.twig", array(
'product' => $product,
'image_path' => '/bundles/eagleshop/images/'
));
}
This is my twig file line related to the issue,
<small class="pr_type">{{product.catTitle}}</small>
But instead of printing 'catTitle' I'm having this issue,
Key "catTitle" for array with keys "0" does not exist in
EagleShopBundle:global:product.html.twig
It is simple: getResult() returns an array of objects, even if there is only one. If you are expecting that this query would return only one object use getOneOrNullResult(). But after that and before you are displaying results you need to check if smth is returned (for example: product instanceof Products) or null is returned.

Symfony2 simple query: can't fetch an object, only array

The following query in Symfony2.6 works with getArrayResult(); BUT doesn't work with getResult(); or getOneOrNullResult();. This means that I can't fetch an object but only an array.
If I use this query, all I get is a white/blank page (not even the symfony debug toolbar). Note that in my twig template I just do a {{ dump() }} of the query result.
The table structure is easy (it's a list of books read by the users):
id, user, book, status, vote, review
(user, book and status are foreign keys)
public function selectOneRecordBy2Ids($user_id, $book_id)
{
/* #var $qb QueryBuilder */
$qb = $this->createQueryBuilder('l');
$qb->select('l');
$qb = $qb->Where($qb->expr()->eq('l.user', ':first'));
$qb = $qb->andWhere($qb->expr()->eq('l.book', ':second'));
$qb = $qb->setParameters(array('first' => $user_id, 'second' => $book_id));
return $qb->getQuery()->getOneOrNullResult();
}
I've noticed a few bad practices here, so let me correct them:
public function selectOneRecordBy2Ids(User $user, Book $book)
{
/* #var $qb QueryBuilder */
$qb = $this->createQueryBuilder('l');
$qb
->andWhere($qb->expr()->eq('l.user', ':first'))
->andWhere($qb->expr()->eq('l.book', ':second'))
->setParameters(array('first' => $user, 'second' => $book));
return $qb->getQuery()->getResult();
}
Select is not necessary if you work only with one entity and you don't fetch any relations. QB returns $this so you can chain the method calls.
Try to use entities as parameters instead of primitive types (if it is possible). If not, then you have to use primitive types as primitives in QB. In this case you'll need a few joins:
->select('l')
->join('l.user', 'u')
->join('l.book', 'b')
->andWhere($qb->expr()->eq('u.id', ':first'))
->andWhere($qb->expr()->eq('b.id', ':second'))
->setParameters(array('first' => $user_id, 'second' => $book_id));
If you want to fetch only one record, then you may have to limit the results by setting the max results:
->setMaxResults(1)
I hope this helps and solves your original problem as well.
getOneOrNullResult() does not return the record, but tells you if any record in database is found, or not.
You might want to use getSingleResult()

Doctrine - Get row or rows from many results based on column value

I am using doctrine with a one to many relationship where each user entity has many post entities. So I have a doctrine query like so
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT u, p FROM MYUserBundle:User u
JOIN u.post p'
);
I can then get the users posts like so
foreach($query->getResult() as $user){
//a bunch of posts related to this user
$posts = $user->getPosts();
}
For convenience I would like to create an API that will allow me to get a specific post or posts out of this $posts object based on a column value without using more queries. So for example I have a column named post_slug, so I would like to be able to say
$posts = $user->getPosts();
$post = $posts->findBySlug('my_slug');
//or something along those lines...
Is this something that can be done with the $posts object or Post entity class?
Doctrine's collections are filterable. So, assuming your Post entities are stored on User::$posts, do this in your user entity.
public function getPostsBySlug( $slug )
{
return $this->posts->filter( function( Post $post ) use ( $slug )
{
return $post->getSlug() == $slug;
} );
}
Then you can just do
$posts = $user->getPostsBySlug( 'my_slug' );
What about doing
$slug = 'my_slug';
array_filter($user->getPosts()->all(), function ($post) use ($slug) {
return $post->getSlug() == $slug;
})
You can move this kind of functionality to a Repository class (extending EntityRepository).
For example:
namespace Acme\ThingBundle\Repository;
use Doctrine\ORM\EntityRepository;
class PostRepository extends EntityRepository
{
public function getBySlug($slug)
{
/// your custom query here
return $q->getQuery()->getResult();
}
}

Resources