2012-08-07 11 views
15

के साथ रिकर्सन से बचें मैं सिम्फनी 2, सिद्धांत, FOSRestBundle और JMSSerializer का उपयोग कर एक आरईएसटी एपीआई बना रहा हूं।सिद्धांत इकाइयों और JMSserializer

मेरे पास जो मुद्दा है, वह मेरी संस्थाओं को क्रमबद्ध करते समय, धारावाहिक किसी भी संबंधित संस्थाओं में खींचता है। एक ऐसे कार्य के लिए जो एक ऐसी कहानी का हिस्सा है जो बोर्ड का हिस्सा है, इसलिए जब कार्य को क्रमबद्ध करते हैं तो मुझे आउटपुट मिलता है जिसमें कहानी शामिल होती है जिसमें बोर्ड शामिल होता है, जिसमें बोर्ड पर अन्य सभी कहानियां शामिल होती हैं।

क्या इसे सीमित करने का कोई आसान तरीका है, और इसके बजाय केवल विदेशी आईडी शामिल करें?

+0

मुझे लगता है कि काफी एक ही सवाल बेन यहां पोस्ट की है: http://stackoverflow.com/questions/6706485/how-to-encode-doctrine-entities-to -जसन-इन-सिम्फनी-2-0-अजैक्स-एप्लिकेशन। आपको JMSSerializer का उपयोग करके कुछ जवाब मिलेंगे या नहीं। –

उत्तर

8

JMSSerializerBundle पर Serializer/Handler/DoctrineProxyHandler.php फ़ाइल देखें। अब, यदि आप इस पंक्ति पर टिप्पणी करते हैं:

public function serialize(VisitorInterface $visitor, $data, $type, &$handled) 
    { 
     if (($data instanceof Proxy || $data instanceof ORMProxy) && (!$data->__isInitialized__ || get_class($data) === $type)) { 
      $handled = true; 

      if (!$data->__isInitialized__) { 
       //$data->__load(); 
      } 

यह आपकी संस्थाओं को आलसी लोड करना बंद कर देगा। यदि आप यही चाहते हैं, तो बस आगे बढ़ें और create your own handler जहां आप आलसी लोड नहीं करते हैं।

यदि यह सही नहीं है, तो मैं अनुशंसा करता हूं कि आप अपने स्वाद पर JMSSerializerBundle को भेजने से पहले अपनी इकाइयों को कस्टमाइज़ करें। उदाहरण के लिए, किसी भी संबंधित संस्थाओं में मैं आईडी चाहता हूं, जबकि अन्य लोगों में मुझे कस्टम कॉलम नाम जैसे कोड, या नाम या कुछ भी चाहिए।

मैं सिर्फ अपनी इकाई वस्तु की एक प्रति बनाता हूं और फिर संबंधों के लिए आवश्यक फ़ील्ड प्राप्त करना शुरू करता हूं। फिर, मैं उस प्रतिलिपि को क्रमबद्ध करता हूं। JMSSerializerBundle आलसी भार नहीं होगा क्योंकि मैंने पहले से ही उचित फ़ील्ड प्रदान किए हैं।

+0

लगता है जैसे यह मेरे लिए काम कर सकता है, इस सप्ताह इस पर काम करने का मौका नहीं मिला है, लेकिन इस सप्ताहांत को देखेंगे। – wgcrouch

+0

कुछ महीने पहले ही यह पता लगाया गया है। धन्यवाद यह फाइलिंग। http://stackoverflow.com/questions/11575345/disable-doctrine-2-lazy-loading-when-using-jms-serializer –

17

जेएमएस बहिष्करण नीति का उपयोग करें।

उदाहरण पर श्रेणी इकाई है, जहां आप बच्चों और उत्पाद से संबंधित संस्थाओं को शामिल नहीं करना चाहते एनोटेशन का उपयोग शामिल होने के लिए: अधिक जानकारी के लिए JMSSerializer docs पर

use ... 
    JMS\SerializerBundle\Annotation\ExclusionPolicy, 
    JMS\SerializerBundle\Annotation\Exclude, 
    ...; 

/** 
* ... 
* @ExclusionPolicy("none") 
*/ 
class Category 
{ 
    /** 
    * ... 
    * @Exclude 
    */ 
    private $children; 

    /** 
    * ... 
    * @Exclude 
    */ 
    private $products; 

} 

देखो।

संपादित करें:

उदाहरण आप केवल डेटा है कि आप की जरूरत का चयन करने के आंशिक कीवर्ड का उपयोग कर सकते है। हालांकि, मैं नहीं कर सकता था, मेरे जीवन के लिए, पूर्ण संबंधित इकाइयों (दो स्तर नीचे) की लोडिंग को अक्षम करें यदि मैं धारावाहिक को इकाई ऑब्जेक्ट पास करता हूं (यहां तक ​​कि DoctrineProxyHandler में लोड अक्षम करते समय भी), लेकिन यदि मैं किसी सरणी का उपयोग करता हूं, यह प्रॉक्सी (हालांकि उम्मीद की गई) के रूप में सिद्धांत आलसी लोडिंग का उपयोग नहीं करता है।

उदाहरण अपने उदाहरण संस्थाओं का उपयोग कर:

$dql = "SELECT t, s, partial b.{id}, partial ss.{id} 
     FROM Acme\AppBundle\Entity\Task t 
     JOIN t.story s 
     JOIN s.board b 
     JOIN b.stories ss" 

$q = $this->_em-createQuery($dql); 

$result = $q->getArrayResult(); 

इस तरह से आप की तरह कुछ मिलेगा:

[ 
{ 
    id: 33, 
    title: "My Task", 
    story: [ 
    { 
     id: 554, 
     board: [ 
     { 
      id: 14, 
      stories: [ 
      { 
       id: 554 
      }, 
      { 
       id: 3424 
      }, 
      { 
       id: 3487 
      } 
      ] 
     } 
     ] 
    } 
    ] 

} 
] 

पी.एस. मैं वास्तव में इस "समस्या" से चिंतित हूं। वैसे भी मैं सरणी परिणाम का उपयोग किए बिना इकाई ऑब्जेक्ट को क्रमबद्ध करने के समाधान के साथ आना चाहूंगा।

+3

दोस्ताना अद्यतन: चूंकि [ver 0.11] (https://github.com/schmittjoh/JMSSerializerBundle/blob/master/UPGRADING.md#upgrading-from-010-to-011) JMS Seralizer कोर को बंडल से निकाला गया था 'JMS \ SerializerBundle \ Annotation \ ExclusionPolicy 'के बजाय यह' JMS \ Serializer \ Annotation \ ExclusionPolicy' और 'JMS \ SerializerBundle \ Annotation \ Exclude' होगा' JMS \ Serializer \ Annotation \ Exclude' होगा। –

9

बस JMSSerializer के नवीनतम संस्करण में एक अद्यतन, जगह आप पर है

JMS \ Serializer \ EventDispatcher \ सब्सक्राइबर \ DoctrineProxySubscriber

बजाय

Serializer \ हैंडलर \ DoctrineProxyHandler

दिखना चाहिए

डिफ़ॉल्ट आलसी लोड व्यवहार को ओवरराइड करने के लिए, किसी को अपना स्वयं का ईवेंट ग्राहक परिभाषित करना चाहिए। आपका \ बंडल \ घटना \ DoctrineProxySubscriber को

parameters: 
    ... 
    jms_serializer.doctrine_proxy_subscriber.class: Your\Bundle\Event\DoctrineProxySubscriber 

आप JMS \ Serializer \ EventDispatcher \ सब्सक्राइबर \ DoctrineProxySubscriber से वर्ग कॉपी कर सकते हैं और बाहर टिप्पणी $ वस्तु:

अपने ऐप्लिकेशन में/इस ऐड config.yuml -> __ लोड(); लाइन

public function onPreSerialize(PreSerializeEvent $event) 
{ 
    $object = $event->getObject(); 
    $type = $event->getType(); 

    // If the set type name is not an actual class, but a faked type for which a custom handler exists, we do not 
    // modify it with this subscriber. Also, we forgo autoloading here as an instance of this type is already created, 
    // so it must be loaded if its a real class. 
    $virtualType = ! class_exists($type['name'], false); 

    if ($object instanceof PersistentCollection) { 
     if (! $virtualType) { 
      $event->setType('ArrayCollection'); 
     } 

     return; 
    } 

    if (! $object instanceof Proxy && ! $object instanceof ORMProxy) { 
     return; 
    } 

    //$object->__load(); Just comment this out 

    if (! $virtualType) { 
     $event->setType(get_parent_class($object)); 
    } 
} 

अद्यतन: मैं क्रमबद्धता उपकरण के अपने खुद के सरलीकृत संस्करण लेखन समाप्त हो गया: है एक समारोह का आईडी चुनने के लिए https://github.com/dlin-me/array-converter-bundle

+1

मुझे यह समाधान पसंद है, हालांकि यह मेरे लिए काम नहीं कर रहा है। मैंने अपना खुद का डॉक्टरप्रोक्सीसस्क्राइबर बनाया और इसे सीरियलाइजेशन के दौरान इस्तेमाल किया, लेकिन कभी भी टिप्पणी की गई रेखा तक पहुंच नहीं पाती और हमेशा आलसी भार संबंधित इकाइयों तक पहुंच जाती है। मैं नहीं चाहता कि सीरियलाइज़र डीबी को प्रश्न पूछें, लेकिन दूसरी ओर मैं चाहता हूं कि यह पहले से ही प्राप्त डेटा को क्रमबद्ध करें। मैं किसी भी विचार के लिए आभारी होंगे। – Radzikowski

+0

मैंने लाइन $ ऑब्जेक्ट पर टिप्पणी की है -> __ लोड और चीजें ** ** ** जैसे कि मुझे इसकी आवश्यकता है ... अब यह 'id_thing लौटाता है: {id_thing: 1} 'ऑब्जेक्ट को दोहराएं .. क्या वापस करने का कोई तरीका है 'id_thing: 1' केवल? – KnF

+0

आह, एक और बात ... मैं सिम्फनी 2 का उपयोग नहीं कर रहा हूं .. बस जेएमएसएसरियलाइज़र और सिद्धांत .. मैं कस्टम ग्राहक कैसे बना सकता हूं? – KnF

0

यहाँ एक-से-एक या एक-से-कई एक में जुड़े संस्थाओं जुड़ने का उपयोग किए बिना सामान्य तरीका।

function selectWithAssociations($doctrine, $className) { 

    $em = $doctrine->getManager(); 
    $meta = $em->getClassMetadata($className); 

    //explicitly get IDs of associated entities 
    $assocClauses = array(); 
    foreach ($meta->getAssociationMappings() as $assocName => $assoc) { 
     if (isset($assoc['joinTable'])) { 
      //todo: doesn't handle many to many associations 
     } else { 
      $assocClauses[] = ", IDENTITY(e.$assocName) AS $assocName"; 
     } 
    } 

    //run custom DQL query 
    $q = $em->createQuery('SELECT e AS _d' . implode('', $assocClauses) . ' FROM ' . $className . ' e'); 
    $result = $q->getArrayResult(); 

    return $result; 
} 
0

यहाँ वर्ग जो एक या कई संगठनों जो JMS Serializer ExclusionStrategy के रूप में इस्तेमाल किया जा सकता की आलसी लोड हो रहा है को रोकने के लिए है।

use Doctrine\ORM\PersistentCollection; 
use Doctrine\ORM\Proxy\Proxy; 
use JMS\Serializer\Context; 
use JMS\Serializer\Exclusion\ExclusionStrategyInterface; 
use JMS\Serializer\Metadata\ClassMetadata; 
use JMS\Serializer\Metadata\PropertyMetadata; 
use JMS\Serializer\SerializationContext; 

/** 
* Class OnlyLoadedAssociationsExclusionStrategy 
* 
* http://stackoverflow.com/questions/11851197/avoiding-recursion-with-doctrine-entities-and-jmsserializer 
*/ 
class OnlyLoadedAssociationsExclusionStrategy implements ExclusionStrategyInterface 
{ 
    public function shouldSkipClass(ClassMetadata $metadata, Context $context) 
    { 
    } 

    public function shouldSkipProperty(PropertyMetadata $property, Context $context) 
    { 
     if ($context instanceof SerializationContext){ 
      $vistingSet=$context->getVisitingSet(); 

      //iterate over object to get last object 
      foreach ($vistingSet as $v){ 
       $currentObject=$v; 
      } 

      $propertyValue=$property->getValue($currentObject); 

      if ($propertyValue instanceof Proxy){ 
       // skip not loaded one association 
       if (!$propertyValue->__isInitialized__){ 
        return true; 
       } 
      } 

      if ($propertyValue instanceof PersistentCollection){ 
       // skip not loaded many association 
       if (!$propertyValue->isInitialized()){ 
        return true; 
       } 
      } 
     } 
     return false; 
    } 
} 

प्रयोग उदाहरण:

$serializationContext->addExclusionStrategy(
    new OnlyLoadedAssociationsExclusionStrategy() 
); 
+0

यहां पोस्ट किया गया: http://stackoverflow.com/questions/11575345/disable-doctrine-2-lazy-loading-when-using-jms-serializer –

+0

आपको कई प्रश्नों में उत्तर कॉपी और पेस्ट करना चाहिए। जब आप ऐसा करते हैं, [एक ध्वज स्वचालित रूप से मॉडरेटर ध्यान के लिए उठाया जाता है] (http://meta.stackoverflow.com/questions/270311/can-we-auto-flag-answers-that-are-clearly-copy-pasted/ 270,341 # 270,341)। इसके बजाए, प्रश्नों में से केवल एक दूसरे के डुप्लिकेट के रूप में। – CubeJockey

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