September 13, 2013

Zend Framework 2: Integrate MongoDB By Doctrine ODM

ZF2 - Doctrine - MongoDB
Đang research để làm ứng dụng với MongoDB bằng ZF2. Ban đầu thì cũng không muốn dùng Doctrine cho lắm vì ám ảnh cái ORM MySQL của nó quá là mệt mỏi, khổ sở. Nên đã cố gắng mày mò cả mấy ngày trời để code với PHP extension, nhưng thật sự quá đuối. Có nhiều cái đuối, trong đó cái đuối to nhất chính là chưa có tẹo kinh nghiệm nào về MongoDB hết, nên thật sự là một khó khăn cho bản thân. Cũng qua nhiều nguồn tham khảo thì đều đánh giá ODM của Doctrine với MongoDB khá ổn, tốt, từ đó đi đến quyết định cuối sẽ xài qua Doctrine trước, khi nào có điều kiện và có thời gian hơn thì lại tiếp tục nghiên cứu. Bài viết chỉ mang tính chất ghi chú lại quá trình cài đặt.

Ở bài viết này, mình sử dụng composer phar để cài đặt lại ZF2, doctrine module ODM thay vì như những loạt bài trước. Sau khi mình cài xong bằng composer phar thì khoái luôn, vì muốn cài thêm cái gì cứ append vào và chạy lệnh. Rất nhanh so với cách thông thường.

Sau khi cài đặt xong ZF2, bạn mở tập tin composer.json để chỉnh sửa như đoạn bên dưới (nằm ngay trong thư mục gốc của project ZF2). Đây là một file dùng để cấu hình cài đặt cho composer phar.
{
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "minimum-stability": "dev",
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.2.*",
        "doctrine/doctrine-mongo-odm-module": "dev-master"
    }
}

Mọi người nên lưu ý dòng thứ 10 và dòng thứ 14 trong đoạn code bên trên. Dòng số 10 nếu như bạn quên sẽ không thể cài đặt được, mình đã bị dính chỗ này.

Tiếp theo, ra ngoài command line chạy lệnh sau (việc cài đặt thông qua composer phar bắt buộc cài đặt thông qua command line)
php composer.phar update

Chương trình sẽ tự động connect server và cài đặt, sau khi cài xong thì bạn sẽ tinh chỉnh 1 tí như sau.
Đầu tiên hết, bạn vào tập tin application.config.php (trong thư mục config của project) để bổ sung 2 module như sau
return array(
    'modules' => array(
        'Application',
        'DoctrineModule',
        'DoctrineMongoODMModule',
    ),
    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
    ),
);

Mọi người lưu ý dòng số 4,5 - đó là 2 module mới được thêm vào: DoctrineModule & DoctrineMongoODMModule. Bạn không bật cái này lên sẽ không chạy được ứng dụng ODM của Doctrine.

Tiếp theo, bạn copy file module.doctrine-mongo-odm.local.php.dist trong thư mục (zf2-project/vendor/doctrine/doctrine-mongo-odm-module/config) sang thư mục zf2-project/config/autoload và đổi tên lại thành module.doctrine-mongo-odm.local.php. Sau khi copy, bạn cần tinh chỉnh cấu hình connect server mongo như đoạn code bên dưới.
return array(
  'doctrine' => array(
    'connection' => array(
      'odm_default' => array(
        'server'   => 'localhost', // Mongo server host name OR IP
        'port'   => '27017', // Mongo server port
        'user'   => null,
        'password' => null,
        'dbname'   => 'eav',
        'options'  => array()
      ),
    ),
    'configuration' => array(
      'odm_default' => array(
        'metadata_cache'   => 'array',
        'driver'       => 'odm_default',
        'generate_proxies'   => true,
        'proxy_dir'      => 'data/DoctrineMongoODMModule/Proxy',
        'proxy_namespace'  => 'DoctrineMongoODMModule\Proxy',
        'generate_hydrators' => true,
        'hydrator_dir'     => 'data/DoctrineMongoODMModule/Hydrator',
        'hydrator_namespace' => 'DoctrineMongoODMModule\Hydrator',
        'default_db'     => null,
        'filters'      => array(), // array('filterName' => 'BSON\Filter\Class'),
        'logger' => null // 'DoctrineMongoODMModule\Logging\DebugStack'
      )
    ),
    'driver' => array(
      'odm_default' => array(
        'drivers' => array()
      )
    ),
    'documentmanager' => array(
      'odm_default' => array(
        'connection'  => 'odm_default',
        'configuration' => 'odm_default',
        'eventmanager'  => 'odm_default'
      )
    ),
    'eventmanager'  => array(
      'odm_default' => array(
        'subscribers' => array()
      )
    ),
  ),
);

Cuối cùng, bạn cần vào thư mục zf2-project/data để tạo thêm 2 cây thư mục như bên dưới, và nhớ phải cấu hình cho nó có quyền ghi (trên Windows khỏi quan tâm cái này).
Như vậy là xong việc cấu hình MongoDB ODM với Doctrine module
Xem thêm các bài viết khác về ZF2 - tại blog tmquang6805.blogspot.com

8 comments:

  1. Khi chạy lệnh "php composer.phar update"
    em gặp lỗi sau:
    "
    - doctrine/mongodb 1.0.x-dev requires ext-mongo >=1....
    - doctrine/mongodb 1.0.9 requires ext-mongo >=1.2.12,<1.6-dev -> the requested PHP extension mongo is missing from your system.
    - doctrine/mongodb 1.0.8 requires ....
    "
    anh có thể chỉ cho em nguyên nhân và cách giải quyết lỗi này không?

    ReplyDelete
  2. Trong đây nó nêu rõ lý do vì sao lỗi rồi đó em, chịu khó đọc tiếng Anh tí là biết thôi em. Chúc em vui

    ReplyDelete
  3. Chào bạn,

    Mình có câu hỏi về Doctrine ODM, mặc dù không liên quan gì nhiều tới topic của bạn, tuy nhiên chỉ có ở topic này bạn có nói đến ODM.

    Mình có mối quan hệ giữa Post & Comments.
    - Comment là embeded document của Post.
    - Mỗi Post có nhiều comments.

    Mình có nhu cầu lấy ra list comments được sort theo created date mới nhất của Post có ID = 1.

    Bạn cho mình hỏi, có cách nào để query bằng ODM ko.

    Thường thì mình giải quyết bằng cách query all Comment của Post có ID = 1, sau đó dùng PHP để sort lại, tuy nhiên điều này rất bất lợi nếu lượng comments của Post quá lớn.

    Nếu có giải pháp nào khác, nhờ bạn gợi ý giúp mình.

    Thanks,

    ReplyDelete
    Replies
    1. Chào bạn,

      Rất vui được làm quen. Thật tình thì mình chưa xài ODM bao giờ, sau khi mình tích hợp ODM của Doctrine vào ZF2 thì mình thấy nó còn chậm hơn nữa, nên thôi, code plain PHP luôn.

      Nhưng vấn đề của bạn thì trong MongoDB đã support rồi. Mình dùng trực tiếp MongoDB để nói đây luôn ha, ko dùng code PHP, bạn tự force lại theo ý mình hen :)

      Theo quan điểm cá nhân, bạn nên sorting ngay lúc insert thêm 1 comment mới vào post. Sau đó thì phần lấy lên cực kỳ nhẹ và đơn giản. Hãy nhớ điều này: tỉ lệ Read/Write => Read luôn luôn lớn hơn Write (đọc bài thì nhiều, nhưng comment được bao nhiêu ^^)

      Và để làm cái chuyện mình nói => bạn tham khảo công thức của MongoDB tại đây:
      http://docs.mongodb.org/manual/reference/operator/update/sort/

      Thanks bạn đã comment :)

      Delete
    2. Chào bạn,

      Cảm ơn vì bạn đã quan tâm & trả lời câu hỏi của mình.

      Sau đây là vấn đề mình đang gặp. Vd ở trên mình đưa ra để nêu lên 1 trường hợp cần giải quyết bằng cách sort 1 Embeded Document trong ODM (hay nói cách khác là sort 1 Collection trong MongoDB).

      Thực sự hướng giải quyết về Created đúng như bạn nói, mình cũng đang làm theo cách đó, sort ngay khi add vào db.

      Tuy nhiên mình gặp 1 vấn đề khá nan giải, đó là giả sử mỗi comment đều có 1 thuộc tính là view (mình vd vậy), giá trị view này hoàn toàn ko cố định, và vấn đề ở chỗ, có requirement bắt sort lại list comments (đã lưu & sort theo created) theo giá trị view này.

      Không biết với trường hợp trên, bạn có gợi ý or link tài liệu nào share giúp mình không, thực sự mình đã research rất nhiều, có thể do khả năng English không được tốt lắm nên tới giờ mình vẫn chưa tìm ra giải pháp.

      Thanks bạn nhìu :)

      Delete
    3. Mình nghĩ, có lẽ bạn đang mong muốn MongoDB nó làm tất tần tật về business cho bạn rồi. Mỗi bài toán đều có rất nhiều cách giải mà. Sao cứ phải là embed document, mà ko là reference document nhỉ.

      Mình chỉ gợi ý vậy thôi, còn bài toán thì bạn phải tự giải thôi ^^
      P/S: Không nên dùng embed document trong trường hợp của bạn đâu. Còn khi nào dùng embed document, reference document thì bạn xem cái note của mình nha

      http://tmquang6805.blogspot.com/2013/09/mongodb-something-to-note.html

      Delete
  4. Em chào anh, anh có thể cho e xin source phần này được không ạ, em tìm hiểu đến phần này thì bí cả tuần nay không có gỡ được. Em chạy composer.phar cứ lỗi hoài. Anh giúp em với

    ReplyDelete
  5. Mới bắt đầu nhập môn tìm hiểu mongodb trong zf2. Rất cảm ơn anh về bài viết này.

    ReplyDelete