Example Usage of ObjectManagerAware inside entity - symfony

I would like to use entity manager inside entity and no idea for usage.
use Doctrine\Common\Persistence\ObjectManagerAware;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use SomeBundle\Entity\Boarding;
use SomeBundle\Entity\User;
class Entity extends ApiUserEntity implements ObjectManagerAware
{
private $em;
public function ___construct(User $user)
{
$this->board = $this->getData(123);
}
public function injectObjectManager(ObjectManager $objectManager, ClassMetadata $classMetadata)
{
$this->em = $objectManager;
}
private function getData($leadId)
{
//return gettype($this->em); //return null
$repository =$this->em->getRepository(Boarding::class);
$query = $repository->createQueryBuilder('b')
->where('b.lead = :lead')
->setParameter('lead', $leadId)
->getQuery();
$boards = $query->getResult();
return $boards;
}
}
Using this code get me error
Call to a member function getRepository() on null"
The entity manager is null also
//return gettype($this->em); //return null
Any idea for example usage?

You can try to create a repository like here. Just add
* #ORM\Entity(repositoryClass="App\Repository\EntityRepository")
or to YAML, Xml depends on your configuration and then create the repository file. Like this one:
// src/AppBundle/Repository/ProductRepository.php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
class ProductRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AppBundle:Product p ORDER BY p.name ASC'
)
->getResult();
}
}

Related

How can I decorate repository class in Symfony 3.4?

I have a task to cache doctrine result with custom keys using redis. Here is repository class:
<?php
namespace AppBundle\Repository;
class JobRepository extends EntityRepository implements JobRepositoryInterface
{
/**
* #return Job[]
*/
public function getActiveWithCategory()
{
$qb = $this->createQueryBuilder('j');
return $qb
->addSelect('c')
->leftJoin('j.category', 'c')
->addCriteria(JobCriteria::active())
->getQuery()
->getResult();
}
}
Interface:
<?php
namespace AppBundle\Repository;
interface JobRepositoryInterface
{
/**
* #return Job[]
*/
public function getActiveWithCategory();
}
Is it possible to create Decorator for this repository and say somehow to doctrine to return needed implementation?
Or I have to create service JobRepositoryService which implements interface. Here I call repository methods. And then create another JobCachedRepositoryService which is decorator for JobRepositoryService. And don't use $this->getDoctrine()->getRepository('Job') in whole project.
Is it right solution? How would you resolve this problem?
Thanks in advance
If you need to cache doctrine's result with redis custom key, you can to it like that:
<?php
namespace AppBundle\Repository;
class JobRepository extends EntityRepository implements JobRepositoryInterface
{
/**
* #return Job[]
*/
public function getActiveWithCategory()
{
$qb = $this->createQueryBuilder('j');
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cacheDriver = new Doctrine\Common\Cache\RedisCache();
$cacheDriver->setRedis($redis);
$cacheDriver->setNamespace('some_namespace_');
$query->setResultCacheDriver($cacheDriver);
$query->useResultCache(true, 3600, 'result_key_in_redis');
$query = $qb->addSelect('c')
->leftJoin('j.category', 'c')
->addCriteria(JobCriteria::active())
->getQuery();
return $query->getResult();
}
}
You can install redis lib via pecl.

Symfony Undefined index

I am creating an application that fetches and search for product name from different sources (DB, XML, JSON, ...)(for this code Im testing only with the DB), my idea was to create an interface for that.
I created the interface ProductRepositoryInterface and the class DoctrineProductRepository then I declared them both as services.
In my controller, I call the search function with the product name as param.
Here is my interface ProductRepositoryInterface :
namespace Tyre\TyreBundle\Repository;
interface ProductRepositoryInterface
{
function search(string $needle);
}
My interface DoctrineProductRepository:
namespace Tyre\TyreBundle\Repository;
class DoctrineProductRepository implements ProductRepositoryInterface
{
public function __constructor(EntityManager $em)
{
$this->em = $em;
}
public function search(string $needle)
{
$repository = $this->em->getRepository('TyreTyreBundle:Products');
$query = $repository->createQueryBuilder('u')
->where("u.name LIKE '%".$needle."%' or u.manufacturer LIKE '%".$needle."%'")
->getQuery();
return $query->getArrayResult();
}
}
My Service.yml
services:
Tyre\TyreBundle\Repository\DoctrineProductRepository:
class: Tyre\TyreBundle\Repository\DoctrineProductRepository
Tyre\TyreBundle\Repository\ProductRepositoryInterface:
class: Tyre\TyreBundle\Repository\ProductRepositoryInterface
and finally my controller :
namespace Tyre\TyreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Tyre\TyreBundle\Repository\DoctrineProductRepository;
use Tyre\TyreBundle\Repository\ProductRepositoryInterface;
class DefaultController extends Controller
{
public function indexAction()
{
return $this->render('TyreTyreBundle:Default:search.html.twig');
}
public function searchAction(Request $request) {
$repositoryMap = [
'db' => DoctrineProductRepository::class,
];
$serviceName = $repositoryMap[$request->get('db')]; /***This is Line 56 ***/
/** #var ProductRepositoryInterface */
$repository = $this->get($serviceName);
$results = $repository->search($request->get('search_for'));
return $this->render('TyreTyreBundle:Default:detail.html.twig', array('results' => $results));
}
public function detailAction()
{
//forward the user to the search page when he tries to access directly to the detail page
return $this->render('TyreTyreBundle:Default:search.html.twig');
}
}
But I get an error :
EDIT
When I try http://localhost:8000/search?db=db , I get other error (I var_dumped $repositoryMap) :
click to view
Am I missing anything?
The reason for your 'ContextErrorException' is :
$request->get('search_for')
is empty because you are passing nothing in the url for that key. Pass 'search_for' also in addition with 'db' like:
http://localhost:8000/search?db=db&search_for=myvalue

Can I create a more global instance of EntityManager in order to keep my code DRY?

From the examples I'm finding in the Symfony docs, it looks like the typical thing to do when needing to save data is something like in the controller class:
public function createAction(){
$product = new Product();
$product->setName('Amy Keyboard');
$product->setPrice(24.99);
$product->setDescription('Ergonomic and stylish!');
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('index.html.twig');
}
It would be really great to not have to type those 3 $em lines in every single controller method! And it would be even sweeter to move all of this logic to a class somewhere else and then just call $product->saveProduct($data)! What is the best option here?
I usually create a manager class e.g. ProductManager and register it as service. I inject the EntityManager via setter injection and implement all the methods I need.
In your case this would look similar to this:
AppBundle/Product/ProductManager
namespace AppBundle\Product;
use Doctrine\ORM\EntityManager;
class ProductManager {
/** #var EntityManager */
private $entityManager;
public function setEntityManager (EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function getAll()
{
return $this->entityManager->createQuery('SELECT p FROM '.Product::class.' p')
->getResult();
}
public function add(Product $product, $flush = true)
{
$this->entityManager->persist($product);
if ( $flush ) {
$this->entityManager->flush($product);
}
}
public function byId($id)
{
// Fetch a product by id (note: No need to use DQL or the EntityRepository here either!)
return $this->entityManager->find(Product::class, $id);
}
}
app/config/services.yml
services:
app.product_manager:
class: AppBundle\Product\ProductManager
calls:
- [setEntityManager, ['#doctrine.orm.entity_manager']]
Controller
public function createAction(){
$product = new Product();
$product->setName('Amy Keyboard');
$product->setPrice(24.99);
$product->setDescription('Ergonomic and stylish!');
// add the product
$this->get('app.product_manager')->add($product);
return $this->render('index.html.twig');
}
Take a look at the Propel project if you want something like $product->save() but it is a totally different approach. This is the official bundle https://github.com/propelorm/PropelBundle/blob/3.0/README.markdown

Extend Doctrine EntityRepository

I have written a class BasicRepository in order to use it instead of the EntityRepository to add some basic modification like remove all deleted-flaged items.
<?php
namespace AppBundle\Repository;
use AppBundle\DataFixtures\ORM\LoadEventPrioData;
use AppBundle\Entity\Location;
use Doctrine\ORM\EntityRepository;
class BasicRepository extends EntityRepository
{
public function createQueryBuilder($alias, $indexBy = null)
{
$query = parent::createQueryBuilder($alias);
dump(parent::getClassName());
dump($this->getClassName());
if (property_exists($this->getClassName(), 'isDeleted')) {
dump("Ping");
$query->andWhere($alias.'.isDeleted = :false')->setParameter('false', false);
}
else {
dump("Pong");
}
return $query;
}
}
Controller:
...
public function searchAction(Request $request) {
$em = $this->getDoctrine()->getManager();
$meta = new ClassMetadata('AppBundle:Location');
$er = new BasicRepository($em, $meta);
$query = $er->createQueryBuilder('u');
...
My aim is that - if the property "isDeleted" (boolean) exists in the Entity - the Query should contain an additional Where-Statement.
For some strange reason property_exists always return false - even when the property exits in the class.
I get your idea. The correct place you're looking for is Doctrine Filters. Check this package: https://github.com/DeprecatedPackages/DoctrineFilters#usage
There you can find example exactly with your use case:
<?php
use Doctrine\ORM\Mapping\ClassMetadata;
use Symplify\DoctrineFilters\Contract\Filter\FilterInterface;
final class SoftdeletableFilter implements FilterInterface
{
/**
* {#inheritdoc}
*/
public function addFilterConstraint(ClassMetadata $entity, $alias)
{
if ($entity->getReflectionClass()->hasProperty('isDeleted')) {
return "$alias.isDeleted = 0";
}
return '';
}
}

Custom Repository (REQUEST DQL)

I have an error when I would like to add a custom method with DQL Request.
Error:
Undefined method 'getAll'. The method name must start with either
findBy or findOneBy!
My Controller:(SheetController.php)
<?php
namespace Test\FrontBundle\Controller;
use Doctrine\ORM\EntityNotFoundException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Test\FrontBundle\Entity\Sheet;
class SheetController extends Controller
{
public function sheetListAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('TestFrontBundle:Sheet');
$sheets = $repository->getAll();
var_dump($sheets);
return $this->render('TestFrontBundle:Sheet:sheetList.html.twig');
}
public function sheetAction($id, Request $request)
{
$repository = $this->getDoctrine()->getManager()->getRepository('TestFrontBundle:Sheet');
$sheet = $repository->find($id);
if(!$sheet)
{
throw new EntityNotFoundException();
}
return $this->render('TestFrontBundle:Sheet:sheet.html.twig', array('sheet' => $sheet));
}
}
?>
My Repository:(SheetRepository.php)
<?php
namespace Test\FrontBundle\Entity;
/**
* SheetRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class SheetRepository extends \Doctrine\ORM\EntityRepository
{
public function getAll()
{
$qb = $this->createQueryBuilder('s');
$query = $qb;
$result = $query->getQuery()->execute();
return $result;
}
}
Please, Could you help me? :)
Why don't you use native Doctrine query findAll() for this?
public function sheetListAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('TestFrontBundle:Sheet');
$sheets = $repository->findAll();
/***/
}
EDIT - With class repository:
class SheetRepository extends \Doctrine\ORM\EntityRepository
{
public function getAll()
{
return $this->createQueryBuilder('s')
->select('s')
->getQuery()
->getResult()
;
}
}
And in your controller : replace findAll() by getAll()

Resources