2012-04-27 6 views
12

इसलिए मैंने सिद्धांत 2 माइग्रेशन (https://github.com/doctrine/migrations) का एक गुच्छा किया है, लेकिन मेरे पास एक नए माइग्रेशन के लिए एक प्रश्न है जो मैं कोशिश कर रहा हूं करने के लिए।

मैं लाइब्रेरी में थोड़ा खोद रहा हूं और मुझे लगता है कि $this->addSql() का उपयोग निष्पादित करने के लिए SQL की एक सूची बनाने के लिए किया जाता है और फिर इसे बाद में निष्पादित किया जाता है।

मैं कुछ ऐसा करना चाहता था जहां मैं कुछ डेटा चुनता हूं, पंक्तियों पर पुनरावृत्ति करता हूं, उस पर आधारित नया डेटा डालता हूं, और उसके बाद मैंने जो डेटा चुना है उसे हटा दें। यह खुद को डीबीएएल लाइब्रेरी में आसानी से उधार देता है, लेकिन मुझे आश्चर्य है, क्या मैं माइग्रेशन में protected $connection सुरक्षित रूप से उपयोग कर सकता हूं? या यह बुरा है क्योंकि यह मेरे $this->addSql() एसक्यूएल को निष्पादित करने से पहले बयान निष्पादित करेगा? ऐसा लगता है कि यह कोड में मैंने जो देखा है उससे dry-run सेटिंग तोड़ देगा। क्या किसी को इस तरह के माइग्रेशन के साथ कोई अनुभव है? क्या कोई सर्वोत्तम प्रथा है?

निम्न माइग्रेशन मैं क्या करना चाहते है, लेकिन मुझे विश्वास है नहीं है कि इस सिद्धांत माइग्रेशन के द्वारा समर्थित है कर रहा हूँ:

public function up(Schema $schema) 
{ 
    // this up() migration is autogenerated, please modify it to your needs 
    $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql"); 

    $this->addSql("ALTER TABLE article_enclosures ADD is_scrape TINYINT(1) NOT NULL"); 
    $this->addSql("ALTER TABLE images DROP FOREIGN KEY FK_E01FBE6AA536AAC7"); 

    // now lets take all images with a scrape and convert the scrape to an enclosure 
    // 
    // Select all images where not scrape_id is null (join on article_image_scrape) 
    // for each image: 
    //  insert into article_enclosures 
    //  update image set enclosure_id = new ID 
    //  delete from article_image_scrape where id... 
    // 
    // insert into article_enclosures select article_image_scrapes... 

    $sql = "SELECT i.id img_id, e.* FROM images i JOIN article_image_scrapes e ON i.scrape_id = e.id"; 
    $stmt = $this->connection->prepare($sql); 
    $stmt->execute(); 
    $scrapesToDelete = array(); 
    while ($row = $stmt->fetch()) { 
     $scrapeArticle = $row['article_id']; 
     $scrapeOldId = $row['id']; 
     $scrapeUrl = $row['url']; 
     $scrapeExtension = $row['extension']; 
     $scrapeUrlHash = $row['url_hash']; 
     $imageId = $row['image_id']; 

     $this->connection->insert('article_enclosures', array(
      'url' => $scrapeUrl, 
      'extension' => $scrapeExtension, 
      'url_hash' => $scrapeUrlHash 
     )); 

     $scrapeNewId = $this->connection->lastInsertId(); 

     $this->connection->update('images', array(
      'enclosure_id' => $scrapeNewId, 
      'scrape_id' => null 
     ), array(
      'id' => $imageId 
     )); 

     $scrapesToDelete[] = $scrapeOldId; 
    } 

    foreach ($scrapesToDelete as $id) { 
     $this->connection->delete('article_image_scrapes', array('id' => $id)); 
    } 

    $this->addSql("INSERT INTO article_scrapes (article_id, url, extension, url_hash) " 
      ."SELECT s.id, s.url, s.extension, s.url_hash" 
      ."FROM article_image_scrapes s"); 

    $this->addSql("DROP INDEX IDX_E01FBE6AA536AAC7 ON images"); 
    $this->addSql("ALTER TABLE images DROP scrape_id, CHANGE enclosure_id enclosure_id INT NOT NULL"); 
} 
+0

मैं बस से पहले और आवश्यक के साथ 'यह एक के बाद अलग माइग्रेशन करने के लिए फैसला किया है के साथ और भी बेहतर है कि दिखाने के addSql' कॉल करता है ताकि ऑर्डर सही हो। – Matt

+0

क्या आपने इसे आजमाया है? मुझे ठीक लगता है – eddy147

+0

मुझे ऐसा लगता है, लेकिन यह एक साल पहले था। मेरा मानना ​​है कि मूल मुद्दा अभी भी खड़ा है। यही है, '-> addSql()' कॉल का उपयोग करके, उनको अंतिम रूप से निष्पादित किया जाएगा। और 'ड्राई-रन' अभी भी आपके प्रत्यक्ष हेरफेर को चलाएगा। तो यह अभी भी हैकी लगता है (लेकिन मैं गलत हो सकता था, कभी जवाब नहीं मिला और मुझे इसके बारे में और कुछ याद नहीं है)। – Matt

उत्तर

11

आप इस

$result = $this->connection->fetchAssoc('SELECT id, name FROM table1 WHERE id = 1'); 
$this->abortIf(!$result, 'row with id not found'); 
$this->abortIf($result['name'] != 'jo', 'id 1 is not jo'); 
// etc.. 

तरह $connection उपयोग कर सकते हैं आप केवल डेटाबेस को पढ़ना चाहिए और अपडेट/डिलीट करने के लिए कनेक्शन का उपयोग नहीं करना चाहिए ताकि यह ड्राई-रन विकल्प को तोड़ न सके।

आपके उदाहरण में, आपको दो माइग्रेशन करना चाहिए। पहला दो बदलाव तालिका करेगा। दूसरा "स्क्रैप वाली छवियों और स्क्रैप को एक संलग्नक में परिवर्तित करेगा" दिनचर्या करेगा। यदि कुछ गलत हो जाता है तो एकाधिक माइग्रेशन का उपयोग करना उन्हें वापस करना आसान है।

8

FYI करें, नवीनतम डॉक्स इस उदाहरण एक "postUp" विधि

http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html

// ... 
use Symfony\Component\DependencyInjection\ContainerAwareInterface; 
use Symfony\Component\DependencyInjection\ContainerInterface; 

class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface 
{ 

    private $container; 

    public function setContainer(ContainerInterface $container = null) 
    { 
     $this->container = $container; 
    } 

    public function up(Schema $schema) 
    { 
     // ... migration content 
    } 

    public function postUp(Schema $schema) 
    { 
     $em = $this->container->get('doctrine.orm.entity_manager'); 
     // ... update the entities 
    } 
} 
+5

मैं यह जोड़ना चाहता हूं कि आपको डॉक्टर माइग्रेशन पर्यावरण में 'EntityManager' से निपटने पर सावधान रहना चाहिए। EntityManager वर्तमान इकाई परिभाषाओं का उपयोग करेगा जो मूल माइग्रेशन में उपयोग किए गए लोगों से भिन्न हो सकते हैं। मैं माइग्रेशन में EntityManager का उपयोग करने से बचना चाहता हूं। – SteveB

+0

@SteveB शायद 'डीबीएएल' परत का उपयोग कर एक समाधान हो सकता है। हमारे पास संपत्ति 'कनेक्शन' तक पहुंच है जो एक '\ Doctrine \ DBAL \ कनेक्शन' –

+1

@AdrienG हाँ है, मेरी टिप्पणी 'EntityManager' को शॉर्टकट के रूप में उपयोग करने के मुद्दे के बारे में अधिक है। हालांकि यह बिल्कुल ठीक दिखता है, यह नहीं है। यह लाइन के नीचे मुद्दों का कारण बन जाएगा जब कोई अंततः इकाई परिभाषा को अद्यतन करेगा। किसी भी चीज का उपयोग सीधे आवेदन की वर्तमान स्थिति से संबंधित नहीं है पूरी तरह से ठीक आईएमओ है। – SteveB

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