2012-11-12 4 views
26

Symfony2 프로젝트의 경우 블로그 게시와 소위 플랫폼 간의 관계를 만들어야했습니다. 플랫폼은 사이트를 보는 데 사용하는 도메인을 기반으로 특정 필터를 정의합니다. 예 : url first-example.com으로 사이트에 가입하면이 사이트는이 특정 플랫폼에 연결된 블로그 게시물 만 제공합니다.다 대 다 관계로 EntityRepository :: findBy()를 사용하면 Doctrine에서 E_NOTICE가됩니다.

이렇게하려면 게시 및 플랫폼이라는 두 개의 엔티티를 만들었습니다. 이후에 다 대 다 (Many-To-Many) 관계로 매핑했습니다. Doctrines의 EntityRepository에있는 내장 함수 findBy()에서이 다 대 다 관계를 통해 데이터를 검색하려고합니다. $postRepoPost 개체와 $platform 기존 Platform 개체에 대한 올바른 저장소입니다

// every one of these methods will throw the same error 
$posts = $postRepo->findBy(array('platforms' => array($platform))); 
$posts = $postRepo->findByPlatforms($platform); 
$posts = $postRepo->findByPlatforms(array($platform)); 

. 나는 다음과 같은 오류 치울 :

ErrorException: Notice: Undefined index: joinColumns in [...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1495 

[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1495 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1452 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1525 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:1018 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php:842 
[...]/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:157 
[...]/src/Foobar/BlogBundle/Tests/ORM/PostTest.php:102 

은 다 대다 관계를이 방법으로 관련 entites를 검색 할 경우에도 가능을, 또는 나 자신에 의해이 함수를 작성하도록 강요 오전
어느 쪽이든? 이상한 점은 Doctrine은 "불가능합니다."와 같은 오류는 발생하지 않지만 내부는 E_NOTICE입니다. 그게 가능해야한다고 생각하는 텐트인데, 여기에 몇 가지 요점이 빠져 있습니다.

흥미로운 부분으로 분리 된 두 엔티티는 다음과 같습니다.

<?php 

namespace Foobar\CommunityBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\ORM\Mapping as ORM; 

// [...] other namespace stuff 

/** 
* @ORM\Entity(repositoryClass="Foobar\CommunityBundle\Entity\Repository\PlatformRepository") 
* @ORM\Table(name="platforms") 
*/ 
class Platform 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    // [...] other field stuff 
} 
<?php 

namespace Foobar\BlogBundle\Entity; 

use Doctrine\Common\Collections\ArrayCollection; 
use Doctrine\ORM\Mapping as ORM; 

// [...] other namespace stuff 

/** 
* @ORM\Entity(repositoryClass="Foobar\BlogBundle\Entity\Repository\PostRepository") 
* @ORM\Table(name="posts") 
*/ 
class Post implements Likeable, Commentable, Taggable, PlatformAware 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\ManyToMany(targetEntity="Foobar\CommunityBundle\Entity\Platform", cascade={"persist"}) 
    * @ORM\JoinTable(name="map_post_platform", 
    *  joinColumns={@ORM\JoinColumn(name="post_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="platform_id", referencedColumnName="id")} 
    *  ) 
    */ 
    protected $platforms; 

    // [...] other fields 

    /** 
    * Constructor 
    */ 
    public function __construct() 
    { 
     // [...] 
     $this->platforms = new ArrayCollection(); 
    } 
} 

물론 (뿐만 아니라 관련 라인까지 제거)을 composer.json 파일의

{ 
    [...] 
    "require": { 
     "php": ">=5.3.3", 
     "symfony/symfony": "2.1.*", 
     "doctrine/orm": ">=2.2.3,<2.4-dev", 
     "doctrine/doctrine-bundle": "1.0.*", 
     "doctrine/doctrine-fixtures-bundle": "dev-master", 
     [...] 

    }, 
    [...] 
} 

답변

19

그것은 매우 가능하지만, 주식 교리 저장소가 이런 식으로 작동하지 않습니다 .

당신은 당신의 상황에 따라, 두 가지 옵션이 있습니다

리포지토리에서 사용자 지정 방법을 작성합니다.

class PostRepository extends EntityRepository 
{ 
    public function getPosts($id) 
    { 
    $qb = $this->createQueryBuilder('p'); 
    $qb->join('p.platform', 'f') 
     ->where($qb->expr()->eq('f.id', $id)); 
    return $qb; 
    } 
} 

또는 플랫폼 개체에서 기본 getter 메서드를 사용하십시오.

$posts = $platform->getPosts(); 

ManyToMany 관계에 문제가 보인다이 방법이 있다면 그것은 분명하지 있도록 "흥미로운 부분을 벗었"하지만 일반적으로

app/console doctrine:generate:entities 
+0

findPostsByPlatform이 답변 주셔서 감사합니다 것입니다. 조금만 더. 첫 번째 방법은 사용자 지정 저장소에 자체 함수를 작성하는 것입니다. 나 자신을 불분명하게 표현했을지 모르지만 Doctrine에 내장 된'find *()'함수를 통해 관련 엔티티를 가져 오려고했습니다. 단방향 연결이 있기 때문에 두 번째 방법은 작동하지 않습니다. 그러므로'Platform'에'$ posts' 속성이 없기 때문에 getter와 setter가 없습니다. 그럼에도 불구하고 여러분의 대답은 많은 도움이됩니다. 이제는 필터링 된 many-to-many 연관을 얻기 위해 내장 된 방법을 사용할 수 없다는 것을 확신합니다. – devsheeep

1

이 질문에 만들어지는 당신을 BIDIRECTIONAL을 원합니다. (현재 UNDIRECTRIONAL입니다.) 양방향성을 만들 MappedBy를 사용

http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#many-to-many-bidirectional

실용 : 당신 실체의

한 쪽을 소유하고, 다른 역 SIDE. Post라는 이름의 엔티티에서 소유하는 쪽이 소유이고 Platform이라는 엔티티가 반대쪽입니다.

소유 SIDE 설정 :

Class Post { 
    ...  
    /** 
    * @ManyToMany(targetEntity="Platform") 
    * @JoinTable(name="map_post_platform", 
    *  joinColumns={@JoinColumn(name="post_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@JoinColumn(name="platform_id", referencedColumnName="id", unique=true)}) 
    **/ 
    protected $platforms; 
    ... 
    public function Post() { 
     $this->platforms= new ArrayCollection(); 
    } 
    ... 
    public function assignToPlatform($platform) { 
     $this->platforms[] = $platform; 
    } 
    ... 
    public function getPlatforms() { 
     return $this->platforms; 
    } 
} 

역 SIDE 설정 : 측면 중 하나에서 시작 개체의 배열, 검색

Class Platform { 
    ... 
    /** 
    * @ManyToMany(targetEntity="Post", mappedBy="platforms") 
    **/ 
    protected $posts; 
    ... 
    public function Platform() { 
     $this->posts= new ArrayCollection(); 
    } 
    ... 
    public function getPosts() 
    { 
     return $this->posts; 
    } 
} 

예 :

$post->getPlatforms(); 
$platform->getPosts(); 
+0

이것은 이러한 목적에 적합한 해결책입니다. –

28

또 다른 방법은, 어쩌면 ID를 사용하지 않고 OO/클리너가 약간 있음 :

public function getPosts(Platform $platform) 
{ 
    $qb = $this->createQueryBuilder("p") 
     ->where(':platform MEMBER OF p.platforms') 
     ->setParameters(array('platform' => $platform)) 
    ; 
    return $qb->getQuery()->getResult(); 
} 

더 나은 방법 이름은

+1

신난다. 교리 문서에서 본 적이 없다. 실적은 어떻습니까? – Nevertheless

+2

성능에 신경 쓰면 QueryBuilder를 사용하지 말고 ORM을 사용하지 마십시오. – jhvaras

+1

나는 당신의 이름이 더 잘 설명 할 수 있다는 것에 동의하지만, 나는 'find'로 시작하는 Doctrine의 마법 같은 기능 때문에 'find'를 사용자 정의 이름으로 사용하지 않는 것을 선호한다. getPostsByPlatform(). – Lighthart