ODM Phalcon (Object-Document Mapper)

Selain kemampuannya untuk memetakan tabel dalam database relasional, Phalcon dapat memetakan dokumen dari database NoSQL. ODM Phalcon menawarkan fungsi CRUD, event, validasi pada layanan lainnya.

Karena tidak adanya query SQL dan perencana, database NoSQL lebih terlihat dalam perbaikan kinerja menggunakan pendekatan Phalcon. Selain itu, tidak ada builder SQL sehingga mengurangi kemungkinan suntikan SQL.

Database NoSQL berikut ini didukung:

Nama Deskripsi
MongoDB MongoDB adalah database NoSQL scalable, kinerja tinggi,  open source .

Membuat Model 

Sebuah model adalah class yang extend dari Phalcon \ MVC \ Collection . Class Ini harus ditempatkan di direktori model. Sebuah model file harus berisi satu kelas; nama kelas harus dalam notasi camel-case:

<?php

class Robots extends \Phalcon\Mvc\Collection
{

}

Jika Anda menggunakan PHP 5.4/5.5 dianjurkan mendeklarasikan setiap kolom yang menjadi bagian dari model untuk menghemat memori dan mengurangi alokasi memori.

Model default “Robot” akan mengacu pada koleksi “robot”. Jika Anda ingin secara manual menentukan nama lain untuk pemetaan koleksi , Anda dapat menggunakan metode getSource():

<?php

class Robots extends \Phalcon\Mvc\Collection
{
    public function getSource()
    {
        return "the_robots";
    }
}

Memahami Document To Object 

Setiap instance dari model merupakan dokumen dalam koleksi. Anda dapat dengan mudah mengakses data pada koleksi dengan membaca properti obyek. Sebagai contoh, untuk koleksi “robot” dengan dokumen:

$ mongo test
MongoDB shell version: 1.8.2
connecting to: test
> db.robots.find()
{ "_id" : ObjectId("508735512d42b8c3d15ec4e1"), "name" : "Astro Boy", "year" : 1952,
    "type" : "mechanical" }
{ "_id" : ObjectId("5087358f2d42b8c3d15ec4e2"), "name" : "Bender", "year" : 1999,
    "type" : "mechanical" }
{ "_id" : ObjectId("508735d32d42b8c3d15ec4e3"), "name" : "Wall-E", "year" : 2008 }
>

Model dgn Namespace 

Namespace dapat digunakan untuk menghindari tabrakan nama kelas. Dalam hal ini perlu untuk menyebutkan nama dari koleksi yg dikaitkan menggunakan getSource:

<?php

namespace Store\Toys;

class Robots extends \Phalcon\Mvc\Collection
{

    public function getSource()
    {
        return "robots";
    }

}

Anda dapat menemukan dokumen tertentu dengan id dan kemudian mencetak namanya:

<?php

// Find record with _id = "5087358f2d42b8c3d15ec4e2"
$robot = Robots::findById("5087358f2d42b8c3d15ec4e2");

// Prints "Bender"
echo $robot->name;

Setelah record ini dalam memori, Anda dapat membuat modifikasi data dan kemudian menyimpan perubahan:

<?php

$robot = Robots::findFirst(array(
    array('name' => 'Astroy Boy')
));
$robot->name = "Voltron";
$robot->save();

Seting Koneksi 

Koneksi diambil dari wadah layanan. Secara default, Phalcon mencoba untuk menemukan koneksi dalam sebuah layanan yang disebut “mongo”:

<?php

// Simple database connection to localhost
$di->set('mongo', function() {
    $mongo = new MongoClient();
    return $mongo->selectDB("store");
}, true);

// Connecting to a domain socket, falling back to localhost connection
$di->set('mongo', function() {
    $mongo = new MongoClient("mongodb:///tmp/mongodb-27017.sock,localhost:27017");
    return $mongo->selectDB("store");
}, true);

Mencari Dokumen 

Karena Phalcon \ MVC \ Collection bergantung pada ekstensi PHP Mongo, Anda memiliki fasilitas yang sama untuk query dokumen dan mengkonversikannya secara transparan untuk instance model:

<?php

// How many robots are there?
$robots = Robots::find();
echo "There are ", count($robots), "\n";

// How many mechanical robots are there?
$robots = Robots::find(array(
    array("type" => "mechanical")
));
echo "There are ", count($robots), "\n";

// Get and print mechanical robots ordered by name upward
$robots = Robots::find(array(
    array("type" => "mechanical"),
    "sort" => array("name" => 1)
));

foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Get first 100 mechanical robots ordered by name
$robots = Robots::find(array(
    array("type" => "mechanical"),
    "sort" => array("name" => 1),
    "limit" => 100
));

foreach ($robots as $robot) {
   echo $robot->name, "\n";
}

Anda juga bisa menggunakan metode FindFirst () untuk mendapatkan hanya record pertama yang cocok dengan kriteria yang diberikan:

<?php

// What's the first robot in robots collection?
$robot = Robots::findFirst();
echo "The robot name is ", $robot->name, "\n";

// What's the first mechanical robot in robots collection?
$robot = Robots::findFirst(array(
    array("type" => "mechanical")
));
echo "The first mechanical robot name is ", $robot->name, "\n";

Baik metode find() dan findFirst() menerima array asosiatif untuk menentukan kriteria pencarian:

<?php

// First robot where type = "mechanical" and year = "1999"
$robot = Robots::findFirst(array(
    "conditions" => array(
        "type" => "mechanical",
        "year" => "1999"
    )
));

// All virtual robots ordered by name downward
$robots = Robots::find(array(
    "conditions" => array("type" => "virtual"),
    "sort"       => array("name" => -1)
));

Opsi query yang tersedia adalah:

Parameter Deskripsi Contoh
conditions Pencarian kondisi untuk operasi find. Digunakan untuk mengekstrak hanya record yang memenuhi kriteria tertentu. Secara default Phalcon_model mengasumsikan parameter pertama adalah kondisi. “conditions” => array (‘$gt’ => 1990)
fields Mengembalikan kolom tertentu, bukannya semua kolom dalam koleksi. Bila menggunakan opsi ini obyek yang tidak lengkap dikembalikan “Ladang” => array (‘name’ => true)
sort Ini digunakan untuk mengurutkan ResultSet.   Menggunakan satu atau lebih kolom sebagaimana setiap elemen dalam array, 1 berarti mengurutkan upward, -1 downwards “Order” => array (“name” => -1, “status” => 1)
limit Batasi hasil query untuk hasil ke kisaran tertentu “Limit” => 10
skip Melompati sejumlah hasil “Skip” => 50

Jika Anda memiliki pengalaman dengan database SQL, Anda mungkin ingin memeriksa SQL to Mongo Mapping Chart.

Agregasi 

Sebuah model dapat mengembalikan hasil perhitungan dengan menggunakan aggregation framework yg disediakan oleh Mongo. Nilai agregasi tsb dihitung tanpa harus menggunakan MapReduce. Dengan opsi ini lebih mudah melakukan tugas-tugas seperti total atau rata-rata pada kolom:

<?php

$data = Article::aggregate(array(
    array(
        '$project' => array('category' => 1)
    ),
    array(
        '$group' => array(
            '_id' => array('category' => '$category'),
            'id' => array('$max' => '$_id')
        )
    )
));

Create/Updating Record 

Metode Phalcon\MVC\Collection::save() membantu Anda untuk create / update dokumen melihat apakah sudah ada dalam koleksi yang berhubungan dengan model. Metode ‘save’ dipanggil internal oleh metode create dan update pada Phalcon \ MVC \ Collection .

Dan juga metode akan mengeksekusi validator terkait dan event yang didefinisikan dalam model:

<?php

$robot       = new Robots();
$robot->type = "mechanical";
$robot->name = "Astro Boy";
$robot->year = 1952;
if ($robot->save() == false) {
    echo "Umh, We can't store robots right now: \n";
    foreach ($robot->getMessages() as $message) {
        echo $message, "\n";
    }
} else {
    echo "Great, a new robot was saved successfully!";
}

Properti “_id” secara otomatis diperbarui dengan objek MongoId  yang diciptakan oleh driver:

<?php

$robot->save();
echo "The generated id is: ", $robot->getId();

Pesan Validasi 

Phalcon \ MVC \ Collection memiliki messaging subsistem yang menyediakan cara yang fleksibel untuk membuat atau menyimpan pesan validasi yg dihasilkan selama proses insert / update.

Setiap pesan terdiri dari sebuah instance dari class Phalcon \ MVC \ Model \ Message. Himpunan pesan yang dihasilkan dapat diambil dengan metode getMessages(). Setiap pesan berisi informasi lengkap seperti nama field yang dihasilkan pesan atau jenis pesan:

<?php

if ($robot->save() == false) {
    foreach ($robot->getMessages() as $message) {
        echo "Message: ", $message->getMessage();
        echo "Field: ", $message->getField();
        echo "Type: ", $message->getType();
    }
}

Event Validasi dan Event Manajer 

Model membantu Anda untuk menerapkan event yang akan dipicu jika Anda melakukan insert atau update. Event tsb membantu mendefinisikan aturan bisnis untuk model tertentu. Berikut ini adalah event yang didukung oleh Phalcon \ MVC \ Collection dan urutan eksekusi:

Operasi Nama Bisa menghentikan operasi? Penjelasan
Inserting/ Update beforeValidation YES Dijalankan sebelum proses validasi dan final insert / update ke database
Inserting beforeValidationOnCreate YES Dijalankan sebelum proses validasi hanya ketika operasi penyisipan
Update beforeValidationOnUpdate YES Dijalankan sebelum bidang divalidasi untuk tidak nulls atau kunci asing ketika operasi update
Inserting / Update onValidationFails YES (sudah berhenti) Dijalankan sebelum proses validasi hanya ketika operasi penyisipan
Inserting afterValidationOnCreate YES Dijalankan setelah proses validasi ketika operasi penyisipan
Update afterValidationOnUpdate YES Dijalankan setelah proses validasi ketika operasi update
Inserting / Update afterValidation YES Dijalankan setelah proses validasi
Inserting / Update beforeSave YES Berjalan sebelum operasi diperlukan selama sistem database
Update beforeUpdate YES Berjalan sebelum operasi diperlukan selama sistem database hanya ketika sebuah operasi update
Inserting beforeCreate YES Berjalan sebelum operasi diperlukan selama sistem database hanya jika operasi memasukkan
Update AfterUpdate NO Berjalan setelah operasi diperlukan selama sistem database hanya ketika sebuah operasi update
Inserting afterCreate NO Berjalan setelah operasi diperlukan selama sistem database hanya jika operasi memasukkan
Inserting / Update afterSave NO Berjalan setelah operasi diperlukan selama sistem database

Untuk membuat model bereaksi terhadap suatu event, kita harus membuat metode dengan nama yang sama dari event:

<?php

class Robots extends \Phalcon\Mvc\Collection
{

    public function beforeValidationOnCreate()
    {
        echo "This is executed before creating a Robot!";
    }

}

Event dapat berguna untuk menetapkan nilai-nilai sebelum melakukan operasi, misalnya:

<?php

class Products extends \Phalcon\Mvc\Collection
{

    public function beforeCreate()
    {
        // Set the creation date
        $this->created_at = date('Y-m-d H:i:s');
    }

    public function beforeUpdate()
    {
        // Set the modification date
        $this->modified_in = date('Y-m-d H:i:s');
    }

}

Selain itu, komponen ini terintegrasi dengan Phalcon \ Events \ Manager , ini berarti kita dapat membuat pendengar/listener yang berjalan saat sebuah event dipicu.

<?php

$eventsManager = new Phalcon\Events\Manager();

//Attach an anonymous function as a listener for "model" events
$eventsManager->attach('collection', function($event, $robot) {
    if ($event->getType() == 'beforeSave') {
        if ($robot->name == 'Scooby Doo') {
            echo "Scooby Doo isn't a robot!";
            return false;
        }
    }
    return true;
});

$robot = new Robots();
$robot->setEventsManager($eventsManager);
$robot->name = 'Scooby Doo';
$robot->year = 1969;
$robot->save();

Dalam contoh di atas, EventsManager hanya bertindak sebagai jembatan antara obyek dan pendengar (fungsi anonim). Jika kita ingin semua obyek yang dibuat dalam aplikasi kita menggunakan EventsManager yang sama, maka kita perlu untuk menetapkan ini ke Model Manager:

<?php

//Registering the collectionManager service
$di->set('collectionManager', function() {

    $eventsManager = new Phalcon\Events\Manager();

    // Attach an anonymous function as a listener for "model" events
    $eventsManager->attach('collection', function($event, $model) {
        if (get_class($model) == 'Robots') {
            if ($event->getType() == 'beforeSave') {
                if ($model->name == 'Scooby Doo') {
                    echo "Scooby Doo isn't a robot!";
                    return false;
                }
            }
        }
        return true;
    });

    // Setting a default EventsManager
    $modelsManager = new Phalcon\Mvc\Collection\Manager();
    $modelsManager->setEventsManager($eventsManager);
    return $modelsManager;

}, true);

Menerapkan Aturan Bisnis 

Ketika insert, update atau delete dijalankan, model memverifikasi apakah ada metode dengan nama event yang tercantum dalam tabel di atas.

Kami merekomendasikan bahwa metode validasi dideklarasikan protected untuk mencegah pelaksanaan logika bisnis secara publik.

Contoh berikut mengimplementasikan suatu event yang memvalidasi tahun ini tidak bisa lebih kecil dari 0 saat update atau insert:

<?php

class Robots extends \Phalcon\Mvc\Collection
{

    public function beforeSave()
    {
        if ($this->year < 0) {
            echo "Year cannot be smaller than zero!";
            return false;
        }
    }

}

Beberapa event mengembalikan false sebagai indikasi untuk menghentikan operasi saat ini. Jika suatu event tidak mengembalikan apa-apa, Phalcon \ MVC \ Collection akan mengasumsikan nilai true.

Validasi Integritas data 

Phalcon \ MVC \ Collection menyediakan beberapa event untuk memvalidasi data dan mengimplementasikan aturan bisnis. Event khusus “validasi”  membantu kita untuk memanggil built-in validator pada record. Phalcon memberikan beberapa built-in validator yang dapat digunakan pada tahap validasi.

Contoh berikut menunjukkan cara menggunakannya:

<?php

use Phalcon\Mvc\Model\Validator\InclusionIn,
    Phalcon\Mvc\Model\Validator\Numericality;

class Robots extends \Phalcon\Mvc\Collection
{

    public function validation()
    {

        $this->validate(new InclusionIn(
            array(
                "field"  => "type",
                "message" => "Type must be: mechanical or virtual",
                "domain" => array("Mechanical", "Virtual")
            )
        ));

        $this->validate(new Numericality(
            array(
                "field"  => "price",
                "message" => "Price must be numeric"
            )
        ));

        return $this->validationHasFailed() != true;
    }

}

Contoh yang diberikan di atas melakukan validasi dengan menggunakan built-in validator “InclusionIn”. Ia memeriksa nilai field “tipe” dalam daftar domain. Jika nilai tidak termasuk dalam metode ini, maka validator akan gagal dan mengembalikan false. Berikut built-in validator yang tersedia:

Nama Penjelasan Contoh
Email Memvalidasi bahwa bidang berisi format email yang valid Contoh
ExclusionIn Memvalidasi bahwa nilai tidak berada dalam daftar nilai yang mungkin Contoh
InclusionIn Memvalidasi bahwa nilai berada dalam daftar nilai yang mungkin Contoh
Numericality Memvalidasi bahwa field memiliki format numerik Contoh
Regex Memvalidasi bahwa nilai field sesuai dengan ekspresi reguler Contoh
StringLength Memvalidasi panjang string Contoh

Selain validator built-in, Anda dapat membuat validator Anda sendiri:

<?php

class UrlValidator extends \Phalcon\Mvc\Collection\Validator
{

    public function validate($model)
    {
        $field = $this->getOption('field');

        $value    = $model->$field;
        $filtered = filter_var($value, FILTER_VALIDATE_URL);
        if (!$filtered) {
            $this->appendMessage("The URL is invalid", $field, "UrlValidator");
            return false;
        }
        return true;
    }

}

Menambahkan validator untuk model:

<?php

class Customers extends \Phalcon\Mvc\Collection
{

    public function validation()
    {
        $this->validate(new UrlValidator(array(
            "field"  => "url",
        )));
        if ($this->validationHasFailed() == true) {
            return false;
        }
    }

}

Ide utama dalam menciptakan validator adalah membuanya dapat digunakan kembali di beberapa model. Sebuah validator juga dapat sederhana seperti:

<?php

class Robots extends \Phalcon\Mvc\Collection
{

    public function validation()
    {
        if ($this->type == "Old") {
            $message = new Phalcon\Mvc\Model\Message(
                "Sorry, old robots are not allowed anymore",
                "type",
                "MyType"
            );
            $this->appendMessage($message);
            return false;
        }
        return true;
    }

}

Delete Record 

Metode Phalcon\MVC\Collection::delete() berfungsi untuk menghapus dokumen. Anda dapat menggunakannya sebagai berikut:

<?php

$robot = Robots::findFirst();
if ($robot != false) {
    if ($robot->delete() == false) {
        echo "Sorry, we can't delete the robot right now: \n";
        foreach ($robot->getMessages() as $message) {
            echo $message, "\n";
        }
    } else {
        echo "The robot was deleted successfully!";
    }
}

Anda juga dapat menghapus banyak dokumen dengan menelusuri resultset dengan foreach:

<?php

$robots = Robots::find(array(
    array("type" => "mechanical")
));
foreach ($robots as $robot) {
    if ($robot->delete() == false) {
        echo "Sorry, we can't delete the robot right now: \n";
        foreach ($robot->getMessages() as $message) {
            echo $message, "\n";
        }
    } else {
        echo "The robot was deleted successfully!";
    }
}

Event berikut ini tersedia untuk mendefinisikan aturan bisnis kustom yang dapat dieksekusi ketika operasi delete dilakukan:

Operasi Nama Bisa menghentikan operasi? Penjelasan
Deleting beforeDelete YES Berjalan sebelum operasi menghapus dibuat
Deleting afterDelete NO Berjalan setelah operasi menghapus dibuat

Event Validasi Gagal 

Tipe lain dari event tersedia bila proses validasi data menemukan ketidaksesuaian:

Operasi Nama Penjelasan
Insert atau Update notSave Dipicu ketika operasi insert / update gagal karena alasan apapun
Insert, Delete atau Update onValidationFails Dipicu ketika setiap operasi manipulasi data gagal

ID Implisit vs Primary Key 

Secara default Phalcon\MVC\Collection mengasumsikan bahwa atribut _id secara otomatis dihasilkan menggunakan MongoIds . Jika model menggunakan primary key kustom perilaku ini dapat diganti:

<?php

class Robots extends Phalcon\Mvc\Collection
{
    public function initialize()
    {
        $this->useImplicitObjectIds(false);
    }
}

Seting Multi Database 

Dalam Phalcon, semua model dapat berasal dari koneksi database yang sama atau sendiri-sendiri. Sebenarnya, ketika Phalcon \ MVC \ Collection perlu terhubung ke database itu meminta layanan “mongo” ke kontainer layanan aplikasi. Anda dapat overide pengaturan layanan ini dalam metode initialize:

<?php

// This service returns a mongo database at 192.168.1.100
$di->set('mongo1', function() {
    $mongo = new MongoClient("mongodb://scott:nekhen@192.168.1.100");
    return $mongo->selectDB("management");
}, true);

// This service returns a mongo database at localhost
$di->set('mongo2', function() {
    $mongo = new MongoClient("mongodb://localhost");
    return $mongo->selectDB("invoicing");
}, true);

Kemudian, dalam metode Initialize, kita mendefinisikan layanan koneksi untuk model:

<?php

class Robots extends \Phalcon\Mvc\Collection
{
    public function initialize()
    {
        $this->setConnectionService('mongo1');
    }

}

Injeksi layanan Dalam Model 

Anda mungkin diminta untuk mengakses layanan aplikasi dalam model, contoh berikut menjelaskan cara untuk melakukannya:

<?php

class Robots extends \Phalcon\Mvc\Collection
{

    public function notSave()
    {
        // Obtain the flash service from the DI container
        $flash = $this->getDI()->getShared('flash');

        // Show validation messages
        foreach ($this->getMessages() as $message){
            $flash->error((string) $message);
        }
    }

}

Event “notSave” dipicu setiap kali action “create” atau “update” gagal. Kami flashing pesan validasi dgn memperoleh layanan “flash”  dari wadah DI. Dengan melakukan ini, kita tidak harus mencetak pesan setelah setiap save.

 

Terjemahan dari
http://docs.phalconphp.com/en/latest/reference/odm.html