symfony2 restrict model based on user - upgrade from symfony1 - symfony

I'm building a multi-tenant application. In Symfony1 I would restrict access to data by accessing the user details and extending the createQuery function:
class PersonTable extends Doctrine_Table{
public function createQuery($alias = '')
{
$query = parent::createQuery($alias);
try {
$user = sfContext::getInstance()->getUser();
}catch(Exception $e){
if ($e->getMessage() == 'The "default" context does not exist.'){
return $query;
}else{
throw $e;
}
}
if ($user->hasGroup('Team1')){
//all good
}else if ($user->hasGroup('Team2')){
$user_id = $user->getGuardUser()->getStaff()->getId();
$alias = $query->getRootAlias();
$time = date('Y-m-d H:i:s',time());
$query->andWhere("$alias.type='type1' and pe.assigned_psw_id");
}
$query->orderBy('name asc');
return $query;
}
}
I know there are downsides to accessing the user object through sfContext in sf1, but this method seemed superior to others, as you can't "forget" to secure a controller against wrong user access.
How can I achieve the same in Symfony2?

I have solved this problem the following way.
Standardise how EntityRepository is fetched among controllers:
public function getUserRestrictedRepository($entity, $em = null )
{
$securityContext = $this->get( 'security.context' );
if (!$em){
$em = $this->getDoctrine()->getManager();
}
return $em
->getRepository( 'MyBundle:' . $entity )
->setSecurityContext( $securityContext );
}
Add a trait to provide queries with injected security query:
trait UserRestrictedEntityRepository {
private $securityContext;
/**
* #return mixed
*/
public function getSecurityContext()
{
return $this->securityContext;
}
/**
* #param mixed $securityContext
*/
public function setSecurityContext($securityContext)
{
$this->securityContext = $securityContext;
return $this;
}
/**
* #return mixed
*/
public function getUser()
{
return $this->getSecurityContext()->getToken()->getUser();
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name)
{
$this->name = $name;
}
function secureQueryWithUser($alias, $qb)
{
$qb->where("1=0");
}
function appendOrderBy($qb, $orderBy)
{
$first = true;
foreach ($orderBy as $field => $dir) {
if (!$dir) $dir = 'asc';
if ($first) {
$qb->orderBy('c.' . $field, $dir);
$first = false;
}else{
$qb->addOrderBy('c.' . $field, $dir);
}
}
}
public function createUnrestrictedQueryBuilder($alias)
{
return parent::createQueryBuilder($alias);
}
/**
* Creates a new QueryBuilder instance that is prepopulated for this entity name.
*
* #param string $alias
*
* #return QueryBuilder
*/
public function createQueryBuilder($alias, $indexBy=NULL)
{
if ($this->getUser()) {
$qb = $this->_em->createQueryBuilder()
->select($alias)
->from($this->_entityName, $alias);
if (isset($this->defaultOrder) && $this->defaultOrder){
$this->appendOrderBy($qb, $this->defaultOrder);
}
if ($this->getUser()->isSuperAdmin()){
return $qb;
}else{
return $this->secureQueryWithUser($alias, $qb);
}
}else{
throw new Exception('Run setUser() before querying ' . $this->getName() .' model.');
}
}
/**
* Finds all entities in the repository.
*
* #return array The entities.
*/
public function findAll()
{
return $this->findBy(array());
}
/**
* Finds entities by a set of criteria.
*
* #param array $criteria
* #param array|null $orderBy
* #param int|null $limit
* #param int|null $offset
*
* #return array The objects.
*/
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
{
$qb = $this->createQueryBuilder('c');
foreach ($criteria as $fkey => $fval){
$qb->andWhere($fkey.' = :'.$fval);
}
if ($limit){
$qb->setMaxResults($limit);
}
if ($offset){
$qb->setFirstResult($offset);
}
$query = $qb->getQuery();
return $query->getResult();
}
}
Implement query additions based on user access in the EnityRepository
class FarmerRepository extends EntityRepository
{
use UserRestrictedEntityRepository;
private $name = 'Farmer';
private $defaultOrder = array('name' => 'asc');
function secureQueryWithUser($alias, $qb)
{
if ($this->getSecurityContext()->isGranted( 'ROLE_CLINIC_ADMIN' )) {
return $qb
->innerJoin("$alias.vet", 'v')
->innerJoin("v.clinic", "cl")
->innerJoin("cl.VetsOfClinic", "vc")
->andWhere('vc.user_id= :userid')
->setParameter('userid', $this->getUser()->getId());
}else if ($this->getSecurityContext()->isGranted( 'ROLE_VET' )){
return $qb
->innerJoin("$alias.vet", 'v')
->andWhere('v.user_id= :userid')
->setParameter('userid', $this->getUser()->getId());
}else{
return $qb
->where("$alias.user_id= :userid")
->setParameter('userid', $this->getUser()->getId());
}
}
}

Related

Symfony 4.2 App\Entity\Shopcart object not found by the #ParamConverter annotation

Im working on Symfony 4.2. I get this error
App\Entity\Shopcart object not found by the #ParamConverter annotation.
when I try to delete or edit an item on shopcard.I tried many solution but failed.I need your suggestions.
Here is my ShopcartController
<?php
namespace App\Controller;
use App\Entity\Shopcart;
use App\Form\ShopcartType;
use App\Repository\ProductRepository;
use App\Repository\ShopcartRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* #Route("/shopcart")
*/
class ShopcartController extends AbstractController
{
/**
* #Route("/", name="shopcart_index", methods={"GET"})
*/
public function index(ShopcartRepository $shopcartRepository, ProductRepository $productRepository): Response
{
$slider=$productRepository->findBy([], ['name'=>'ASC'], 3); //slider doesn't exist hatası için ekledim
return $this->render('shopcart/index.html.twig', [
'shopcarts' => $shopcartRepository->getAllShops(),
'slider' => $slider, //slider doesn't exist hatası için ekledim
]);
}
/**
* #Route("/new", name="shopcart_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$shopcart = new Shopcart();
$form = $this->createForm(ShopcartType::class, $shopcart);
$form->handleRequest($request);
echo $submittedToken=$request->request->get('token');
if($this->isCsrfTokenValid('add-item', $submittedToken)) { //alınan tokenla uyuşuyorsa göre sepete ekliyor
if ($form->isSubmitted()) {
$entityManager = $this->getDoctrine()->getManager();
$user=$this->getUser();
$shopcart->setQuantity($request->request->get('quantity'));
$shopcart->setUserid($user->getid());
$entityManager->persist($shopcart);
$entityManager->flush();
return $this->redirectToRoute('shopcart_index');
}
}
return $this->render('shopcart/new.html.twig', [
'shopcart' => $shopcart,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="shopcart_show", methods={"GET"})
*/
public function show(Shopcart $shopcart): Response
{
return $this->render('shopcart/show.html.twig', [
'shopcart' => $shopcart,
]);
}
/**
* #Route("/{id}/edit", name="shopcart_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Shopcart $shopcart): Response
{
$form = $this->createForm(ShopcartType::class, $shopcart);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('shopcart_edit',['id'=>$shopcart->getId()]);
}
return $this->render('shopcart/edit.html.twig', [
'shopcart' => $shopcart,
'form' => $form->createView(),
]);
}
/**
* #Route("/{id}", name="shopcart_delete", methods={"DELETE"})
*/
public function delete(Request $request, Shopcart $shopcart): Response
{
//methodu post ile değiştirip dene
if ($this->isCsrfTokenValid('delete'.$shopcart->getId(), $request->request->get('_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->remove($shopcart);
$entityManager->flush();
}
return $this->redirectToRoute('shopcart_index');
}
/**
* #Route("/{id}/del", name="shopcart_del", methods={"DELETE"})
*/
public function del(Request $request, Shopcart $shopcart): Response
{
$em=$this->getDoctrine()->getManager();
$em->remove($shopcart);
$em->flush();
return $this->redirectToRoute('shopcart_index');
}
}
And here is ShopcartRepository.I use only getAllShops method.
<?php
namespace App\Repository;
use App\Entity\Shopcart;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use phpDocumentor\Reflection\Types\Integer;
/**
* #method Shopcart|null find($id, $lockMode = null, $lockVersion = null)
* #method Shopcart|null findOneBy(array $criteria, array $orderBy = null)
* #method Shopcart[] findAll()
* #method Shopcart[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ShopcartRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Shopcart::class);
}
// /**
// * #return Shopcart[] Returns an array of Shopcart objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('s')
->andWhere('s.exampleField = :val')
->setParameter('val', $value)
->orderBy('s.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Shopcart
{
return $this->createQueryBuilder('s')
->andWhere('s.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
//LET JOIN WITH SQL
public function getAllShops():array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT p.name, p.price, s.*, u.id FROM shopcart s, product p, user u
WHERE s.productid = p.id and s.userid=u.id
';
$stmt=$conn->prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
}
public function getUserShopCartTotal($userid): float
{
$em=$this->getEntityManager();
$query= $em->createQuery('
SELECT sum(p.price *s .quantity) as total
FROM App\Entity\Shopcart s, App\Entity\Product p
WHERE s.productid = p.id and s.userid=:userid
')
->setParameter('userid',$userid);
$result=$query->getResult();
if($result[0]['total']!=null){
return $result[0]["total"];
} else {
return 0;
}
}
public function getUserShopCartCount($userid): Integer
{
$em=$this->getEntityManager();
$query= $em->createQuery('
SELECT count(s.id) as shopcount
FROM App\Entity\Shopcart s
WHERE s.userid=:userid
')
->setParameter('userid',$userid);
$result=$query->getResult();
if($result[0]['shopcount']!=null){
return $result[0]["shopcount"];
} else {
return 0;
}
}
public function getUserShopCart($userid): array
{
$em=$this->getEntityManager();
$query= $em->createQuery('
SELECT p.name, p.price, s.quantity,s.productid, s.userid, (p.price * s.quantity) as total
FROM App\Entity\Shopcart s, App\Entity\Product p
WHERE s.productid = p.id and s.userid=:userid
')
->setParameter('userid',$userid);
return $query->getResult();
}
}
I think the problem is that you have two delete functions. The del function is a copy of the delete function. If you remove 'del' function your problem will be solved. The 'del' function override the route oh other functions.

Method not found in entity Paginator from doctrine bundle

I'm trying to clean up some code done in a messy way and right now I'm having trouble with doctrine's paginator.
When I'm accessing a page that handle paginator in order to show all different articles of my blog I'm getting this error:
Neither the property "id" nor one of the methods "id()", "getid()"/"isid()"/"hasid()" or "__call()" exist and have public access in class "Doctrine\ORM\Tools\Pagination\Paginator".
In doctrine vendor bundle those methods are not set but my entity have them and I know that it is forbidden to edit a vendor file. I'm missing something because I don't know if I should extend my paginator entity and add those missing methods or is there a little bit more to do ?
I just started symfony and I know that my bases are not enough to understand it all by myself.
Thank you very much for you time and attention.
Here is my Article controller for route category:
/**
* #Route("/categorie/{id}", name="categorie")
*
* #param Request $request
* #param Helper $helper
* #param AuthorizationCheckerInterface $authChecker
* #param DocumentCategory $categorie
* #param TwitterService $twitterService
*
* #return RedirectResponse|Response
*/
public function categorie(
Request $request,
Helper $helper,
AuthorizationCheckerInterface $authChecker,
DocumentCategory $categorie,
TwitterService $twitterService
) {
if (!$authChecker->isGranted('IS_AUTHENTICATED_FULLY')
&& !$authChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirectToRoute('login');
}
$page = (int) ($request->get('page'));
if (0 === $page) {
$page = 1;
}
$userType = $this->getDoctrine()->getRepository('App:User')
->getManagerExpertCollabo($this->getUser());
$articleAlaUneListe = [];
$articleIdListe = $helper->getArticleIdAuth($authChecker);
$articleListe = $this->getDoctrine()
->getRepository('App:Document')
->getPage(
self::ITEM_PER_PAGE * ($page - 1),
self::ITEM_PER_PAGE,
'document.dateCreated',
'DESC',
'(documentCategory.id = \''.$categorie->getId().'\' and '.$helper->baseRequestArticle().')',
7,
[],
$articleIdListe
);
[$articlePopulaireListe, $categorieListe, $totalPage] = $this->getPopularArticleList(
$articleListe,
$helper,
$articleIdListe
);
$articlesList->getDocuments();
$feedData = $twitterService->getTwitterFeed();
return $this->render('article/list.html.twig', [
'pageClass' => 'backoffice withFooterLarge dashboard',
'totalPage' => $totalPage,
'page' => $page,
'feedData' => $feedData,
'categorieListe' => $categorieListe,
'categorie' => $categorie,
'articleAlaUneListe' => $articleAlaUneListe,
'articlePopulaireListe' => $articlePopulaireListe,
'articleListe' => $articleListe, ]);
}
Here is the document entity for categories field:
/**
* #ORM\JoinTable(name="ht_lk_document_category"),
* #ORM\ManyToMany(targetEntity="App\Entity\DocumentCategory", inversedBy="documents")
*/
private $categories;
/**
* #return Collection|array<DocumentCategory>
*/
public function getCategories(): Collection
{
return $this->categories;
}
public function setCategories($category): self
{
$this->categories = $category;
return $this;
}
Here is the DocumentCategory entity :
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Document", mappedBy="categories")
*/
private $documents;
/**
* #return Collection|Document[]
*/
public function getDocuments(): Collection
{
return $this->documents;
}
Here is the Document Repository :
public function getPage($first_result, $max_results, $orderby, $direction, $criteria, $documentType = null, $searchWordArray = [], $articleIdListe = '')
{
$qb = $this->createQueryBuilder('docArticle');
$qb->select('docArticle')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
/*
if(sizeof($searchWordArray) > 0){
$fieldIndice = 1;
foreach($searchWordArray as $searchWord){
$qb->andWhere('(document.name_fr LIKE ?'.$fieldIndice.' or document.name_en LIKE ?'.$fieldIndice.' or document.content_fr LIKE ?'.$fieldIndice.' or document.content_en LIKE ?'.$fieldIndice.')');
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
} */
->leftJoin('docArticle.categories', 'documentCategory')
->leftJoin('docArticle.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results);
if (!empty($criteria)) {
$qb->where('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$pag = new Paginator($qb->getQuery());
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
if ('()' !== $articleIdListe) {
$qb->where('(docArticle.id IN '.$articleIdListe);
}
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
And finally here is the Document Category Repository :
/**
* #param $first_result
* #param $max_results
* #param $orderby
* #param $direction
* #param $criteria
* #param int|null $documentType
* #param array $searchWordArray
* #param string $articleIdListe
*
* #return array
*/
public function getPage(
$first_result,
$max_results,
$orderby,
$direction,
$criteria,
$documentType = null,
$searchWordArray = [],
$articleIdListe = ''
) {
$qb = $this->createQueryBuilder('document');
$qb->select('document')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
->addSelect('documentType', 'documentType');
if (\count($searchWordArray) > 0) {
$fieldIndice = 1;
foreach ($searchWordArray as $searchWord) {
$qb->andWhere(
'('
.'document.name_fr LIKE ?'.$fieldIndice
.' or document.name_en LIKE ?'.$fieldIndice
.' or document.content_fr LIKE ?'.$fieldIndice
.' or document.content_en LIKE ?'.$fieldIndice
.')'
);
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
}
if ($documentType) {
if (\mb_strlen($articleIdListe) > 3) {
$qb->andWhere('(documentType.id = :documentType OR document.id IN '.$articleIdListe.')')
->setParameter('documentType', $documentType);
} else {
$qb->andWhere('(documentType.id = :documentType)')
->setParameter('documentType', $documentType);
}
}
$qb->leftJoin('document.categories', 'documentCategory')
->leftJoin('document.documentType', 'documentType')
->leftJoin('document.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results)
->andWhere('document.documentType<>6');
if (!empty($criteria)) {
$qb->andWhere('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$sql = $qb->getQuery()->getSql();
$pag = new Paginator($qb->getQuery());
dump($pag);
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
/**
* #param int|null $documentType
*
* #return array
*/
public function getArticleIdList($documentType = null)
{
$qb = $this->createQueryBuilder('document');
$qb->select('document.id');
if ($documentType) {
$qb->where('(document.documentType = :documentType)')
->setParameter('documentType', $documentType);
}
$compte = $qb->getQuery()->getScalarResult();
return $compte;
}
(I deleted all unnecessary method for this question)
Add the following code to the entity class from which you want to show data:
public function getId(): ?string
{
return $this->id;
}
Or
if you do not want the property "id" to be displayed in the view, comment out or delete the lines of code in your Twig template for the entity in question. For example, delete
<td>{{ Category.id }}</td>

Symfony always return access denied, #Security, controller, isAuthor

I code a simple app (Symfony 4.1.7) with a user and product system
A user can edit his product, but not another user's
My problem, I go on the edit route, it return access denied, even when it's my product
My ProductController :
/**
* #Route("seller/myproduct/{id}/edit", name="seller_edit_product")
* #param Product $product
* #return Response
* #Security("product.isAuthor(user)")
*/
public function edit(Product $product, Request $request): Response
{
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()){
$this->em->flush();
$this->addFlash('success', 'Modify Successfully');
return $this->redirectToRoute('seller_index_product');
}
return $this->render('seller/product/edit.html.twig', [
'product' => $product,
'form' => $form->createView()
]);
}
Product.php
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="product_id")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
public function getUser(): User
{
return $this->user;
}
public function setUser(User $user): self
{
$this->user = $user;
return $this;
}
/**
* #return bool
*/
public function isAuthor(User $user = null)
{
return $user && $user->getProductId() === $this->getUser();
}
In my isAuhor function
== Access Denied
!== I can access the edition of product that Is not mine
User.php
/**
* #ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="user",orphanRemoval=true)
*/
private $product_id;
public function __construct()
{
$this->product_id = new ArrayCollection();
}
/**
* #return Collection|Product[]
*/
public function getProductId(): Collection
{
return $this->product_id;
}
public function addProductId(Product $productId): self
{
if (!$this->product_id->contains($productId)) {
$this->product_id[] = $productId;
$productId->setUser($this);
}
return $this;
}
}
Thank you
Your isAuthor function will always return false as you are comparing an ArrayCollection to a User
You could add a function in User Class definition that checks if a given user have a given product or no.
So in Product.php :
/**
* #return bool
*/
public function isAuthor(User $user = null)
{
return $user && $user->hasProduct($this);
}
And the hasProduction function could be something like this:
// this goes into User.php
/**
* #return bool
*/
public function hasProduct(Product $product)
{
return $this->product_id->contains($product)
}

Symfony 3.3.2 Doctrine EntityRepository constructor argument

I'm newbie on Symfony. I am trying to update an old project under symfony 2.6 to symfony 3.3.
After multiple bug fixes I am stuck on a point: I have an Error in my EntityRepository.php file with the constructor.
Type error: Too few arguments to function Doctrine\ORM\EntityRepository::__construct(), 1 passed in /Users/.../var/cache/dev/appDevDebugProjectContainer.php on line 3434 and exactly 2 expected
I understand the error, but my EntityRepository file not contain any __construct method. Should I fix something between Symfony 2 and 3 for the consructor to work?
Thanks a lot.
Here is my MilestoneRepository.php file:
namespace MilestonesBundle\Entity\Repository;
use DateTime;
use Doctrine\ORM\EntityRepository;
use Milestones\Entity\Factory\MilestoneFactoryInterface;
use Milestones\Entity\Repository\MilestoneRepositoryInterface;
class MilestoneRepository extends EntityRepository implements MilestoneFactoryInterface, MilestoneRepositoryInterface
{
protected $current = false;
/**
* #see MilestoneFactoryInterface
*/
public function create()
{
$class = $this->getClassName();
return new $class;
}
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
{
if (!$orderBy) {
$orderBy['startsAt'] = 'ASC';
}
return parent::findBy($criteria, $orderBy, $limit, $offset);
}
/**
* #see MilestoneRepositoryInterface
*/
public function findCurrent()
{
$now = new DateTime;
if ($this->current === false) {
$this->current = $this->createQueryBuilder('m')
->where('m.startsAt <= :now')
->andWhere('(m.endsAt IS NULL OR :now < m.endsAt)')
->setParameter('now', $now->format('Y-m-d'))
->orderBy('m.startsAt', 'ASC')
->setMaxResults(1)
->getQuery()
->getOneOrNullResult()
;
}
return $this->current;
}
/**
* #see MilestoneRepositoryInterface
*/
public function isOpen()
{
$current = $this->findCurrent();
return $current && $current->isStart();
}
}
And here is my EntityRepository.php file:
namespace Common\Doctrine\ORM;
use Doctrine\ORM\EntityRepository as BaseEntityRepository;
use Doctrine\ORM\QueryBuilder;
class EntityRepository extends BaseEntityRepository
{
protected $alias = 'x';
public function add($entity)
{
$em = $this->getEntityManager();
$em->persist($entity);
$em->flush();
}
public function remove($entity)
{
$em = $this->getEntityManager();
$em->remove($entity);
$em->flush();
}
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null, $result = true)
{
$alias = $this->alias;
$builder = $this->createQueryBuilder($alias);
$this->applyCriteria($builder, $alias, $criteria);
$this->applyOrderBy($builder, $alias, $orderBy);
$this->applyLimit($builder, $limit);
$this->applyOffset($builder, $offset);
if (!$result) {
return $builder;
}
return $builder->getQuery()->getResult();
}
public function findOneBy(array $criteria, array $orderBy = null, $result = true)
{
$alias = $this->alias;
$builder = $this->createQueryBuilder($alias);
$this->applyCriteria($builder, $alias, $criteria);
$this->applyOrderBy($builder, $alias, $orderBy);
if (!$result) {
return $builder;
}
return $builder->getQuery()->getOneOrNullResult();
}
protected function applyCriteria(QueryBuilder $builder, $alias, array $criteria)
{
$map = $this->getCriteriaMap();
foreach ($criteria as $property => $value) {
if (array_key_exists($property, $map)) {
call_user_func_array($map[$property], [$builder, $alias, $property, $value]);
} else {
$this->applyDefaultCriterion($builder, $alias, $property, $value);
}
}
}
protected function getCriteriaMap()
{
return [];
}
protected function applyDefaultCriterion($builder, $alias, $property, $value)
{
if (null === $value) {
$builder->andWhere($alias.'.'.$property.' IS NULL');
} else {
$parameter = 'p_' . uniqid();
$builder->andWhere($alias.'.'.$property.' = :'.$parameter);
$builder->setParameter($parameter, $value);
}
}
/**
* Apply order by
*
* #param QueryBuilder $builder
* #param string $alias
* #param array|null $orderBy
* #return void
*/
protected function applyOrderBy(QueryBuilder $builder, $alias, array $orderBy = null)
{
if (empty($orderBy)) {
$orderBy = $this->getDefaultOrder();
}
$map = $this->getOrderingMap();
foreach ($orderBy as $property => $direction) {
if (array_key_exists($property, $map)) {
call_user_func_array($map[$property], [$builder, $alias, $property, $direction]);
} else {
$this->applyDefaultOrder($builder, $alias, $property, $direction);
}
}
}
protected function getDefaultOrder()
{
return [];
}
protected function getOrderingMap()
{
return [];
}
protected function applyDefaultOrder(QueryBuilder $builder, $alias, $property, $direction)
{
$builder->orderBy($alias.'.'.$property, $direction);
}
protected function applyLimit(QueryBuilder $builder, $limit = null)
{
if ($limit) {
$builder->setMaxResults($limit);
}
}
protected function applyOffset(QueryBuilder $builder, $offset = null)
{
if ($offset) {
$builder->setFirstResult($offset);
}
}
}
I think I'm accessing through a service, with this:
services:
# Factories
milestones.factory.milestone:
alias: milestones.repository.milestone
arguments: [ MilestonesBundle\Entity\Milestone ]
# Repositories
milestones.repository.milestone:
class: MilestonesBundle\Entity\Repository\MilestoneRepository
factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository
arguments: [ MilestonesBundle\Entity\Milestone ]
replace this code:
milestones.repository.milestone:
class: MilestonesBundle\Entity\Repository\MilestoneRepository
factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository
arguments: [ MilestonesBundle\Entity\Milestone ]
with this one:
milestones.repository.milestone:
class: MilestonesBundle\Entity\Repository\MilestoneRepository
factory: ['#doctrine.orm.entity_manager', getRepository]
arguments: [ MilestonesBundle\Entity\Milestone ]
factory method - getRepository
I think somewhere in jour code this method is called:
public function create()
{
$class = $this->getClassName();
return new $class;
}
And this is calling the constructor of Doctrine\ORM\EntityRepository:
public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class)
{
$this->_entityName = $class->name;
$this->_em = $em;
$this->_class = $class;
}
therefore you will have to inject the arguments if you want to use your create method... I think it should be something like new $class($entityManager, Entity::class)

Symfony2 get parameters.yml in entity, special case

I know its against the framework to make an entity container aware, but this is a special case, i have a credit card entity, and i want to do this:
/**
* #return mixed
*/
public function getNumber()
{
$number = $this->number;
$crypt = base64_decode($number);
$number = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $crypt, MCRYPT_MODE_ECB);
return trim($number);
}
/**
* #param $number
* #return $this
*/
public function setNumber($number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
$this->number = $number;
return $this;
}
And i want the $key to be the secret from parameters.yml, since i dont want to save it in the code.
I can't pass it as a parameter, when i use the FormType, cause the form type will not pass it when it binds the request.
$credit_card = new CreditCard();
$credit_card->setCustomer($customer);
$payment_form = $this->createPaymentForm($credit_card);
$payment_form->handleRequest($request);
Remove data modifications from your Entity, and add it to your FormType.
public function getNumber()
{
return $this->number;
}
public function setNumber($number)
{
$this->number = $number;
return $this;
}
Make your FormType take the parameter as argument.
class CreditCardType extends AbstractType {
private $key;
public function __construct($key) {
$this->key = $key;
}
// ...
// Listen on the PRE_BIND event to update your value before binding
$builder->addEventListener(FormEvents::PRE_BIND, function (FormEvent $event)
{
$data = $event->getData();
$number = $data['number'];
$crypt = $this->encryptNumber($number);
$data['number'] = $crypt;
$event->setData($data);
});
public function encryptNumber($key, $number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
return $number;
}
}
Now, in your createPaymentForm, add the parameter to your FormType instance, like this :
$param = $this->container->getParameter('yourkeyparam');
$form = $this->createForm(new CreditCardType($param), $credit_card, array());
Hope this is what you need.

Resources