methode getconnection not found in \Doctrine\Common\Persistence - symfony

I am following a tutoral on Symfony 4 where we want to create a raw query. Here is the code that is provided in the tutorial :
public function index(Request $request)
{
$entityManager = $this->getDoctrine()->getManager();
$conn = $entityManager->getConnection();
$sql = '
SELECT * FROM user u
WHERE u.id > :id
';
$stmt = $conn->prepare($sql);
$stmt->execute(['id' => 3]);
//more code
}
But when I try to do the same the methode getconnection seem to not be recognized by my IDE and it gives me this message :
methode getconnection not found in \Doctrine\Common\Persistence\ObjectManager
Any ideas about what shoould I do ? I will apreciate it.

since it's not really an error, but more of a static analysis result, you can try to quiet the static analysis tool used (not exactly sure, which one it is) you could do this when getting your entity manager:
/** #var \Doctrine\ORM\EntityManagerInterface $entityManager */
$entityManager = $this->getDoctrine()->getManager();
if the static analysis tool is any good, it will accept the comment/hint and recognize the entity manager for what it truly is and probably will stop complaining.
(the question I ask myself: is there a reason you use plain SQL instead of ... you know ... the entity manager, like ... $user = $entityManager->find(User::class, 3); ... unless your User is not an entity for whatever reason)

Related

Single position to restrict access to a Doctrine entity

I've just started working with Doctrine and built a simple blog project. One of my requirements is that a blog post should not be visible to anybody (for simpleness, skip an editor's interface) until the publish date is reached.
As far as I see, it's obvious to do so using a custom repository. Let's extend the find method the following way:
public function find($id, $lockMode = null, $lockVersion = null)
{
/** #var Post $post */
$post = parent::find($id, $lockMode, $lockVersion);
if($post->getCreatedAt() > new \DateTime()) {
return null;
}
return $post;
}
This restricts the access for a page showing a single Post entity. For an overview page, the same can be done using a custom method:
public function findForOverview()
{
$query = $this->createQueryBuilder('p')
->where('p.createdAt < CURRENT_TIMESTAMP()')
->orderBy('p.createdAt', 'DESC')
->getQuery();
return $query->getResult();
}
So, even for this simple requirement, I've already written two custom methods. If I continue to work on my project, other restriction limitations might occur and additional ways to load that entity might arise. And as far as I see, for each case I have to implement the logic for all access guards.
Is there no simpler way to do that? I'm thinking of something like an annotation or an "entity load listener" that makes it simple to write one single entry point for all such checks - making it impossible to forget such checks...
Such restrictions are usually implemented by using mechanism of SQL filters in Doctrine. Implementation of this filter works on lower level then DQL and allows you to apply modifications for SQL query being constructed. In your case it may look like this:
namespace App\ORM\Filter;
use App\Entity\Post;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
class PostVisibilityFilter extends SQLFilter
{
/**
* Gets the SQL query part to add to a query.
*
* #param ClassMetadata $targetEntity
* #param string $targetTableAlias
* #return string The constraint SQL if there is available, empty string otherwise
*/
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
{
if ($targetEntity->name !== Post::class) {
return '';
}
return sprintf('%s.%s >= now()', $targetTableAlias, $targetEntity->getColumnName('createdAt'));
}
}

Controller class not seeing method from repository class

I have spent the last few hours trying to find an answer however not gaining at all. I feel that it will end up being something simple that I did not have knowledge of. This section of code is of course incorrect but I wanted to show the idea of what I was trying to do here. I currently have a base repository class that has the findAllQueryBuilder method within it that will allow for reduced code. Right now I have about 10 repository classes that all need to use findAllQueryBuilder. This function is within the basecontroller I have built. The main issue is that this controllor does not see findAllQueryBuilder because as you can see this takes in the parameters to determine which data location is needed. I've done this once already in another location in my code with an interface however that was with a class I will put that example here also.
public function listAction(Request $request, RepositoryTypeInterface $repositoryName, $table, $sql, $route)
{
$filter = $request->query->get('filter');
$repository = "Bundle:$repositoryName";
$qb = $this->getDoctrine()
->getRepository($repository, 'tenant')
->findAllQueryBuilder($filter, $table, $sql);
As you can see in the following I set the type as the interface to make sure it knew that it was going to be that then.
public function newAction(Request $request, EntityTypeInterface $controllerType, formType, $repository, $routeName)
{
And then instantiated it within the childclass controllor
public function newAction(Request $request, EntityTypeInterface $controllerType = null, $formType = ContactType::class, $repository = 'Contact', $routeName = 'api_contacts_show')
{
$controllerType = new Contact();
return parent::newAction($request, $controllerType, $formType, $repository, $routeName);
}
So The first example above has me attempting the same thing however I am not sure how to apply this to this situation. as "Bundle:$repository" is a string and the parameter used is a string and it's not an entity so creating an instance doesn't make sense when all I need is its functionality. I just need some way to have access to this functionality. any ideas would work but I'm feeling like I'm missing something simple.
Here is the exact error I get,
Method 'findAllQueryBuilder' not found in \Doctrine\Common\Persistence\ObjectRepository
Referenced method is not found in subject class.
I'm sure there is a way to apply this concept to fix the lack of 'seeing' the function however as of right now I'm not completely sure.
Thank you anyone in advance.
EDIT:
I'm using a basecontrollor that is setting this up for the other controllers ie:cantactscontrollor class which uses the ContactEntity class mapped to the contactrepository class which is a child of a baserepository class which is where findAllQueryBuilder is located, I'm not sure how to map that.
public function listAction(Request $request, $repositoryName, $table, $sql, $route)
{
$filter = $request->query->get('filter');
$repository = "TenantBundle:$repositoryName";
/** #var RepositoryTypeInterface $qb */
$qb = $this->getDoctrine()
->getRepository($repository, 'tenant');
$queryResults = $qb->findAllQueryBuilder($filter, $table, $sql);
Sorry for the late response on this but here is the answer I was able to find. As I thought it was a simple thing but essentially the Docblock labeled $qb as the said interface above making sure it knew that any class that implements it will be accepted. Now knowing what type it will be, the error message is no longer there. Notice also how I split it up.

Symfony2 Entity properties loaded from db

So , i'm working on a news portal , and i have two entities :
News Entity (id,title...source)
Source Entity(id,title...)
In News Entity,field named 'Source' is an id to Source Entity;
So , i need to access Source Title when publishing news . I know there's posibility doing thing relationships ManyToOne . But i don't want do it , because it makes my life harder in some cases . Is there posibility to execute a Query in Entity ? like :
public function getSourceTitle()
{
$query = ...;
return $query->getScalarResult();
}
Can i do it ? or is there another posibility ?
It's not a good practice to query insiide Entity class. Entity class should hold just fields, setters and getters, nothing else. So, if you want to query the db, and how are you planning to do it? Injecting EntityManager? Ok, If you really want to do it you can simply do it like this:
...
private $entityManager;
public function __construct(EntityManagerINterface $entityManager)
{
$this->entityManager = $entityManager;
}
...
public function getSourceTitle()
{
$sourceRepository = $this->entityManager->getRepository('VendorMyBundle:Source');
$queryBuilder = $sourceRepository->createQueryBuilder('s')
->....
return $queryBuilder->getScalarResult();
}
and use it as new MyEntity($entityManager) on entity creation.. But, you should know that this is considered as very bad practice...

When to use Entity Manager in Symfony2

At the moment I am learning how to use Symfony2. I got to the point where they explain how to use Doctrine.
In the examples given they sometimes use the entity manager:
$em = $this->getDoctrine()->getEntityManager();
$products = $em->getRepository('AcmeStoreBundle:Product')
->findAllOrderedByName();
and in other examples the entity manager is not used:
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
So I actually tried the first example without getting the entity manager:
$repository = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product');
$products = $repository->findAllOrderedByName();
and got the same results.
So when do i actually need the entity manager and when is it OK to just go for the repository at once?
Looking at Controller getDoctrine() equals to $this->get('doctrine'), an instance of Symfony\Bundle\DoctrineBundle\Registry. Registry provides:
getEntityManager() returning Doctrine\ORM\EntityManager, which in turn provides getRepository()
getRepository() returning Doctrine\ORM\EntityRepository
Thus, $this->getDoctrine()->getRepository() equals $this->getDoctrine()->getEntityManager()->getRepository().
Entity manager is useful when you want to persist or remove an entity:
$em = $this->getDoctrine()->getEntityManager();
$em->persist($myEntity);
$em->flush();
If you are just fetching data, you can get only the repository:
$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');
$product = $repository->find(1);
Or better, if you are using custom repositories, wrap getRepository() in a controller function as you can get auto-completition feature from your IDE:
/**
* #return \Acme\HelloBundle\Repository\ProductRepository
*/
protected function getProductRepository()
{
return $this->getDoctrine()->getRepository('AcmeHelloBundle:Product');
}
I think that the getDoctrine()->getRepository() is simply a shortcut to getDoctrine()->getEntityManager()->getRepository(). Did not check the source code, but sounds rather reasonable to me.
If you plan to do multiple operations with the entity manager (like get a repository, persist an entity, flush, etc), then get the entity manager first and store it in a variable. Otherwise, you can get the repository from the entity manager and call whatever method you want on the repository class all in one line. Both ways will work. It's just a matter of coding style and your needs.

Using distinct Doctrine2

I am developing an application in symfony2 and using doctrine2. I created a custom repository class that has one function:
<?php
namespace Anotatzailea\AnotatzaileaBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* InterpretatzeaRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class InterpretatzeaRepository extends EntityRepository
{
public function getInterpDesberdinak($value)
{
$qb = $this->createQueryBuilder('c')
->select('DISTINCT c.attribute')
->where('c.fer = :Value')
->setParameter('Value', $value);
$Emaitza = $qb->getQuery()->getResult();
return $Emaitza;
}
}
What I want to get with this function is an array of all the "Interpretatzea" objects that have a distinct c.attribute and all have c.fer = value. Is the query correct? I would also want to know how to pass the value parameter to the repository function. Thanks
A cursory look at your repository method suggests it looks okay :) IIRC, I think the use of DISTINCT there is fine. If you do have problems you can always do a GROUP BY instead.
As for calling the repo method in a controller and passing a $value variable to it, that's pretty straightforward; for example:
// in your controller
$value = 'foo';
// get doctrine connection from DI, etc.
$em = $this->getDoctrine()
->getEntityManager();
// get the repository object for your
// entity and call your repository method
$result = $em->getRepository('AnotatzaileaAnotatzaileaBundle:Interpretatzea')
->getInterpDesberdinak($value);
// ... do something with your $result here
Note you use a concatenated version of your namespace and bundle, followed by a colon and the entity; e.g: AcmeTestBundle:User
Hope this helps :)

Resources