i have a strange problem when trying to render entity in symfony2 easyadminBundle i got a blank screen without any errors,
when trying to list entity 'Ads' that has many-to-one relation-ship with entity 'pages' ,where page contains many ads., however if i modified the action parameter in the url to be &action=new instead of &action=list it shows the form but after saving it giving me the same blank screen!
My Pages Entity :
/**
* #var string
*
* #ORM\Column(name="page_name", type="string", length=30, nullable=true)
*/
private $pageName;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/*#ORM\OneToMany(targetEntity="Ads", mappedBy="pages")
*
*/
protected $ads;
public function __construct()
{
$this->ads = new ArrayCollection();
}
}
Ads Entity:
/**
* Ads
*
* #ORM\Table(name="ads")
* #ORM\Entity
*/
class Ads
{
/**
* #var integer
*
* #ORM\Column(name="page_id", type="integer", nullable=false)
*/
private $page_id ;
/**
* #var string
*
* #ORM\Column(name="ad_text", type="text", nullable=false)
*/
private $adText;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Pages", inversedBy="ads")
* #ORM\JoinColumn(name="page_id", referencedColumnName="id")
*/
private $page_ad;
}
Your configuration looks "not complicated", so it should work as expected. The "blank page" error is really strange. We render the data with try...catch to avoid any issue when we cannot access the information. Besides, we also catch the exceptions to display customized error pages.
Can you see any error message in your dev.log file?
You could also do the following. Create the simplest possible configuration for the list view of the Ads entity as follows:
easy_admin:
entities:
Ads:
list:
fields: ['id']
If this work, try adding more fields one by one until you find the error.
Related
I would like to be able to use entity validator constraints to verify if the foreign key book_id is valid, please see below:
Book.php
/**
* Book
*
* #ORM\Table("book")
* #ORM\Entity
* #ORM\Entity(repositoryClass="AppBundle\Repository\BookRepository")
*/
class Book
{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string")
* #Assert\Length(
* max = 250,
* maxMessage = "Name cannot be longer than {{ limit }} characters",
* groups={"create","update"}
* )
*/
private $name;
/**
* #ORM\OneToOne(targetEntity="Loan", mappedBy="book", fetch="LAZY")
*/
protected $loan;
}
Loan.php
/**
* Loan
*
* #ORM\Table("loan")
* #ORM\Entity
* #ORM\Entity(repositoryClass="AppBundle\Repository\LoanRepository")
*/
class Loan
{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
* #ORM\Column(name="book_id", type="integer")
*/
protected $book_id;
/**
* #var string
* #ORM\Column(name="name", type="string")
* #Assert\Length(
* max = 500,
* maxMessage = "Person cannot be longer than {{ limit }} characters",
* groups={"create","update"}
* )
*/
private $person;
/**
* #ORM\OneToOne(targetEntity="Book", inversedBy="loan")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
*/
protected $book;
}
Here is how I am currently validating the loan entity
$loan = new Loan();
$loan->setPerson($person);
$loan->setBookId($id);
/** #var ConstraintViolation $error */
foreach ($this->get('validator')->validate($loan,null,['create'])->getIterator() as $index => $error) {
$errorMessages[] = $error->getMessage();
}
I figured maybe I can add a custom validator like this to the loan entity:
/**
* #Assert\IsTrue(message = "The book does not exist")
* #return bool
*/
public function isBookLegal(BookRepository $bookRepository)
{
return !$bookRepository->fetchById($this->book_id);
}
But I end up with the follow exception:
Type error: Too few arguments to function
AppBundle\Entity\Loan::isBookLegal(), 0 passed and exactly 1 expected
First of all, you should not have both $book_id and $book in your Loan entity. You should remove $book_id, which is enough for your entity relationship.
Then, all you need to do is add an #Assert\NotBlank() on $book:
use Symfony\Component\Validator\Constraints as Assert;
...
/**
* #ORM\OneToOne(targetEntity="Book", inversedBy="loan")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
* #Assert\NotBlank()
*/
protected $book;
I'm not sure what code you are using to get all of your loans, but as Edwin states that's not really good form. You want want something more like:
foreach ($loans as $loan) {
$errors = $this->get('validator')->validate($loan);
// do something here if there is an error
}
The assertion function you wrote isn't going to work because you can't pass in a value to your isBookLegal() function there, nor can you ever use the database connection/repository from within your Entity class.
I'm not really sure what you are trying to accomplish without greater context here. Doctrine is already going to validate your $book member because of your #ORM\OneToOne annotation in the first place. You don't have to perform any additional validation. I'm guessing you are trying to pass in a value directly to $book_id, which is incorrect. You should only be passing already-valid $book entities to your Loan class, via $loan->setBook(Book $book);
I'm building a simple web-service using Symfony 3, Doctrine 2.5 and stuck at ORM relations described below in simplified structure.
I have an Action entity containing many actions with ManyToOne relation...
class Action
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="\AppBundle\Entity\Status")
* #ORM\JoinColumn(referencedColumnName="code", nullable=false)
*/
private $status;
and the Status Entity with a few statuses.
class Status
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="integer", unique=true)
*/
private $code;
I cannot get proper way to set referencedColumnName="code" column (not 'Id' as usual) for Action entity.
Configured this way repo throws wxception at persist moment with "Notice: Undefined index: code";
I guess that it is mappedBy or inversedBy annotation parameter... but can't figure out "how".
Unfortunately it's not supported in Doctrine (reference).
You may edit your Status entity like this (ensure that code is set before persist):
class Status
{
/**
* #ORM\Column(name="code", type="integer", unique=true)
* #ORM\Id
*/
private $code;
}
If autoincremented field is your requirement you can take a look on this answer for possible solutions.
Just thought I'd add you can still use the non-primary keys as many to many, by using the entity itself as the join table. This will work but you still need to set your relationship keys correctly.
Example:
/**
* #ORM\Entity
*/
class Car {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\ManyToMany(targetEntity="Registration", mappedBy="Cars")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")}
* )
*/
public $Registrations;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
/**
* #ORM\Entity
*/
class Registration {
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(name="registration_code", type="text", length=128, nullable=false)
* #var string
*/
public $registrationCode;
/**
* #var ArrayCollection
* #ORM\ManyToMany(targetEntity="Car", mappedBy="Registrations")
* #ORM\JoinTable(name="car",
* joinColumns={#ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")},
* inverseJoinColumns={#ORM\JoinColumn(name="id", referencedColumnName="id")}
* )
*/
public $Cars;
public function __construct() {
$this->Cars = new ArrayCollection();
}
}
The upside is that it works fine as a workaround.
Keep in mind a few things:
it's a collection not a single instance;
column has to be managed manually on your end;
you must set up constraints correctly (indexes, keys, etc);
check your queries still perform!
There are three entities: Customer, Messages, Attachments.
The relationship between these entities is straight forward: A customer can have many messages and a message can have many attachments. Both relations are "one-to-many".
I told doctrine to be lazy when loading the messages for the Customer entity. So $customer->getMessages() results in an additional SQL statement. That's fine.
But I also defined an "EAGER" loading for the attachments for the Message entity.
Now I would have expected that the messages I get by calling $customer->getMessages() are already loaded with all their attachments. But $message->getAttachments() still causes one SQL statement per message.
Is this behavior expected?
Just for reference, excepts from my classes:
Customer.php
class Customer
{
/**
* #ORM\OneToMany(targetEntity="Message", mappedBy="customer")
* #ORM\OrderBy({"createdOn" = "DESC"})
*/
private $messages;
Message.php
class Message
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
**/
private $customer;
/**
* #ORM\OneToMany(targetEntity="Attachment", mappedBy="message", fetch="EAGER")
**/
private $attachments;
Attachment.php:
class Attachment
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Message", inversedBy="attachments")
* #ORM\JoinColumn(name="message_id", referencedColumnName="id")
**/
private $message;
It sounds like expected behavior to me. The doctrine documentation seems to imply that eager fetching is only one level deep.
According to the docs:
Whenever you query for an entity that has persistent associations and
these associations are mapped as EAGER, they will automatically be
loaded together with the entity being queried and is thus immediately
available to your application.
http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-eager-loading
The entity being queried in your case is customer and customer has eager on messages so messages are populated. Messages, however are not the object being queried, so attachments do not get loaded.
the correct code example might be like the following:
NOTE: fetch message with lazy loading, i.e. get messages with additional query proactively; as long as the messages are fetched from database, the corresponding attachments referenced to each message will be loaded automatically.
Customer
class Customer
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Message", mappedBy="customer", fetch="LAZY")
* #ORM\OrderBy({"createdOn" = "DESC"})
*/
private $messages;
Message
class Message
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
/**
* #ORM\OneToMany(targetEntity="Attchment", mappedBy="message", fetch="EAGER")
*/
private $attachments;
Attachment
class Attachment
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToONe(targetEntity="Message", inversedBy="attachments")
* #ORM\JoinColumn(name="message_id", referencedColumnName="id")
*/
private $message;
I am trying to set up some ManyToOne/OneToMany relationships on objects in my database using Doctrine (2.2.3+) via Symfony2 (2.3.0) and am getting a strange error. Here are the relevant parts of the objects (many attributes to one product):
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity
*/
class Product
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
...
/**
*
* #OneToMany(targetEntity="ProductAttributes", mappedBy="product")
*/
protected $product_attributes;
public function __construct() {
$this->product_attributes = new \Doctrine\Common\Collections\ArrayCollection();
}
}
/**
* ProductAttributes
*
* #ORM\Table(name="product_attributes")
* #ORM\Entity
*/
class ProductAttributes
{
/**
* #var integer
*
* #ORM\Column(name="pa_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $pa_id;
/**
* #var integer
*
* #ORM\Column(name="product_id", type="integer")
*/
protected $product_id;
...
/**
*
* #ManyToOne(targetEntity="Product", inversedBy="product_attributes")
* #JoinColumn(name="product_id", referencedColumnName="id")
*/
protected $product;
}
When I run the
php app/console doctrine:generate:entities BundleName
command I get the following error:
[Doctrine\Common\Annotations\AnnotationException]
[Semantical Error] The annotation "#OneToMany" in property LVMount\LVMBundle\Entity\Product::$product_attributes was never imported. Did you maybe forget to add a "use" statement for this annotation?
I have looked through the Doctrine docs and don't see any reference to a "use" statement for the ManyToOne/OneToMany pairings. What is going on?
Your annotations' syntax aren't complete.
You can see the proper syntax for any doctrine annotation below.
/**
* #ORM\********
*/
So, in your case it should look like the following.
/**
* #ORM\OneToMany(targetEntity="ProductAttributes", mappedBy="product")
*/
You will also want to fix the annotations in the ProductAttributes entity.
I'm having this issue with JMSSerializerBundle. It basically gives me an exception for something that I've already done. This is my entity:
Edited to avoid confusion about annotation lines
<?php
namespace My\ProjectBundle\Entity;
use JMS\SerializerBundle\Annotation\Type;
use Doctrine\ORM\Mapping as ORM;
/**
* My\ProjectBundle\Entity\Music
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="My\ProjectBundle\Entity\MusicRepository")
*/
class Music extends Post
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")
* #Type("string")
*/
protected $album;
/**
* #var string $artist
*
* #ORM\Column(name="artist", type="string")
* #Type("string")
*/
protected $artist;
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string")
* #Type("string")
*/
protected $title;
/**
* #var array $genres
*
* #ORM\Column(name="genres", type="array")
* #Type("array")
*/
protected $genres;
As you can see, I've added #Type() annotations for the fields, but it still gives me the exception when I call:
$listenedMusic = $serializer->deserialize($content, 'My\ProjectBundle\Entity\Music', 'json');
I've checked and the $content variable is not empty and has all the fields mapped in JSON format.
In my Monolog files, this is the exact Exception:
[2012-11-29 23:39:07] request.CRITICAL: JMS\SerializerBundle\Exception\RuntimeException:
You must define a type for My\ProjectBundle\Entity\Music::$album. (uncaught exception)
at /vendor/jms/serializer-bundle/JMS/SerializerBundle/Serializer/GenericDeserializationVisitor.php line 177
Why does it still give me this exception?
I'm fairly certain it's because you have two comment strings with different pieces of the whole annotation. Symfony only looks at the comment string directly preceding the class member.
Try replacing:
/** #Type("string")*/
/**
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
with:
/**
* #Type("string")
*
* #var string $album
*
* #ORM\Column(name="album", type="string")*/
protected $album;
(and in every other place you have these duplicate annotation comments)
It's only a guess, but I think it'll fix it. When I tried doing this:
class Something
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
/**
*
*/
private $id;
}
...Symfony gave me this error:
No identifier/primary key specified for Entity 'SomeApp\SomeBundle\Entity\Something'. Every Entity must have an identifier/primary key.
I have fixed this by updating my entire project to dev-master packages. It seemed it was a bug in JMSSerializer, because without modifying any code, I stopped getting this error.
/**
* #var integer $duration
*
* #ORM\Column(name="duration", type="bigint")
* #Type("int")
*/
protected $duration;
Type 'int' doesn't exist for serialization, you must use 'integer'.