2017-06-29 89 views
2

我想能夠使用實體驗證約束來驗證,如果外鍵book_id是有效的,請參閱以下內容:Symfony的實體驗證驗證外鍵存在

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; 
} 

貸款.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; 
} 

這裏是我當前如何驗證貸款實體

$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(); 
    } 

我想也許我可以這樣添加自定義驗證的貸款實體:

/** 
* @Assert\IsTrue(message = "The book does not exist") 
* @return bool 
*/ 
public function isBookLegal(BookRepository $bookRepository) 
{ 
    return !$bookRepository->fetchById($this->book_id); 
} 

但我結束了與後續的例外:

Type error: Too few arguments to function 
AppBundle\Entity\Loan::isBookLegal(), 0 passed and exactly 1 expected 
+0

首先將foreach的第一個參數賦值給一個變量,然後在foreach中使用它,這只是討厭的。其次,當你打電話給你的'isBookLegal'時,你可以不帶參數地調用它 - 這就是爲什麼你會得到這個消息。 – Edwin

+0

但是,如何通過驗證觸發isBookLegal?換句話說,我該如何驗證將參數傳遞給此函數? – Freid001

回答

2

首先,你不應該您的Loan實體中都有$book_id$book。您應該刪除$book_id,這對您的實體關係來說已經足夠了。

然後,所有你需要做的就是添加一個@Assert\NotBlank()$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; 

我不知道您使用的是讓所有的貸款,什麼樣的代碼,但埃德溫的狀態,這不是真正的好形成。你要想要的東西更像:

foreach ($loans as $loan) { 
    $errors = $this->get('validator')->validate($loan); 
    // do something here if there is an error 
} 

你寫的斷言功能是行不通的,因爲你不能在一個價值傳遞給您的isBookLegal()功能那裏,沒有你就不使用數據庫連接/存儲庫從你的實體類中。

我不確定你在沒有更大的背景下試圖完成什麼。原則已經首先驗證您的$book成員,因爲您的@ORM\OneToOne註釋。您不必執行任何額外的驗證。我猜你正試圖直接將值傳遞給$book_id,這是不正確的。你只應該通過已有效的$book實體到你的Loan類,通過$loan->setBook(Book $book);

+0

感謝您的詳細解答,我想我很想理解理論實體關係如何工作。如果我刪除book_id,我應該在這裏設置什麼名字:@ORM \ JoinColumn(name =「book_id」,referencedColumnName =「id」) – Freid001

+0

哦,我想我現在看到了。所以我不需要隱式地將book_id設置爲一個類屬性,因爲教義會解決它需要按名稱指定添加該列。 – Freid001

+0

這是正確的。另請查看這裏:http://symfony.com/doc/current/doctrine/reverse_engineering.html如果您的數據庫已經創建,您可以讓Doctrine爲您自動生成所有實體。 –