how doctrine entityRepository works? - php

i'm new on doctrine orm so i try to learn some tutorial on
ps:knpuniversity.com/screencast/doctrine-queries/dql
but i still confused for exp:
src/AppBundle/Entity/Category.php
class Category
{
private $id;
private $name;
private $iconKey;
private $fortuneCookies;
We can access build in method by
$categoryRepository = $this->getDoctrine()
->getManager()
->getRepository('AppBundle:Category');
$categories = $categoryRepository->findAll();
But if we want to access new method we can do this
$categoryRepository = $this->getDoctrine()
->getManager()
->getRepository('AppBundle:Category');
$categories = $categoryRepository->findAllOrdered();
Then provide class for repository
src/AppBundle/Entity/CategoryRepository.php
class CategoryRepository extends EntityRepository
{
public function findAllOrdered()
{
die('this query will blow your mind...');
}
}
i still not get it!!
$categoryRepository = $this->getDoctrine()
->getManager()
->getRepository('AppBundle:Category');
if those above point to category entity, how come it suddenly can link to CategoryRepository and we could access findAllOrdered() method?
did i missed something guys please help?

As I understood you are using annotations and most probably you have an annotation of the entity class. You just have to specify the repository class like this:
/**
* #ORM\Entity(repositoryClass="AppBundle\Entity\CategoryRepository")
* #ORM\Table(name="Category")
*/
Specify

As several developers told you, it's important to link your Entity class with your Repository class through the annotations.
#ORM\Table(name="your_entity_name")
#ORM\Entity(repositoryClass="Your_RepositoryClass")
If you want to call your repository with a name more customized (e.g. 'repository.category' instead of 'AppBundle:Category'), you can create a service through a yml file.

Related

Symfony3 repository method doesn't work

I'm trying to call a method in the repository ArticleRepository from my controller ArticleController. However it says :
Undefined method 'afficheArticle'. The method name must start with either findBy or findOneBy!
my Entity Article : (Entity\Article.php)
/**
* Article
*
* #ORM\Table(name="Article", indexes={#ORM\Index(name="I_FK_Article_TypeArticle", columns={"idTypeArticle"})})
* #ORM\Entity(repositoryClass="erp-gkeep\new_erp\gkeepBundle\Repository\ArticleRepository")
*/
class Article
{
my ArticleController (Controller\ArticleController)
/**
* #Route("viewArticle2", name="viewArticle2")
*/
public function listAction2()
{
$data = $this->getDoctrine()->getRepository('gkeepBundle:Article')->afficheArticle();
my ArticleRepository
<?php
/**
* Created by PhpStorm.
*/
namespace gkeepBundle\Repository;
use Doctrine\ORM\EntityRepository;
class ArticleRepository extends EntityRepository
{
public function afficheArticle(){
$em=$this->getEntityManager();
$query = $em->createQuery(
'SELECT a.reference, a.designationfr, a.designationen, a.plan, a.url, a.datecreation, a.idtypearticle
FROM gkeepBundle:Article a
'
);
$articles = $query->getArrayResult();
return $articles;
}
}
if someone can help me please ! I'm pretty sure it's a stupid error :/
The value of repositoryClass in your mapping annotation needs to be the namespace + class name of your repository, it looks like you've maybe added some of the directory structure as well. - actually isn't a valid character in a PHP namespace, so the value you've got now definitely isn't right.
Try
#ORM\Entity(repositoryClass="gkeepBundle\Repository\ArticleRepository")
For reference: when this classname is not valid, Doctrine falls back to the default repository - this is what's throwing the error you're seeing.

Symfony 3.0: Reuse entity in repository

On my Symfony 3.0 project I have a Entity named ImageGroups and a repository I made ImageGroupsRepository that Use ImageGroups entity. I also made an Images entity with a ImagesRepository
In ImageGroupsRepository I have a method named getUserImageGroups and on ImagesRepository I have a method named add.
What I want to ask is How to use the getUserImageGroups method from ImageGroupsRepository into add from ImagesRepository?
The answer given by A.L is correct, I just wanted to offer an alternative method to access the entity manager without having to call the function again, via $this->_em:
class ImagesRepository extends EntityRepository
{
public function add()
{
$imagesGroups = $this->_em
->getRepository('AcmeBundle:ImageGroups')
->getUserImageGroups();
// …
}
}
If you look at the documentation for EntityRepository you'll see that the getEntityManager() function simply returns the protected $_em member of the EntityRepository class.
In your repository, you can get the entity manager with $this->getEntityManager(), this allow to call getRepository() in order to get another repository:
class ImagesRepository extends EntityRepository
{
public function add()
{
$em = $this->getEntityManager();
$imagesGroups = $em
->getRepository('AcmeBundle:ImageGroups')
->getUserImageGroups();
// …
}
}

Class XXX is not a valid document or mapped super class

I'm using doctrine Doctrine MongoDB ODM 1.0.3. When trying to update document using doctrine I'm getting the following error:
Class XXX is not a valid document or mapped super class.
I have the following class for the document:
<?php
namespace Documents;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
* #ODM\Document(collection="posts")
*/
class Posts
{
/** #ODM\Id */
private $id;
/** #ODM\Field(type="string") */
private $title;
/** #ODM\EmbedMany(targetDocument="Comment") */
private $comments = array();
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function addComment($comment)
{
$this->comments[] = $comment;
}
public function getComments()
{
return $this->comments;
}
}
The following code is used to add new document:
$post = new \Documents\Posts();
$post->setTitle( $_POST['title'] );
$dm->persist($post);
$dm->flush();
Later I want to update the added document to add new comment for example. I use the following code:
$comment = new \Documents\Comment($_POST['comment_text']);
$dm->createQueryBuilder('Posts')
->update()
->field('comments')->push($comment)
->field('_id')->equals(new \MongoId($_POST['id']))
->getQuery()
->execute();
but getting the above mentioned error.
As you stated in your own answer you need to provide fully qualified name of class. Just wanted to add that better than to pass the string it is to use static class property like this instead: createQueryBuilder(\Documents\Posts::class); It works much better with IDEs (autocompletion, refactoring etc...)
For people getting this error in PHP 8 and above, check that you are not mixing annotations (e.g. /** #Entity */) and attributes (e.g. #[Entity]), and that you have indicated which method you are using in your config:
mappings:
App:
# pick one:
type: annotation
type: attribute
This always trips me up when I start a new project and the config defaults to annotations when I'm used to using attributes.
In case anyone else have a similar problem, you need to pass fully qualified class name to createQueryBuilder. My document classes are all inside Documents namespace so after passing it like this createQueryBuilder('\Documents\Posts') the problem is solved.
Based on the other varying answers here, it seems this error isn't super precise.
In my case the class was missing the EmbeddedDocument annotation.
namespace Foo;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
/**
* #ODM\EmbeddedDocument
*/
class Bar { }

Symfony2 : Repository Class not found

Today I stuck in Repository Class Function I got this error
Undefined method 'test'. The method name must start with either findBy or findOneBy!
I allready checked these solutions -
Solution 1
Solution 2
Solution 3
Is anything I need to add into config file ?
This is my Entity Class
// src/Foo/NewsBundle/Entity/News.php
namespace Foo\NewsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* News
* #ORM\Entity(repositoryClass="Foo\NewsBundle\Repository\NewsRepository")
* #ORM\Table(name="news")
* #ORM\HasLifecycleCallbacks()
*/
class News
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $title;
This is my repository Class
// Foo/NewsBundle/Repository/NewsRepository.php
namespace Foo\NewsBundle\Repository;
use Doctrine\ORM\EntityRepository;
Class NewsRepository extends EntityRepository
{
public function test()
{
return "Nisarg";
}
}
And I am calling this test() function this wat from the controller
public function indexAction()
{
// $news = $this->getDoctrine()
// ->getRepository('FooNewsBundle:News')
// ->findAll();
$em = $this->getDoctrine()
->getManager();
$news = $em->getRepository('FooNewsBundle:News')->test();
if (!$news) {
throw $this->createNotFoundException('No news found');
}
$build['news'] = $news;
return $this->render('FooNewsBundle:Default:news_show_all.html.twig', $build);
}
Check if you have specified your repository class in your News orm config file.
There must be somthing like "repositoryClass: Foo\NewsBundle\Repository\NewsRepository"
And don't forget to clear cache!
In your entity you are not using annotation, check if you have a news.yml file in Resources/config/doctrine
I think the standard for repository classes is to put it in a subdirectory of the entity folder and still use the same entity namespace. Yours used a different namespace which is why I think you have the error.
According to the cookbook this is how the entity and custom respistory are defined.
link to custom repository class in the cookbook.
Entity
// src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="Acme\StoreBundle\Entity\ProductRepository")
*/
class Product
{
//...
}
Repository:
// src/Acme/StoreBundle/Entity/ProductRepository.php
namespace Acme\StoreBundle\Entity;
use Doctrine\ORM\EntityRepository;
class ProductRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC'
)
->getResult();
}
}
Fedor Petrick is right!
You should look for the orm file that corresponds to the entity.
In my case, I have created a custom repository named: OfertaRepository.php in the folder OfertaBundle\Entity
On the other hand, I have a file Oferta.orm.xml
In line three , It said :
<entity name="OfertaBundle\Entity\Oferta" table="oferta">
But it should be :
<entity name="OfertaBundle\Entity\Oferta" table="oferta" repository-class="OfertaBundle\Entity\OfertaRepository">
Now, the method in the OfertaRepository.php works well!
Your code look correct in the Entity and Repository. Perhaps you could try to call the getRepository directly without ->getManager.
$this->getDoctrine->getRepository('FooNewsBundle:News')->test();
If you need a specific field you should have a look at the short notations with findOneBy and findBy in most cases its much easier instead of writing a custom class.
http://symfony.com/doc/current/book/doctrine.html
Are you in production ? Perhaps clearing your cache is the solution :
php app/console cache:clear --env=prod --no-debug
If clearing your cache doesn't work, is $em->getRepository('FooNewsBundle:News') instanceOf Foo\NewsBundle\Repository\NewsRepository true or false? By the looks of things, your not getting the correct repository somehow?
have you generated the entities?
php app/console doctrine:generate:entities BUNDLENAME
launch this command and then retry your code

symfony architecture: custom method with repository access on entity creation

I have an DB table with a UNIQUE column that should contain a unique 8 character alphanumeric string.
I've (finally) making the move from my own MVC framework to symfony. Up until now I would have had a private method in the model that is called on CREATE. A loop in the method would generate a random hash, and perform a READ on the table to see if it is unique: if so, the hash would be returned and injected into the CREATE request.
The problem as I see it is that in symfony I have no access to the repository from within the entity class, so I can't use a lifecycle callback. I understand the reasoning behind this. On the other hand, the hash generation has nothing to do with the controller – for me it is internal logic that belongs in the model. If I later change the data structure, I need to edit the controller.
My question is: architecture-wise, where should I put the hash generation method?
You can use a listener. You were right that the lifecycle callbacks are not the correct solution since you need access to the repository. But you can define a Listener that listens to the same event as the lifecycle callback, but is an service and therefore can have the repository as dependency.
Answering my own question:
I created a custom repository, which has access to the doctrine entity manager.
The repository has a createNewHash method:
class HashRepository extends EntityRepository
{
public function createNewHash()
{
$hash = new Hash();
$hash->setHash($this->_getUniqueHash());
$em = $this->getEntityManager();
$em->persist($hash);
$em->flush();
return $hash;
}
private function _getUniqueHash()
{
$hash = null;
$hashexists = true;
while ($hashexists) {
$hash = $this->_generateRandomAlphaNumericString();
if (!$hashobject = $this->findOneByHash($hash)) {
$hashexists = false;
}
}
return $hash;
}
private function _generateRandomAlphaNumericString( $length=8 )
{
$bits = $length / 2;
return bin2hex(openssl_random_pseudo_bytes($bits));
}
}
The createNewHash() method can then be called from the Controller, and the Controller does not have to concern itself with hash creation.
EDIT: Listeners are another way of doing it.
In your entity constructor, i can add this:
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* MyEntity
*
* #ORM\Table(name="my_entity")
*/
class MyEntity
{
/**
* #ORM\Column(type="string", length=8, unique=true, nullable=false)
* #var string
*/
private $uniqId;
public function __construct()
{
$this->uniqId = hash('crc32b', uniqid());
}
// ...
}
Hope this helps

Categories