2012-11-12 8 views
26

में एक ई-नोटिस का कारण बन जाएगा सिम्फनी 2 प्रोजेक्ट के लिए मुझे ब्लॉग पोस्ट और तथाकथित प्लेटफ़ॉर्म के बीच संबंध बनाना था। एक प्लेटफ़ॉर्म साइट पर देखने के लिए उपयोग किए जाने वाले डोमेन के आधार पर एक विशिष्ट फ़िल्टर को परिभाषित करता है। उदाहरण के लिए: यदि आप url first-example.com द्वारा साइट में शामिल होते हैं, तो साइट केवल ब्लॉग पोस्ट प्रदान करेगी, जो इस विशिष्ट प्लेटफॉर्म से जुड़े हुए हैं।एंटीटी रिपोजिटरी :: findBy() का उपयोग कई से कई रिश्ते के साथ डॉक्टर

ऐसा करने के लिए, मैंने दो इकाइयां पोस्ट और प्लेटफार्म बनाई। बाद में मैंने उन्हें कई से कई रिश्ते के साथ मैप किया। मैं बिल्टिन फ़ंक्शन findBy() से डॉक्टरों के EntityRepository में इस से कई से कई रिश्तों के माध्यम से डेटा पुनर्प्राप्त करने का प्रयास कर रहा हूं।

// 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)); 

कहाँ $postRepoPost इकाई और $platform एक मौजूदा 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 पुनः प्राप्त करना संभव है, या हूँ मैं अपने आप से इन कार्यों लिखने के लिए मजबूर कर दिया? अजीब चीज यह है: सिद्धांत किसी भी त्रुटि को फेंक नहीं देगा: "यह संभव नहीं है।", लेकिन एक आंतरिक E_NOTICE। Thats क्यों मुझे लगता है कि यह संभव होना चाहिए, लेकिन मुझे कुछ बिंदु याद आ रही है।

दिलचस्प भागों में फिसल गया, दोनों इकाइयां इस तरह दिखती हैं।

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

या प्लेटफ़ॉर्म ऑब्जेक्ट में डिफ़ॉल्ट गेटर विधियों का उपयोग करें।

$posts = $platform->getPosts(); 

आप "दिलचस्प भागों के लिए नीचे छीन लिया" तो यह स्पष्ट करता है, तो आप इस विधि की जरूरत नहीं है, लेकिन यह सामान्य रूप से

app/console doctrine:generate:entities 
+0

अपने जवाब के लिए धन्यवाद। बस थोड़ा सा जोड़ा। आपकी पहली विधि कस्टम रिपोजिटरी में अपना फ़ंक्शन लिख रही है। मैंने खुद को अस्पष्ट व्यक्त किया हो सकता है लेकिन मैंने संबंधित संस्थाओं को अंतर्निहित 'find *() 'सिद्धांत के कार्य के माध्यम से लाने की कोशिश की। दूसरी विधि काम नहीं करती है क्योंकि मेरे पास एक यूनी-दिशात्मक संघ है। इसलिए 'प्लेटफार्म' पर कोई संपत्ति '$ पोस्ट' नहीं है और इसके कारण, कोई गेटर और सेटर्स नहीं हैं। फिर भी आपका जवाब मुझे बहुत मदद करता है, क्योंकि अब मैं और अधिक निश्चित हूं कि फ़िल्टर करने के लिए अंतर्निहित तरीकों का उपयोग करना संभव नहीं है। – devsheeep

1

इस सवाल पर किया जाता है लगता है एक ManyToMany संबंध के साथ एक समस्या है कि कौन सा बिडरेक्शनल चाहते हैं (और अब अनियंत्रित है)। bidirectionality बनाने के लिए MappedBy का उपयोग करें:

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

प्रैक्टिकल:

अपने संस्थाओं के एक तरफ के मालिक है, अन्य व्युत्क्रम पक्ष। पोस्ट नामक आपकी उदाहरण इकाई में पक्ष का स्वामित्व है, और प्लेटफार्म नाम की इकाई विपरीत पक्ष है।

मालिक पक्ष स्थापना:

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

व्युत्क्रम पक्ष सेटअप:

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

एक और तरीका है, शायद आईडी का उपयोग किये बिना थोड़ा ओओ/क्लीनर:

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

एक बेहतर तरीका नाम होगा findPostsByPlatform

+1

बहुत बढ़िया, इसे डॉक्टर डॉक्स में नहीं देखा है। प्रदर्शन के बारे में क्या? – Nevertheless

+2

यदि आप प्रदर्शन के बारे में परवाह करते हैं तो QueryBuilder का उपयोग न करें, न तो एक ओआरएम। – jhvaras

+1

मैं मानता हूं कि आपका नाम अधिक वर्णनात्मक है, लेकिन मैं 'खोज' से शुरू होने वाले सिद्धांतों के जादू-जैसे कार्यों के कारण कस्टम नामों में 'ढूंढ' का उपयोग करने से बचना पसंद करता हूं। getPostsByPlatform()। – Lighthart

संबंधित मुद्दे