Model Phalcon

Sebuah model menggambarkan informasi (data) dari aplikasi dan aturan untuk memanipulasi data tersebut. Model Phalcon terutama digunakan untuk mengelola aturan interaksi dengan tabel database yang sesuai. Dalam kebanyakan kasus, setiap tabel dalam database Anda akan sesuai dengan satu model dalam aplikasi Anda. Sebagian besar logika bisnis aplikasi Anda akan terkonsentrasi dalam model.

Phalcon \ MVC \ Model adalah dasar untuk semua model dalam aplikasi Phalcon. Ini memberikan kemerdekaan basis data, fungsi CRUD dasar, kemampuan pencarian canggih, dan kemampuan untuk berhubungan/relasi dengan model satu sama lain, antara service lainnya. Phalcon \ MVC \ Model mengurangi penggunaan pernyataan SQL karena menerjemahkan metode dinamis ke masing-masing operasi mesin database.

Model dimaksudkan untuk bekerja pada abstraksi database pada lapisan atas. Jika Anda perlu untuk bekerja dengan database pada tingkat yang lebih rendah memeriksa dokumentasi komponen Phalcon \ Db .

Membuat Model Phalcon 

Sebuah model adalah class yang extend dari Phalcon \ MVC \ Model . Dan harus ditempatkan di direktori model. Sebuah file model harus berisi satu class; nama class harus dalam notasi camel case :

<?php

class Robots extends \Phalcon\Mvc\Model
{

}

Contoh di atas menunjukkan penerapan model “Robot” . Perhatikan bahwa class Robot mewarisi Phalcon \ MVC \ Model . Komponen ini memberikan banyak fungsi untuk model yang mewarisinya, termasuk CRUD dasar basis data (Create, Read, Update, Delete) operasi, validasi data, serta dukungan pencarian canggih dan kemampuan untuk berhubungan dengan beberapa model satu sama lain.

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

Secara default, model “Robots” akan mengacu pada tabel “robots”. Jika Anda ingin secara manual menentukan nama lain untuk pemetaan tabel , Anda dapat menggunakan metode getSource():

<?php

class Robots extends \Phalcon\Mvc\Model
{

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

}

Model Robot sekarang dipetakan ke tabel “the_robots”. Perintah initialize() membantu dalam menyiapkan model dengan pengaturan perilaku kustom misal tabel yang berbeda. Perintah initialize() hanya disebut sekali selama request.

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->setSource("the_robots");
    }

}

Perintah initialize() ini hanya dipanggil sekali selama request, itu dimaksudkan untuk melakukan inisialisasi yang berlaku untuk semua instance dari model yang dibuat dalam aplikasi. Jika Anda ingin menyisipkan kode setiap instance dibuat, Anda dapat menggunakan ‘onConstruct’:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function onConstruct()
    {
        //...
    }

}

Properti publik vs setter / getter 

Model dapat diimplementasikan dengan properti publik, yang berarti bahwa setiap properti dapat dibaca / diperbarui dari setiap bagian dari kode yang telah instantiated bahwa kelas model tanpa batasan:

<?php

class Robots extends \Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public $price;
}

Dengan menggunakan getter dan setter Anda dapat mengontrol properti yang publik, melakukan berbagai transformasi data (yang tidak mungkin sebaliknya) dan juga menambahkan aturan validasi terhadap data yang disimpan dalam objek:

<?php

class Robots extends \Phalcon\Mvc\Model
{
    protected $id;

    protected $name;

    protected $price;

    public function getId()
    {
        return $this->id;
    }

    public function setName($name)
    {
        //The name is too short?
        if (strlen($name) < 10) {
            throw new \InvalidArgumentException('The name is too short');
        }
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPrice($price)
    {
        //Negative prices aren't allowed
        if ($price < 0) {
            throw new \InvalidArgumentException('Price can\'t be negative');
        }
        $this->price = $price;
    }

    public function getPrice()
    {
        //Convert the value to double before be used
        return (double) $this->price;
    }
}

Properti publik tidak memberikan kompleksitas dalam pengembangan. Namun getter / setter banyak meningkatkan testability, extensibility dan pemeliharaan aplikasi. Pengembang dapat memutuskan strategi mana yang lebih tepat untuk aplikasi yang mereka ciptakan. ORM kompatibel dengan kedua skema properti.

Model dalam Namespace 

Namespace dapat digunakan untuk menghindari tabrakan nama class. Tabel dipetakan diambil dari nama class, dalam hal ini ‘Robots’:

<?php

namespace Store\Toys;

class Robots extends \Phalcon\Mvc\Model
{

}

Memahami Record Untuk Object 

Setiap instance dari model mewakili sebuah baris dalam tabel. Anda dapat dengan mudah mengakses data record dengan membaca properti obyek. Sebagai contoh, untuk tabel “robot” dengan daftar baris:

mysql> select * from robots;
+----+------------+------------+------+
| id | name       | type       | year |
+----+------------+------------+------+
|  1 | Robotina   | mechanical | 1972 |
|  2 | Astro Boy  | mechanical | 1952 |
|  3 | Terminator | cyborg     | 2029 |
+----+------------+------------+------+
3 rows in set (0.00 sec)

Anda bisa menemukan record tertentu dengan primary key dan kemudian mencetak namanya:

<?php

// Find record with id = 3
$robot = Robots::findFirst(3);

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

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

<?php

$robot = Robots::findFirst(3);
$robot->name = "RoboCop";
$robot->save();

Seperti yang Anda lihat, tidak ada kebutuhan untuk menggunakan pernyataan SQL mentah. Phalcon \ MVC \ Model menyediakan abstraksi database yang tinggi untuk aplikasi web.

Menemukan Record 

Phalcon \ MVC \ Model juga menawarkan beberapa metode untuk query record. Contoh berikut akan menunjukkan kepada Anda bagaimana untuk melakukan query untuk mendapatkan satu atau beberapa record dari 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("type = 'mechanical'");
echo "There are ", count($robots), "\n";

// Get and print virtual robots ordered by name
$robots = Robots::find(array(
    "type = 'virtual'",
    "order" => "name"
));
foreach ($robots as $robot) {
    echo $robot->name, "\n";
}

// Get first 100 virtual robots ordered by name
$robots = Robots::find(array(
    "type = 'virtual'",
    "order" => "name",
    "limit" => 100
));
foreach ($robots as $robot) {
   echo $robot->name, "\n";
}

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

<?php

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

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

// Get first virtual robot ordered by name
$robot = Robots::findFirst(array("type = 'virtual'", "order" => "name"));
echo "The first virtual robot name is ", $robot->name, "\n";

Baik perintah Find() atau FindFirst() menerima array asosiatif untuk menentukan kriteria pencarian:

<?php

$robot = Robots::findFirst(array(
    "type = 'virtual'",
    "order" => "name DESC",
    "limit" => 30
));

$robots = Robots::find(array(
    "conditions" => "type = ?1",
    "bind"       => array(1 => "virtual")
));

Opsi query yang tersedia adalah:

Parameter Deskripsi Contoh
conditions Pencarian kondisi untuk operasi find. Digunakan untuk mengekstrak hanya catatan-catatan yang memenuhi kriteria tertentu. Secara default Phalcon \ MVC \ Model mengasumsikan parameter pertama adalah kondisi. “conditions” => “Nama LIKE ‘steve%'”
columns Kembali kolom tertentu, bukan kolom penuh dalam model. Bila menggunakan opsi ini obyek yang dikembalikan tidak lengkap  “columns” => “id, nama”
bind Bind digunakan bersama-sama dengan opsi lainnya, dengan mengganti placeholder dan escape value sehingga meningkatkan keamanan “bind” => array (“status” => “A”, “type” => “beberapa waktu”)
bindTypes Ketika bind parameter, Anda dapat menggunakan parameter ini untuk menentukan tambahan pengecekan tipe data (casting) untuk parameter terikat meningkat keamanan “BindTypes” => array (Column :: BIND_TYPE_STR, Kolom :: BIND_TYPE_INT)
order Digunakan untuk mengurutkan ResultSet. Gunakan satu atau lebih kolom dipisahkan dengan koma. “Order” => “nama DESC, status”
limit Batasi hasil query untuk hasil ke kisaran tertentu “limit” => 10 / “limit” => array (“number” => 10, “offset” => 5)
group Memungkinkan untuk mengumpulkan data di beberapa record dan kelompok hasil menurut satu atau lebih kolom “group” => “nama, status”
for_update Dengan opsi ini, Phalcon \ MVC \ Model membaca data terbaru yang tersedia, pengaturan kunci eksklusif pada setiap baris yg dibaca “for_update” => true
shared_lock Dengan opsi ini, Phalcon \ MVC \ Model membaca data terbaru yang tersedia, pengaturan kunci bersama pada setiap baris dibaca “shared_lock” => true
Cache Cache resultset, mengurangi akses berkelanjutan ke sistem relasional “cache” => array (“lifetime” => 3600, “key” => “my-find-key”)
hydration Mengatur strategi hidrasi untuk mewakili setiap record dikembalikan dalam hasil “hydration” =>Resultset::HYDRATE_OBJECTS

Jika Anda lebih suka, ada juga tersedia cara untuk membuat query dengan cara berorientasi obyek, daripada menggunakan sebuah array dari parameter:

<?php

$robots = Robots::query()
    ->where("type = :type:")
    ->andWhere("year < 2000")
    ->bind(array("type" => "mechanical"))
    ->order("name")
    ->execute();

Perintah statis query() mengembalikan Phalcon \ MVC \ Model \ Criteria objek yang ramah dengan autocomplete IDE.

Semua query secara internal ditangani sebagai query PHQL. PHQL adalah tingkat tinggi, object-oriented dan bahasa yg mirip dgn SQL. Bahasa ini menyediakan lebih banyak fitur untuk melakukan query seperti join dengan model lain, mendefinisikan group, menambahkan agregasi dll

Terakhir, ada perintah findFirstBy<property-name>(). Perintah ini memperluas perintah “FindFirst ()” yang disebutkan sebelumnya. Hal ini memungkinkan Anda untuk dengan cepat melakukan pengambilan dari tabel dengan menggunakan nama properti dalam metode itu sendiri dan lewat itu parameter yang berisi data yang ingin Anda cari dalam kolom tersebut. Contohnya, untuk mengambil Model Robot seperti kami sebutkan sebelumnya:

<?php

class Robots extends \Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public $price;
}

Kita memiliki tiga properti untuk bekerja di sini. $id, $name dan $price. Jadi, katakanlah Anda ingin mengambil record pertama dalam tabel dengan nama ‘Terminator’. Hal ini dapat ditulis seperti:

<?php

$name = "Terminator";
$robot = Robots::findFirstByName($name);

if($robot){
    $this->flash->success("The first robot with the name " . $name . " cost " . $robot->price ".");
}else{
    $this->flash->error("There were no robots found in our table with the name " . $name ".");
}

Perhatikan bahwa kita menggunakan ‘Name’ dalam pemanggilan perintah dan memberikan variabel $name untuk itu, yang berisi nama yang kita cari di tabel. Perhatikan juga bahwa ketika kita menemukan kecocokan dengan permintaan tsb, semua properti lain jd tersedia untuk jenis perintah ini.

Model resultsets 

Sementara findFirst () mengembalikan langsung sebuah instance dari class yg diambil (bila ada data yang akan dikembalikan), metode find() mengembalikan Phalcon \ MVC \ Model \ ResultSet \ Simple . Ini adalah obyek yang merangkum semua fungsi resultset telah seperti traversing, mencari baris tertentu, menghitung, dll

Objek ini lebih baik daripada array standar. Salah satu fitur terbesar dari Phalcon \ MVC \ Model \ ResultSet adalah bahwa setiap saat hanya ada satu record dalam memori. Hal ini sangat membantu dalam manajemen memori terutama ketika bekerja dengan data dalam jumlah besar.

<?php

// Get all robots
$robots = Robots::find();

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

// Traversing with a while
$robots->rewind();
while ($robots->valid()) {
    $robot = $robots->current();
    echo $robot->name, "\n";
    $robots->next();
}

// Count the resultset
echo count($robots);

// Alternative way to count the resultset
echo $robots->count();

// Move the internal cursor to the third robot
$robots->seek(2);
$robot = $robots->current();

// Access a robot by its position in the resultset
$robot = $robots[5];

// Check if there is a record in certain position
if (isset($robots[3])) {
   $robot = $robots[3];
}

// Get the first record in the resultset
$robot = $robots->getFirst();

// Get the last record
$robot = $robots->getLast();

Resultsets Phalcon merupakan emulator kursor yg dapat digeser, Anda bisa mendapatkan setiap baris hanya dengan mengakses posisinya, atau mencari pointer internal untuk posisi tertentu. Perhatikan bahwa beberapa sistem database tidak mendukung kursor macam ini, ini memaksa untuk kembali mengeksekusi-ulang query untuk memundurkan kursor ke awal dan mendapatkan baris pada posisi yang diminta. Demikian pula, jika resultset yang dilalui beberapa kali, query harus dijalankan jumlah yang sama kali.

Menyimpan hasil query besar dalam memori bisa mengkonsumsi banyak sumber daya, karena ini, resultsets diperoleh dari database dalam potongan terdiri dari 32 baris mengurangi kebutuhan untuk mengulang query. dalam beberapa kasus juga menghemat memori.

Perhatikan bahwa resultsets dapat diserialisasi dan disimpan di backend cache. Phalcon \ Cache dapat membantu dengan tugas itu. Namun, serialisasi data yang menyebabkan Phalcon \ MVC \ Model untuk mengambil semua data dari database berbentuk array, sehingga mengkonsumsi lebih banyak memori saat proses ini berlangsung.

<?php

// Query all records from model parts
$parts = Parts::find();

// Store the resultset into a file
file_put_contents("cache.txt", serialize($parts));

// Get parts from file
$parts = unserialize(file_get_contents("cache.txt"));

// Traverse the parts
foreach ($parts as $part) {
   echo $part->id;
}

Filter resultsets 

Cara yang paling efisien untuk filter data menetapkan beberapa kriteria pencarian, database akan menggunakan indeks yang ditetapkan pada tabel untuk mengembalikan data yang lebih cepat. Sebagai tambahan Phalcon memungkinkan Anda untuk menyaring data menggunakan PHP dengan menggunakan semua sumber daya yang tidak tersedia dalam database:

<?php

$customers = Customers::find()->filter(function($customer) {

    //Return only customers with a valid e-mail
    if (filter_var($customer->email, FILTER_VALIDATE_EMAIL)) {
        return $customer;
    }

});

Bind Parameter 

Bind Parameter juga didukung di Phalcon \ MVC \ Model . Meskipun ada dampak kinerja sedikit dengan menggunakan bind parameter, Anda dianjurkan untuk menggunakan metodologi ini sehingga dapat mengurangi kemungkinan kode Anda menjadi sasaran serangan injeksi SQL. Baik string maupun integer telah didukung. Parameter Binding hanya dapat dicapai sebagai berikut:

<?php

// Query robots binding parameters with string placeholders
$conditions = "name = :name: AND type = :type:";

//Parameters whose keys are the same as placeholders
$parameters = array(
    "name" => "Robotina",
    "type" => "maid"
);

//Perform the query
$robots = Robots::find(array(
    $conditions,
    "bind" => $parameters
));

// Query robots binding parameters with integer placeholders
$conditions = "name = ?1 AND type = ?2";
$parameters = array(1 => "Robotina", 2 => "maid");
$robots     = Robots::find(array(
    $conditions,
    "bind" => $parameters
));

// Query robots binding parameters with both string and integer placeholders
$conditions = "name = :name: AND type = ?1";

//Parameters whose keys are the same as placeholders
$parameters = array(
    "name" => "Robotina",
    1 => "maid"
);

//Perform the query
$robots = Robots::find(array(
    $conditions,
    "bind" => $parameters
));

Bila menggunakan penampung numerik, Anda akan perlu untuk mendefinisikan mereka sebagai bilangan bulat yaitu 1 atau 2. Dalam hal ini “1” atau “2” dianggap string dan bukan angka, jadi placeholder tidak bisa berhasil diganti.

String secara otomatis di-escape menggunakan PDO . Fungsi ini akan memastikan charset koneksi, jadi disarankan untuk menentukan charset benar dalam parameter koneksi atau konfigurasi database, karena charset yang salah akan menghasilkan efek yang tidak diinginkan saat menyimpan atau mengambil data.

Selain itu Anda dapat mengatur parameter “bindTypes”, ini memungkinkan menentukan bagaimana parameter harus terikat menurut jenis datanya:

<?php

use \Phalcon\Db\Column;

//Bind parameters
$parameters = array(
    "name" => "Robotina",
    "year" => 2008
);

//Casting Types
$types = array(
    "name" => Column::BIND_PARAM_STR,
    "year" => Column::BIND_PARAM_INT
);

// Query robots binding parameters with string placeholders
$robots = Robots::find(array(
    "name = :name: AND year = :year:",
    "bind" => $parameters,
    "bindTypes" => $types
));

Karena default bind-type \Phalcon\Db\Column:: BIND_PARAM_STR, tidak ada kebutuhan untuk menentukan “bindTypes” parameter jika semua kolom adalah dari tipe tersebut.

Parameter Binding tersedia untuk semua metode query seperti find () dan FindFirst () dan juga metode perhitungan seperti count(), sum(), average() dll

Inisialisasi / Mempersiapkan Record yg Diambil 

Kadang setelah mendapat record dari database yang diperlukan untuk menginisialisasi data sebelum digunakan oleh seluruh aplikasi. Anda dapat menerapkan metode ‘afterFetch’ dalam model, event ini akan dilaksanakan setelah membuat instance dan menetapkan data untuk itu:

<?php

class Robots extends Phalcon\Mvc\Model
{

    public $id;

    public $name;

    public $status;

    public function beforeSave()
    {
        //Convert the array into a string
        $this->status = join(',', $this->status);
    }

    public function afterFetch()
    {
        //Convert the string to an array
        $this->status = explode(',', $this->status);
    }
}

Jika Anda menggunakan getter / setter dari / atau bersama-sama dengan properti public, Anda dapat menginisialisasi kolom setelah diakses:

<?php

class Robots extends Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public $status;

    public function getStatus()
    {
        return explode(',', $this->status);
    }

}

Relasi antar Model 

Ada empat jenis relasi: satu-satu, satu-ke-banyak, banyak-ke-satu dan banyak-ke-banyak. Relasi mungkin searah atau dua arah, dan masing-masing dapat sederhana (satu untuk satu model) atau yang lebih kompleks (kombinasi model). Model manager mengelola foreign key constraint untuk hubungan ini, definisi ini membantu integritas referensial serta akses mudah dan cepat dari catatan terkait dengan model. Melalui penerapan relasi ini, mudah untuk mengakses data dalam model terkait dari setiap record dengan cara yang seragam.

Relasi Searah 

Hubungan Searah adalah mereka yang dihasilkan dalam kaitannya dengan satu pada lainnya tetapi tidak sebaliknya.

Relasi dua arah 

Hubungan dua arah membangun hubungan di kedua model dan setiap model mendefinisikan hubungan terbalik dari yang lain.

Mendefinisikan Relasi 

Dalam Phalcon, hubungan harus didefinisikan dalam perintah initialize() model. Metode belongsTo(), hasOne(), hasMany() dan hasManyToMany() mendefinisikan hubungan antara satu atau lebih kolom dari model satu untuk kolom dalam model lain. Masing-masing metode ini membutuhkan 3 parameter: kolom lokal, model yang direferensikan, kolom direferensikan.

Metode Deskripsi
hasMany Mendefinisikan hubungan 1-n
hasOne Mendefinisikan hubungan 1-1
belongsTo Mendefinisikan hubungan n-1 
hasManyToMany Mendefinisikan hubungan n-n

Skema berikut menunjukkan 3 tabel yang hubungan akan memberi kita contoh mengenai relasi:

CREATE TABLE `robots` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(70) NOT NULL,
    `type` varchar(32) NOT NULL,
    `year` int(11) NOT NULL,
    PRIMARY KEY (`id`)
);

CREATE TABLE `robots_parts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `robots_id` int(10) NOT NULL,
    `parts_id` int(10) NOT NULL,
    `created_at` DATE NOT NULL,
    PRIMARY KEY (`id`),
    KEY `robots_id` (`robots_id`),
    KEY `parts_id` (`parts_id`)
);

CREATE TABLE `parts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(70) NOT NULL,
    PRIMARY KEY (`id`)
);
  • Model “Robot” memiliki banyak “RobotsParts”.
  • Model “Parts” memiliki banyak “RobotsParts”.
  • Model “RobotsParts” milik kedua “Robot” dan “Parts” model sebagai banyak-ke-satu hubungan.
  • Model “Robot” memiliki hubungan many-to-many ke “Parts” melalui “RobotsParts”

Periksa diagram EER untuk memahami lebih baik hubungan:

../_images/eer-1.png

Model dan relasinya bisa diimplementasikan sebagai berikut:

<?php

class Robots extends \Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany("id", "RobotsParts", "robots_id");
    }

}


<?php

class Parts extends \Phalcon\Mvc\Model
{

    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany("id", "RobotsParts", "parts_id");
    }

}


<?php

class RobotsParts extends \Phalcon\Mvc\Model
{

    public $id;

    public $robots_id;

    public $parts_id;

    public function initialize()
    {
        $this->belongsTo("robots_id", "Robots", "id");
        $this->belongsTo("parts_id", "Parts", "id");
    }

}

Parameter pertama menunjukkan kolom model lokal yang digunakan dalam hubungan; kedua menunjukkan nama model referensi dan ketiga nama field dalam model direferensikan. Anda juga bisa menggunakan array untuk mendefinisikan beberapa kolom dalam relasi.

Relasi banyak-ke-banyak membutuhkan 3 model dan menentukan atribut yang terlibat dalam hubungan:

<?php

class Robots extends \Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public function initialize()
    {
        $this->hasManyToMany(
            "id",
            "RobotsParts",
            "robots_id", "parts_id",
            "Parts",
            "id"
        );
    }

}

Memberdayakan Relasi 

Ketika secara eksplisit mendefinisikan hubungan antara model, mudah untuk menemukan record terkait untuk record tertentu.

<?php

$robot = Robots::findFirst(2);
foreach ($robot->robotsParts as $robotPart) {
    echo $robotPart->parts->name, "\n";
}

Phalcon menggunakan metode magic  __ set / __get / __call untuk menyimpan atau mengambil data terkait dengan relasi.

Dengan mengakses atribut dengan nama yang sama dengan relasi akan mengambil semua record yang terkait .

<?php

$robot = Robots::findFirst();
$robotsParts = $robot->robotsParts; // all the related records in RobotsParts

Juga, Anda dapat menggunakan magic getter:

<?php

$robot = Robots::findFirst();
$robotsParts = $robot->getRobotsParts(); // all the related records in RobotsParts
$robotsParts = $robot->getRobotsParts(array('limit' => 5)); // passing parameters

Jika perintah memiliki awalan “get”  Phalcon \ MVC \ Model akan mengembalikan findFirst() / find() hasil. Contoh berikut membandingkan mengambil hasil pencarian yang berkaitan dengan menggunakan metode magic dan tanpa:

<?php

$robot = Robots::findFirst(2);

// Robots model has a 1-n (hasMany)
// relationship to RobotsParts then
$robotsParts = $robot->robotsParts;

// Only parts that match conditions
$robotsParts = $robot->getRobotsParts("created_at = '2012-03-15'");

// Or using bound parameters
$robotsParts = $robot->getRobotsParts(array(
    "created_at = :date:",
    "bind" => array("date" => "2012-03-15")
));

$robotPart = RobotsParts::findFirst(1);

// RobotsParts model has a n-1 (belongsTo)
// relationship to RobotsParts then
$robot = $robotPart->robots;

Mendapatkan record terkait secara manual:

<?php

$robot = Robots::findFirst(2);

// Robots model has a 1-n (hasMany)
// relationship to RobotsParts, then
$robotsParts = RobotsParts::find("robots_id = '" . $robot->id . "'");

// Only parts that match conditions
$robotsParts = RobotsParts::find(
    "robots_id = '" . $robot->id . "' AND created_at = '2012-03-15'"
);

$robotPart = RobotsParts::findFirst(1);

// RobotsParts model has a n-1 (belongsTo)
// relationship to RobotsParts then
$robot = Robots::findFirst("id = '" . $robotPart->robots_id . "'");

Awalan “get” digunakan untuk find() / findFirst() record terkait. Tergantung pada jenis hubungan itu akan menggunakan ‘find’ atau ‘FindFirst’:

Jenis Deskripsi Metode Implisit
Belongs-To Pengembalian instance model record terkait langsung FindFirst
Has-One Pengembalian instance model record terkait langsung FindFirst
Has-Many Pengembalian koleksi instance model model direferensikan find
Has-Many-to-Many Pengembalian koleksi instance model yg direferensikan, secara implisit tidak ‘inner join’ dengan model yang terlibat (Query yang kompleks)

Anda juga dapat menggunakan awalan “count” untuk mendapatkan integer yang menunjukkan hitungan record terkait:

<?php

$robot = Robots::findFirst(2);
echo "The robot has ", $robot->countRobotsParts(), " parts\n";

Relasi dgn Alias 

Untuk menjelaskan lebih baik bagaimana alias bekerja, mari kita periksa contoh berikut:

Table “robots_similar” memiliki fungsi untuk mendefinisikan robot apa yang mirip dengan yg lain:

mysql> desc robots_similar;
+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| id                | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| robots_id         | int(10) unsigned | NO   | MUL | NULL    |                |
| similar_robots_id | int(10) unsigned | NO   |     | NULL    |                |
+-------------------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

Kedua “robots_id” dan “similar_robots_id” memiliki hubungan dengan model Robots:

tutorial phalcon eer-2

Sebuah model yang memetakan tabel ini dan hubungan nya adalah sebagai berikut:

<?php

class RobotsSimilar extends Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->belongsTo('robots_id', 'Robots', 'id');
        $this->belongsTo('similar_robots_id', 'Robots', 'id');
    }

}

Karena kedua hubungan mengarah ke model yang sama (Robot), memperoleh record yang berhubungan dengan hubungan tidak bisa jelas:

<?php

$robotsSimilar = RobotsSimilar::findFirst();

//Returns the related record based on the column (robots_id)
//Also as is a belongsTo it's only returning one record
//but the name 'getRobots' seems to imply that return more than one
$robot = $robotsSimilar->getRobots();

//but, how to get the related record based on the column (similar_robots_id)
//if both relationships have the same name?

Alias ​​memungkinkan kita untuk mengubah nama relasi keduanya untuk memecahkan masalah ini:

<?php

class RobotsSimilar extends Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->belongsTo('robots_id', 'Robots', 'id', array(
            'alias' => 'Robot'
        ));
        $this->belongsTo('similar_robots_id', 'Robots', 'id', array(
            'alias' => 'SimilarRobot'
        ));
    }

}

Dengan alias kita bisa mendapatkan record yang terkait dengan mudah:

<?php

$robotsSimilar = RobotsSimilar::findFirst();

//Returns the related record based on the column (robots_id)
$robot = $robotsSimilar->getRobot();
$robot = $robotsSimilar->robot;

//Returns the related record based on the column (similar_robots_id)
$similarRobot = $robotsSimilar->getSimilarRobot();
$similarRobot = $robotsSimilar->similarRobot;

Magic Getters vs metode Explicit 

Kebanyakan IDE dan editor dengan kemampuan auto-completion tidak dapat menyimpulkan jenis yang benar saat menggunakan getter magic, selain getter magic anda dapat mendefinisikan metode-metode tsb secara eksplisit dengan docblocks yg sesuai, membantu IDE untuk menghasilkan auto-completion yang lebih baik:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany("id", "RobotsParts", "robots_id");
    }

    /**
     * Return the related "robots parts"
     *
     * @return \RobotsParts[]
     */
    public function getRobotsParts($parameters=null)
    {
        return $this->getRelated('RobotsParts', $parameters);
    }

}

Virtual Foreign Keys 

Secara default, relationship tidak bertindak seperti foreign keys basis data, yaitu, jika Anda mencoba untuk memasukkan / memperbarui nilai tanpa nilai yang valid dalam model yg direferensikan, Phalcon tidak akan menghasilkan pesan validasi. Anda dapat mengubah perilaku ini dengan menambahkan parameter keempat ketika mendefinisikan hubungan.

Model RobotsParts dapat diubah untuk mengaktifkan fitur ini:

<?php

class RobotsParts extends \Phalcon\Mvc\Model
{

    public $id;

    public $robots_id;

    public $parts_id;

    public function initialize()
    {
        $this->belongsTo("robots_id", "Robots", "id", array(
            "foreignKey" => true
        ));

        $this->belongsTo("parts_id", "Parts", "id", array(
            "foreignKey" => array(
                "message" => "The part_id does not exist on the Parts model"
            )
        ));
    }

}

Jika Anda mengubah relasi belongsTo() untuk berfungsi sbg foreign key, maka akan memvalidasi setiap nilai-nilai masukkan / pembaruan di kolom tersebut, apakah nilai tsb valid pada model direferensikan. Demikian pula, jika hasMany() / hasOne() diubah maka akan memvalidasi bahwa record tsb tidak dapat dihapus jika record tsb masih digunakan pada model referensi.

<?php

class Parts extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->hasMany("id", "RobotsParts", "parts_id", array(
            "foreignKey" => array(
                "message" => "The part cannot be deleted because other robots are using it"
            )
        ));
    }

}

Cascade / Membatasi Action 

Relasi yang bertindak sebagai foreign key virtual secara default membatasi create / update / delete record untuk menjaga integritas data:

<?php

namespace Store\Models;

use Phalcon\Mvc\Model,
    Phalcon\Mvc\Model\Relation;

class Robots extends Model
{

    public $id;

    public $name;

    public function initialize()
    {
        $this->hasMany('id', 'Store\Models\Parts', 'robots_id', array(
            'foreignKey' => array(
                'action' => Relation::ACTION_CASCADE
            )
        ));
    }

}

Kode di atas disusun untuk menghapus semua record yg direferensikan (parts) jika master record (robots) dihapus.

Melakukan Perhitungan 

Perhitungan (atau agregasi) adalah alat bantu untuk fungsi-fungsi yang umum digunakan sistem database seperti COUNT, SUM, MAX, MIN atau AVG. Phalcon \ MVC \ Model memungkinkan untuk menggunakan fungsi-fungsi ini langsung dari metode yang disebutkan.

Contoh Count:

<?php

// How many employees are?
$rowcount = Employees::count();

// How many different areas are assigned to employees?
$rowcount = Employees::count(array("distinct" => "area"));

// How many employees are in the Testing area?
$rowcount = Employees::count("area = 'Testing'");

// Count employees grouping results by their area
$group = Employees::count(array("group" => "area"));
foreach ($group as $row) {
   echo "There are ", $row->rowcount, " in ", $row->area;
}

// Count employees grouping by their area and ordering the result by count
$group = Employees::count(array(
    "group" => "area",
    "order" => "rowcount"
));

// Avoid SQL injections using bound parameters
$group = Employees::count(array(
    "type > ?0",
    "bind" => array($type)
));

Contoh Sum:

<?php

// How much are the salaries of all employees?
$total = Employees::sum(array("column" => "salary"));

// How much are the salaries of all employees in the Sales area?
$total = Employees::sum(array(
    "column"     => "salary",
    "conditions" => "area = 'Sales'"
));

// Generate a grouping of the salaries of each area
$group = Employees::sum(array(
    "column" => "salary",
    "group"  => "area"
));
foreach ($group as $row) {
   echo "The sum of salaries of the ", $row->area, " is ", $row->sumatory;
}

// Generate a grouping of the salaries of each area ordering
// salaries from higher to lower
$group = Employees::sum(array(
    "column" => "salary",
    "group"  => "area",
    "order"  => "sumatory DESC"
));

// Avoid SQL injections using bound parameters
$group = Employees::sum(array(
    "conditions" => "area > ?0",
    "bind" => array($area)
));

Contoh Average:

<?php

// What is the average salary for all employees?
$average = Employees::average(array("column" => "salary"));

// What is the average salary for the Sales's area employees?
$average = Employees::average(array(
    "column" => "salary",
    "conditions" => "area = 'Sales'"
));

// Avoid SQL injections using bound parameters
$average = Employees::average(array(
    "column" => "age",
    "conditions" => "area > ?0",
    "bind" => array($area)
));

contoh Max / Min :

<?php

// What is the oldest age of all employees?
$age = Employees::maximum(array("column" => "age"));

// What is the oldest of employees from the Sales area?
$age = Employees::maximum(array(
    "column" => "age",
    "conditions" => "area = 'Sales'"
));

// What is the lowest salary of all employees?
$salary = Employees::minimum(array("column" => "salary"));

Hydration Mode 

Sebagaimana disebutkan di atas, resultsets adalah koleksi objek yang lengkap, ini berarti bahwa setiap hasil yg dikembalikan adalah obyek yang mewakili setiap baris dalam database. Objek ini dapat dimodifikasi dan disimpan lagi secara permanen:

<?php

// Manipulating a resultset of complete objects
foreach (Robots::find() as $robot) {
    $robot->year = 2000;
    $robot->save();
}

Kadang-kadang record diambil hanya untuk ditampilkan kepada pengguna dalam mode read-only, dalam kasus ini mungkin berguna untuk mengubah cara record ditampilkan untuk memfasilitasi penanganannya. Strategi yang digunakan untuk mewakili objek dikembalikan dalam resultset ini disebut ‘hydration mode’:

<?php

use Phalcon\Mvc\Model\Resultset;

$robots = Robots::find();

//Return every robot as an array
$robots->setHydrateMode(Resultset::HYDRATE_ARRAYS);

foreach ($robots as $robot) {
    echo $robot['year'], PHP_EOL;
}

//Return every robot as an stdClass
$robots->setHydrateMode(Resultset::HYDRATE_OBJECTS);

foreach ($robots as $robot) {
    echo $robot->year, PHP_EOL;
}

//Return every robot as a Robots instance
$robots->setHydrateMode(Resultset::HYDRATE_RECORDS);

foreach ($robots as $robot) {
    echo $robot->year, PHP_EOL;
}

Modus Hidrasi juga dapat dikirimkan sebagai parameter pada perintah ‘find’:

<?php

use Phalcon\Mvc\Model\Resultset;

$robots = Robots::find(array(
    'hydration' => Resultset::HYDRATE_ARRAYS
));

foreach ($robots as $robot) {
    echo $robot['year'], PHP_EOL;
}

Create/Updating Record 

Perintah Phalcon\MVC\Model::save() memungkinkan Anda untuk melakukan create / update record menyesuaikan apakah sudah ada tidaknya di tabel yang terkait pada model. Perintah Save disebutkan internal oleh perintah create dan update Phalcon\MVC\Model . Untuk memastikan perintah ini bekerja seperti yang diharapkan maka perlu didefinisikan terlebih dahulu primary key entitas untuk menentukan apakah suatu record harus diperbarui atau ditambahkan.

Juga perintah tsb bisa mengeksekusi validator terkait, foreign key virtual 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!";
}

Sebuah Array dapat diberikan ke perintah “save” untuk menghindari penetapan setiap kolom secara manual. Phalcon \ MVC \ Model akan memeriksa apakah ada setter diterapkan untuk kolom yg diberikan dalam array memberikan prioritas daripada memberikan langsung nilai-nilai dari atribut:

<?php

$robot = new Robots();
$robot->save(array(
    "type" => "mechanical",
    "name" => "Astro Boy",
    "year" => 1952
));

Value yg diberikan secara langsung atau melalui array atribut telah dilakukan escape/ sanitaize sesuai dengan tipe data atribut terkait. Jadi, Anda dapat melewatkan sebuah array aman tanpa khawatir tentang kemungkinan suntikan SQL:

<?php

$robot = new Robots();
$robot->save($_POST);

Tanpa tindakan pencegahan penempatan nilai massal dapat memungkinkan penyerang untuk menetapkan nilai database kolom manapun. Gunakan fitur ini hanya jika Anda ingin mengizinkan user untuk create / update setiap kolom dalam model, bahkan jika kolom tersebut tidak ada dalam element form yg dikirim.

Anda dapat mengatur parameter tambahan ‘save’ untuk menetapkan whitelist kolom yang diambil saja ketika melakukan menempatkan nilai secara massal:

<?php

$robot = new Robots();
$robot->save($_POST, array('name', 'type'));

Kepastian Create / Update 

Karna suatu hal, bisa kita bisa menghendaki create record tetapi justru update. Hal ini bisa terjadi jika kita menggunakan Phalcon\MVC\Model::save() untuk menyimpan record dalam database. Jika kita ingin benar-benar yakin bahwa record merupakan create atau update, kita dapat mengubah perintah save() dengan create() atau update():

<?php

$robot       = new Robots();
$robot->type = "mechanical";
$robot->name = "Astro Boy";
$robot->year = 1952;

//This record only must be created
if ($robot->create() == 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 created successfully!";
}

Metode ini “create” dan “update” juga menerima sebuah array nilai sebagai parameter.

Kolom Identitas Auto-generate 

Beberapa model mungkin memiliki kolom identitas. Kolom ini biasanya adalah primary key dari tabel. Phalcon \ MVC \ Model dapat mengenali kolom identitas yg muncul dalam SQL INSERT yg dihasilkan, sehingga sistem database dapat menghasilkan nilai auto-generate untuk itu. Setelah membuat rekor, kolom identitas akan diisi dengan nilai yang dihasilkan dalam sistem database:

<?php

$robot->save();

echo "The generated id is: ", $robot->id;

Phalcon \ MVC \ Model mampu mengenali kolom identitas. Tergantung pada sistem database, kolom tersebut mungkin kolom serial seperti di PostgreSQL atau kolom auto_increment dalam kasus MySQL.

PostgreSQL menggunakan urutan untuk menghasilkan nilai-nilai auto-numerik, secara default, Phalcon mencoba untuk mendapatkan nilai yang dihasilkan dari urutan “table_field_seq”, misalnya: robots_id_seq, jika urutan yang memiliki nama yang berbeda, metode “getSequenceName” perlu diterapkan:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function getSequenceName()
    {
        return "robots_sequence_name";
    }

}

Pesan validasi 

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

Setiap pesan terdiri dari sebuah instance dari kelas Phalcon \ MVC \ Model \ Message . Himpunan pesan yang dihasilkan dapat diambil dengan perintah getMessages(). Setiap pesan berisi informasi yg lebih lengkap seperti nama field yang menghasilkan 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();
    }
}

Phalcon \ MVC \ Model dapat menghasilkan jenis pesan validasi berikut:

Jenis Deskripsi
PresenceOf Dihasilkan ketika kolom dengan atribut non-null pada database sedang mencoba untuk memasukkan / memperbarui nilai null
ConstraintViolation Dihasilkan ketika bagian kolom foreign key virtual mencoba untuk memasukkan / memperbarui nilai yang tidak ada dalam model yg direferensikan
InvalidValue Dihasilkan ketika validator gagal karena nilai yang tidak valid
InvalidCreateAttempt Diproduksi ketika sebuah record dicoba untuk dibuat tapi sudah ada
InvalidUpdateAttempt Diproduksi ketika sebuah record berusaha untuk diperbarui tapi itu tidak ada

Metode getMessages() dapat di-overide dalam model untuk menggantikan / menerjemahkan pesan standar yang dihasilkan secara otomatis oleh ORM:

<?php

class Robots extends Phalcon\Mvc\Model
{
    public function getMessages()
    {
        $messages = array();
        foreach (parent::getMessages() as $message) {
            switch ($message->getType()) {
                case 'InvalidCreateAttempt':
                    $messages[] = 'The record cannot be created because it already exists';
                    break;
                case 'InvalidUpdateAttempt':
                    $messages[] = 'The record cannot be updated because it already exists';
                    break;
                case 'PresenceOf':
                    $messages[] = 'The field ' . $message->getField() . ' is mandatory';
                    break;
            }
        }
        return $messages;
    }
}

Event dan Event Manajer 

Model memungkinkan Anda untuk menerapkan event yg akan dimunculkan ketika melakukan insert / update / delete. Hal ini membantu mendefinisikan aturan bisnis untuk model tertentu. Berikut ini adalah event yang didukung oleh Phalcon \ MVC \ Model dan ketertiban mereka eksekusi:

Operasi Nama Bisa menghentikan operasi? Penjelasan
Inserting/Updating beforeValidation YES Dijalankan sebelum kolom divalidasi untuk non nulls / string kosong atau foreign key
Inserting beforeValidationOnCreate YES Dijalankan sebelum kolom divalidasi untuk non nulls / string kosong atau foreign key ketika operasi penyisipan sedang dijalankan
Updating beforeValidationOnUpdate YES Dijalankan sebelum kolom divalidasi untuk non nulls / string kosong atau foreign key ketika operasi update sedang dijalankan
Inserting / Updating onValidationFails YES
(sudah berhenti)
Dijalankan setelah validator integritas gagal
Inserting afterValidationOnCreate YES Dijalankan setelah kolom divalidasi untuk non nulls / string kosong atau foreign key ketika operasi penyisipan sedang dijalankan
Updating afterValidationOnUpdate YES Dijalankan setelah kolom divalidasi untuk non nulls / string kosong atau foreign key ketika operasi update sedang dijalankan
Inserting / Updating afterValidation YES Dijalankan setelah kolom divalidasi untuk non nulls / string kosong atau foreign key
Inserting / Updating beforeSave YES Berjalan sebelum operasi pada sistem database
Updating beforeUpdate YES Berjalan sebelum operasi pada sistem database hanya ketika sebuah operasi update sedang dibuat
Inserting beforeCreate YES Berjalan sebelum operasi padasistem database hanya jika operasi memasukkan sedang dibuat
Updating AfterUpdate NO Berjalan setelah operasi padasistem database hanya ketika sebuah operasi update sedang dibuat
Inserting afterCreate NO Berjalan setelah operasi pada sistem database hanya jika operasi memasukkan sedang dibuat
Inserting / Updating afterSave NO Berjalan setelah operasi pada sistem database

Implementasi Event di dalam Class Model 

Cara termudah untuk membuat model bereaksi terhadap event adalah menerapkan metode dengan nama yang sama dari event di vlass model:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    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\Model
{

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

}

Menggunakan Event Manajer Sendiri 

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

<?php

use Phalcon\Mvc\Model,
    Phalcon\Events\Manager as EventsManager;

class Robots extends Model
{

    public function initialize()
    {

        $eventsManager = new EventsManager();

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

        //Attach the events manager to the event
        $this->setEventsManager($eventsManager);
    }

}

Dalam contoh di atas, EventsManager hanya bertindak sebagai jembatan antara obyek dan pendengar (fungsi anonim). Event akan disalurkan ke pendengar ketika ‘robot’ disimpan:

<?php

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

Jika kita ingin semua objek yang dibuat dalam aplikasi kita menggunakan EventsManager yang sama, maka kita perlu menetapkan ke Model Manager:

<?php

//Registering the modelsManager service
$di->setShared('modelsManager', function() {

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

    //Attach an anonymous function as a listener for "model" events
    $eventsManager->attach('model', function($event, $model){

        //Catch events produced by the Robots 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 ModelsManager();
    $modelsManager->setEventsManager($eventsManager);
    return $modelsManager;
});

Jika pendengar mengembalikan nilai false maka akan menghentikan operasi yang sedang dieksekusi saat ini.

Menerapkan Aturan Bisnis 

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

Kami merekomendasikan bahwa metode validasi dideklarasikan protected untuk mencegah logika bisnis diakses 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\Model
{

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

}

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

Validasi Integritas data 

Phalcon \ MVC \ Model menyediakan beberapa event untuk memvalidasi data dan mengimplementasikan aturan bisnis. Event special “validasi” memungkinkan kita untuk memanggil validator built-in 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\Uniqueness;

class Robots extends \Phalcon\Mvc\Model
{

    public function validation()
    {

        $this->validate(new InclusionIn(
            array(
                "field"  => "type",
                "domain" => array("Mechanical", "Virtual")
            )
        ));

        $this->validate(new Uniqueness(
            array(
                "field"   => "name",
                "message" => "The robot name must be unique"
            )
        ));

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

}

Contoh di atas melakukan validasi dengan menggunakan built-in validator “InclusionIn”. Fungsi tsb memeriksa kesesuaian nilai field “type” dalam daftar domain. Jika nilai tidak termasuk dalam metode maka validator akan gagal dan mengembalikan nilai false. Berikut built-in validator yang tersedia:

Nama Penjelasan Contoh
PresenceOf Memvalidasi bahwa nilai kolom yang non null atau string kosong. Validator ini akan ditambahkan secara otomatis berdasarkan atribut yg ditandai sebagai non null pada tabel terkait Contoh
Email Memvalidasi bahwa kolom berisi format email yang valid Contoh
ExclusionIn Memvalidasi bahwa nilai tidak termasuk dalam daftar pengecualian Contoh
InclusionIn Memvalidasi bahwa nilai termasuk dalam daftar nilai yang mungkin Contoh
Numericality Memvalidasi bahwa field memiliki format numerik Contoh
Regex Memvalidasi bahwa nilai field sesuai dengan ekspresi reguler Contoh
Uniqueness Memvalidasi bahwa sebuah kolom atau kombinasi kolom yang tidak ada lebih dari sekali dalam record pada tabel terkait Contoh
StringLength Memvalidasi panjang string Contoh
Url Memvalidasi bahwa nilai memiliki format URL yang valid Contoh

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

<?php

use Phalcon\Mvc\Model\Validator,
    Phalcon\Mvc\Model\ValidatorInterface;

class MaxMinValidator extends Validator implements ValidatorInterface
{

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

        $min = $this->getOption('min');
        $max = $this->getOption('max');

        $value = $model->$field;

        if ($min <= $value && $value <= $max) {
            $this->appendMessage(
                "The field doesn't have the right range of values",
                $field,
                "MaxMinValidator"
            );
            return false;
        }
        return true;
    }

}

Menambahkan validator untuk model:

<?php

class Customers extends \Phalcon\Mvc\Model
{

    public function validation()
    {
        $this->validate(new MaxMinValidator(
            array(
                "field"  => "price",
                "min" => 10,
                "max" => 100
            )
        ));
        if ($this->validationHasFailed() == true) {
            return false;
        }
    }

}

Ide menciptakan validator adalah membuatnya dapat digunakan kembali pada beberapa model. Sebuah validator juga dapat dibuat sederhana seperti berikut:

<?php

use Phalcon\Mvc\Model,
    Phalcon\Mvc\Model\Message;

class Robots extends Model
{

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

}

Menghindari Injeksi SQL 

Setiap nilai yang diberikan untuk model atribut di-escape tergantung dari jenis datanya. Seorang pengembang tidak perlu untuk escape data secara manual pada setiap nilai sebelum menyimpannya ke database. Internal Phalcon menggunakan kelebihan bound parameter yang disediakan oleh PDO untuk secara otomatis escape setiap nilai yang akan disimpan dalam database.

mysql> desc products;
+------------------+------------------+------+-----+---------+----------------+
| Field            | Type             | Null | Key | Default | Extra          |
+------------------+------------------+------+-----+---------+----------------+
| id               | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| product_types_id | int(10) unsigned | NO   | MUL | NULL    |                |
| name             | varchar(70)      | NO   |     | NULL    |                |
| price            | decimal(16,2)    | NO   |     | NULL    |                |
| active           | char(1)          | YES  |     | NULL    |                |
+------------------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

Jika kita menggunakan hanya PDO untuk menyimpan record dengan cara yang aman, kita perlu menulis kode berikut:

<?php

$productTypesId = 1;
$name = 'Artichoke';
$price = 10.5;
$active = 'Y';

$sql = 'INSERT INTO products VALUES (null, :productTypesId, :name, :price, :active)';
$sth = $dbh->prepare($sql);

$sth->bindParam(':productTypesId', $productTypesId, PDO::PARAM_INT);
$sth->bindParam(':name', $name, PDO::PARAM_STR, 70);
$sth->bindParam(':price', doubleval($price));
$sth->bindParam(':active', $active, PDO::PARAM_STR, 1);

$sth->execute();

Kabar baiknya adalah bahwa Phalcon melakukan ini untuk Anda secara otomatis:

<?php

$product = new Products();
$product->product_types_id = 1;
$product->name = 'Artichoke';
$product->price = 10.5;
$product->active = 'Y';
$product->create();

Mengabaikan Kolom Tertentu 

Untuk memberitahu Phalcon\MVC\Model untuk selalu mengabaikan beberapa kolom dalam create dan / atau update record untuk mendelegasikan/menyerahkan tugas ini ke sistem database untuk memberikan dari nilai kolom sendiri baik melaui trigger atau nilai default kolom tsb:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        //Skips fields/columns on both INSERT/UPDATE operations
        $this->skipAttributes(array('year', 'price'));

        //Skips only when inserting
        $this->skipAttributesOnCreate(array('created_at'));

        //Skips only when updating
        $this->skipAttributesOnUpdate(array('modified_in'));
    }

}

Kode ini akan mengabaikan kolom tsb secara global pada setiap operasi INSERT / UPDATE di seluruh aplikasi. Memaksakan nilai default (dr database) bisa dilakukan dengan cara sebagai berikut:

<?php

$robot = new Robots();
$robot->name = 'Bender';
$robot->year = 1999;
$robot->created_at = new \Phalcon\Db\RawValue('default');
$robot->create();

Sebuah callback juga dapat digunakan untuk menyatakan kondisi kapan menggunakan nilai default (dr database) otomatis:

<?php

use Phalcon\Mvc\Model,
    Phalcon\Db\RawValue;

class Robots extends Model
{
    public function beforeCreate()
    {
        if ($this->price > 10000) {
            $this->type = new RawValue('default');
        }
    }
}

Jangan menggunakan \Phalcon\Db\RawValue untuk menetapkan nilai data eksternal (seperti input pengguna) atau data variabel. Nilai kolom ini akan diabaikan ketika binding parameter pada query. Jadi bisa digunakan untuk menyerang aplikasi, menyuntikkan SQL.

Update Dinamis 

Pernyataan UPDATE SQL yang secara default dibuat dengan setiap kolom yang didefinisikan dalam model (SQL full update semuakolom). Anda dapat mengubah model tertentu untuk melakukan update dinamis, dalam hal ini, hanya kolom yang telah berubah digunakan untuk membuat pernyataan SQL final.

Dalam beberapa kasus, cara ini dapat meningkatkan kinerja dengan mengurangi lalu lintas antara aplikasi dan database server, khususnya ketika tabel memiliki field blob / text:

<?php

class Robots extends Phalcon\Mvc\Model
{
    public function initialize()
    {
        $this->useDynamicUpdate(true);
    }
}

Menghapus Record 

Metode Phalcon\MVC\Model::delete() memungkinkan untuk menghapus catatan. Anda dapat menggunakannya sebagai berikut:

<?php

$robot = Robots::findFirst(11);
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 record dengan menelusuri resultset dengan foreach:

<?php

foreach (Robots::find("type='mechanical'") 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/sendiri yang dapat dieksekusi ketika operasi delete dilakukan:

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

Dengan event di atas juga dapat didefinisikan aturan bisnis dalam model:

<?php

class Robots extends Phalcon\Mvc\Model
{

    public function beforeDelete()
    {
        if ($this->status == 'A') {
            echo "The robot is active, it can't be deleted";
            return false;
        }
        return true;
    }

}

Event Validasi Gagal 

Selain itu jg ada event lainnya yang tersedia ketika proses validasi data menemukan ketidaksesuaian:

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

Perilaku/Behaviour 

Perilaku ini adalah salah satu bentuk pengolahan data pada model yg dapat diterapkan ke beberapa model. Sehingga dapat mengadopsi/ menggunakan kembali kode yg sama, ORM menyediakan API untuk menerapkan perilaku dalam model Anda. Juga, Anda dapat menggunakan event dan callback seperti yang terlihat sebelumnya sebagai alternatif untuk menerapkan Perilaku dengan lebih banyak kebebasan.

Sebuah perilaku harus ditambahkan dalam model initializer, model bebas memiliki perilaku bersama ini:

<?php

use Phalcon\Mvc\Model\Behavior\Timestampable;

class Users extends \Phalcon\Mvc\Model
{
    public $id;

    public $name;

    public $created_at;

    public function initialize()
    {
        $this->addBehavior(new Timestampable(
            array(
                'beforeCreate' => array(
                    'field' => 'created_at',
                    'format' => 'Y-m-d'
                )
            )
        ));
    }

}

Perilaku built-in berikut disediakan oleh framework:

Nama Deskripsi
Timestampable Memungkinkan untuk secara otomatis memperbarui model atribut tabungan datetime ketika record yang dibuat atau diperbarui
SoftDelete Alih-alih secara permanen menghapus catatan itu menandai catatan sebagai dihapus mengubah nilai kolom bendera

Timestampable 

Perilaku ini menerima berbagai pilihan, key tingkat pertama harus nama event yang menunjukkan saat kolom harus dimodifikasi nilainya:

<?php

public function initialize()
{
    $this->addBehavior(new Timestampable(
        array(
            'beforeCreate' => array(
                'field' => 'created_at',
                'format' => 'Y-m-d'
            )
        )
    ));
}

Setiap event dapat memiliki pilihan sendiri, ‘field’ adalah nama dari kolom yang harus diperbarui, jika ‘format’ adalah string maka akan digunakan sebagai format dari fungsi PHP date, format yang juga bisa menjadi fungsi anonim memberikan Anda kebebasan untuk menghasilkan setiap jenis timestamp :

<?php

public function initialize()
{
    $this->addBehavior(new Timestampable(
        array(
            'beforeCreate' => array(
                'field' => 'created_at',
                'format' => function() {
                    $datetime = new Datetime(new DateTimeZone('Europe/Stockholm'));
                    return $datetime->format('Y-m-d H:i:sP');
                }
            )
        )
    ));
}

Jika opsi ‘format’ dihilangkan timestamp menggunakan fungsi PHP time.

SoftDelete 

Perilaku ini dapat digunakan dengan cara berikut:

<?php

use Phalcon\Mvc\Model\Behavior\SoftDelete;

class Users extends \Phalcon\Mvc\Model
{

    const DELETED = 'D';

    const NOT_DELETED = 'N';

    public $id;

    public $name;

    public $status;

    public function initialize()
    {
        $this->addBehavior(new SoftDelete(
            array(
                'field' => 'status',
                'value' => Users::DELETED
            )
        ));
    }

}

Perilaku ini menerima dua pilihan: ‘field’ dan ‘value’; ‘field’ menentukan kolom apa harus diperbarui dan ‘value’ nilai yang akan dihapus. Mari kita menganggap tabel ‘users’ memiliki data sebagai berikut:

mysql> select * from users;
+----+---------+--------+
| id | name    | status |
+----+---------+--------+
|  1 | Lana    | N      |
|  2 | Brandon | N      |
+----+---------+--------+
2 rows in set (0.00 sec)

Jika kita menghapus salah satu record, status akan diperbarui bukannya menghapus record:

<?php

Users::findFirst(2)->delete();

Operasi ini akan menghasilkan data berikut dalam tabel:

mysql> select * from users;
+----+---------+--------+
| id | name    | status |
+----+---------+--------+
|  1 | Lana    | N      |
|  2 | Brandon | D      |
+----+---------+--------+
2 rows in set (0.01 sec)

Perhatikan bahwa Anda perlu menentukan kondisi record yg statusnya terhapus dalam query Anda untuk secara efektif mengabaikanya sehingga dianggap sebagai record yg telah dihapus, perilaku ini tidak bekerja hingga fungsi tsb.

Menciptakan Perilaku Anda sendiri 

ORM menyediakan API untuk membuat perilaku Anda sendiri. Sebuah perilaku harus menjadi class yang mengimplementasikan Phalcon \ MVC \ Model \ BehaviorInterface. Juga, Phalon\MVC\Model\Behavior menyediakan sebagian besar metode yang diperlukan untuk mempermudah implementasi perilaku.

Perilaku berikut ini adalah contoh, menerapkan perilaku Blamable yang membantu mengidentifikasi pengguna yang melakukan operasi atas model:

<?php

use Phalcon\Mvc\Model\Behavior;
use Phalcon\Mvc\Model\BehaviorInterface;

class Blameable extends Behavior implements BehaviorInterface
{

    public function notify($eventType, $model)
    {
        switch ($eventType) {

            case 'afterCreate':
            case 'afterDelete':
            case 'afterUpdate':


                $userName = // ... get the current user from session

                //Store in a log the username - event type and primary key
                file_put_contents(
                    'logs/blamable-log.txt',
                    $userName . ' ' . $eventType . ' ' . $model->id
                );

                break;

            default:
                /* ignore the rest of events */
        }
    }

}

Diatas adalah perilaku yang sangat sederhana, tetapi ini menggambarkan bagaimana menciptakan perilaku, sekarang mari kita menambahkan perilaku ini untuk model:

<?php

class Profiles extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->addBehavior(new Blamable());
    }

}

Sebuah perilaku juga mampu menangkap metode yg hilang pada model Anda:

<?php

use Phalcon\Mvc\Model\Behavior,
    Phalcon\Mvc\Model\BehaviorInterface;

class Sluggable extends Behavior implements BehaviorInterface
{

    public function missingMethod($model, $method, $arguments=array())
    {
        // if the method is 'getSlug' convert the title
        if ($method == 'getSlug') {
            return Phalcon\Tag::friendlyTitle($model->title);
        }
    }

}

Memanggil metode tersebut pada model yang mengimplementasikan Sluggable, mengembalikan judul SEO friendly:

<?php

$title = $post->getSlug();

Menggunakan Trait sebagai perilaku 

Mulai dari PHP 5.4 Anda dapat menggunakan Trait untuk menggunakan kembali kode dalam class Anda, ini adalah cara lain untuk menerapkan perilaku kustom. Trait berikut mengimplementasikan versi sederhana dari perilaku Timestampable:

<?php

trait MyTimestampable
{

    public function beforeCreate()
    {
        $this->created_at = date('r');
    }

    public function beforeUpdate()
    {
        $this->updated_at = date('r');
    }

}

Kemudian Anda dapat menggunakannya dalam model Anda sebagai berikut:

<?php

class Products extends \Phalcon\Mvc\Model
{
    use MyTimestampable;
}

Transaksi 

Ketika proses melakukan beberapa operasi database, sering bahwa setiap langkah berhasil diselesaikan sehingga integritas data dapat dipertahankan. Transaksi menawarkan kemampuan untuk memastikan bahwa semua operasi database telah dilaksanakan dengan sukses sebelum data berkomitmen untuk database.

Transaksi dalam Phalcon memungkinkan Anda untuk melakukan semua operasi jika semua telah dilaksanakan dengan sukses atau rollback semua operasi jika sesuatu yang tidak beres.

Transaksi manual 

Jika sebuah aplikasi hanya menggunakan satu koneksi dan transaksi yang tidak terlalu rumit, transaksi dapat dibuat dengan hanya memindahkan koneksi saat ini untuk mode transaksi, melakukan rollback atau commit jika operasi ini berhasil atau tidak:

<?php

class RobotsController extends Phalcon\Mvc\Controller
{
    public function saveAction()
    {
        $this->db->begin();

        $robot = new Robots();

        $robot->name = "WALL·E";
        $robot->created_at = date("Y-m-d");
        if ($robot->save() == false) {
            $this->db->rollback();
            return;
        }

        $robotPart = new RobotParts();
        $robotPart->robots_id = $robot->id;
        $robotPart->type = "head";
        if ($robotPart->save() == false) {
            $this->db->rollback();
            return;
        }

        $this->db->commit();
    }
}

Transaksi Implisit 

Relasi yang ada dapat digunakan untuk menyimpan record dan instance terkait, operasi semacam ini secara implisit menciptakan transaksi untuk memastikan bahwa data yang disimpan dengan benar:

<?php

$robotPart = new RobotParts();
$robotPart->type = "head";

$robot = new Robots();
$robot->name = "WALL·E";
$robot->created_at = date("Y-m-d");
$robot->robotPart = $robotPart;

$robot->save(); //Creates an implicit transaction to store both records

Transaksi Terisolasi 

Transaksi terisolasi dijalankan dalam koneksi baru, memastikan semua SQL yang dihasilkan, pemeriksaan foreign key virtual dan aturan bisnis terisolasi dari koneksi utama.Transaksi semacam ini membutuhkan transaction manager yang secara global mengelola setiap transaksi yg dibuat, memastikan bahwa semua benar-benar rollback/commit sebelum mengakhiri request:

<?php

use Phalcon\Mvc\Model\Transaction\Manager as TxManager,
    Phalcon\Mvc\Model\Transaction\Failed as TxFailed;

try {

    //Create a transaction manager
    $manager = new TxManager();

    // Request a transaction
    $transaction = $manager->get();

    $robot = new Robots();
    $robot->setTransaction($transaction);
    $robot->name = "WALL·E";
    $robot->created_at = date("Y-m-d");
    if ($robot->save() == false) {
        $transaction->rollback("Cannot save robot");
    }

    $robotPart = new RobotParts();
    $robotPart->setTransaction($transaction);
    $robotPart->robots_id = $robot->id;
    $robotPart->type = "head";
    if ($robotPart->save() == false) {
        $transaction->rollback("Cannot save robot part");
    }

    //Everything goes fine, let's commit the transaction
    $transaction->commit();

} catch(TxFailed $e) {
    echo "Failed, reason: ", $e->getMessage();
}

Transaksi dapat digunakan untuk menghapus banyak catatan dengan cara yang konsisten:

<?php

use Phalcon\Mvc\Model\Transaction\Manager as TxManager,
    Phalcon\Mvc\Model\Transaction\Failed as TxFailed;

try {

    //Create a transaction manager
    $manager = new TxManager();

    //Request a transaction
    $transaction = $manager->get();

    //Get the robots will be deleted
    foreach (Robots::find("type = 'mechanical'") as $robot) {
        $robot->setTransaction($transaction);
        if ($robot->delete() == false) {
            //Something goes wrong, we should to rollback the transaction
            foreach ($robot->getMessages() as $message) {
                $transaction->rollback($message->getMessage());
            }
        }
    }

    //Everything goes fine, let's commit the transaction
    $transaction->commit();

    echo "Robots were deleted successfully!";

} catch(TxFailed $e) {
    echo "Failed, reason: ", $e->getMessage();
}

Transaksi digunakan kembali di mana pun objek transaksi diambil. Sebuah transaksi baru yang dihasilkan hanya ketika commit() atau rollback() dilakukan. Anda dapat menggunakan wadah layanan untuk membuat manajer transaksi global untuk seluruh aplikasi:

<?php

$di->setShared('transactions', function(){
    return new \Phalcon\Mvc\Model\Transaction\Manager();
});

Kemudian mengaksesnya dari controller atau view:

<?php

class ProductsController extends \Phalcon\Mvc\Controller
{

    public function saveAction()
    {

        //Obtain the TransactionsManager from the services container
        $manager = $this->di->getTransactions();

        //Or
        $manager = $this->transactions;

        //Request a transaction
        $transaction = $manager->get();

        //...
    }

}

Sementara transaksi aktif, manajer transaksi akan selalu mengembalikan objek transaksi yang sama di seluruh aplikasi.

Pemetaan Kolom Independen 

ORM mendukung pemetaan kolom yang bebas, yang memungkinkan pengembang untuk menggunakan nama kolom yang berbeda dibandingkan dgn tabel yg terkait. Phalcon akan mengenali nama kolom baru dan akan mengubah nama mereka diserasikan dgn masing-masing kolom dalam database. Ini adalah fitur yang hebat ketika memiliki kebutuhan untuk mengubah nama field dalam database tanpa harus khawatir dgn semua kode query. Perubahan pada pemetaan kolom dalam model akan mengurus itu semua. Sebagai contoh:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function columnMap()
    {
        //Keys are the real names in the table and
        //the values their names in the application
        return array(
            'id' => 'code',
            'the_name' => 'theName',
            'the_type' => 'theType',
            'the_year' => 'theYear'
        );
    }

}

Kemudian Anda dapat menggunakan nama-nama baru seperti biasa dalam kode Anda:

<?php

//Find a robot by its name
$robot = Robots::findFirst("theName = 'Voltron'");
echo $robot->theName, "\n";

//Get robots ordered by type
$robot = Robots::find(array('order' => 'theType DESC'));
foreach ($robots as $robot) {
    echo 'Code: ', $robot->code, "\n";
}

//Create a robot
$robot = new Robots();
$robot->code = '10101';
$robot->theName = 'Bender';
$robot->theType = 'Industrial';
$robot->theYear = 2999;
$robot->save();

Perhatikan hal-hal berikut ketika mengubah nama kolom Anda:

  • Referensi atribut dalam relationship / validator harus menggunakan nama baru
  • Menggunakan nama kolom yang sebenarnya akan menghasilkan exception pada ORM

Manfaat pemetaan kolom independen ini antara lain:

  • Menuliskan aplikasi yang menggunakan kaidah/kenyamanan Anda sendiri
  • Menghilangkan prefiks / sufiks dr vendor dalam kode Anda
  • Mengubah nama kolom tanpa mengubah kode aplikasi Anda

Operasi Pada Resultset 

Jika resultset yang terdiri dari objek lengkap, ResultSet adalah kemampuan untuk melakukan operasi pada record yang diperoleh dengan cara yang sederhana:

Snapshot Record 

Model tertentu bisa diatur untuk mempertahankan snapshot record ketika di-query. Anda dapat menggunakan fitur ini untuk melaksanakan audit atau hanya untuk mengetahui kolom apa yang berubah sesuai dengan query data yg tersimpan:

<?php

class Robots extends Phalcon\Mvc\Model
{
    public function initialize()
    {
        $this->keepSnapshots(true);
    }
}

Ketika mengaktifkan fitur ini aplikasi mengkonsumsi memori sedikit lebih besar untuk melacak nilai-nilai asli yang diperoleh dari data yg tersimpan. Dalam model dimana fitur ini diaktifkan, Anda dapat memeriksa kolom apa yg berubah:

<?php

//Get a record from the database
$robot = Robots::findFirst();

//Change a column
$robot->name = 'Other name';

var_dump($robot->getChangedFields()); // ['name']
var_dump($robot->hasChanged('name')); // true
var_dump($robot->hasChanged('type')); // false

Model Meta-Data 

Untuk mempercepat pengembangan, Phalcon \ MVC \ Model membantu Anda untuk query kolom dan constraint/batasan dari tabel yang terkait dengan model. Untuk mencapai hal ini, Phalcon \ MVC \ Model \ metadata tersedia untuk mengelola dan men-cache tabel meta-data.

Kadang-kadang diperlukan untuk mendapatkan atribut-atribut ketika bekerja dengan model. Anda bisa mendapatkan instance meta-data sebagai berikut:

<?php

$robot = new Robots();

// Get Phalcon\Mvc\Model\Metadata instance
$metaData = $robot->getModelsMetaData();

// Get robots fields names
$attributes = $metaData->getAttributes($robot);
print_r($attributes);

// Get robots fields data types
$dataTypes = $metaData->getDataTypes($robot);
print_r($dataTypes);

Caching Meta-Data 

Setelah aplikasi ini dalam tahap produksi (diterapkan pada lapangan sebenarnya), tidak perlu untuk query meta-data tabel dari sistem database setiap kali Anda menggunakan tabel. Ini dapat dilakukan caching meta-data menggunakan salah satu adapter berikut:

Adaptor Deskripsi API
Memory Ini adalah adaptor default. Meta-data di-cache hanya selama request. Ketika request selesai, meta-data dihapus dianggap sebagai bagian dari memori request normal. Adaptor ini sangat cocok ketika aplikasi dalam development sehingga dapat me-refresh meta-data dalam setiap request yang berisi kolom baru dan / atau modifikasi. Phalcon \ MVC \ Model \ metadata \ Memory
Session Adapter ini menyimpan meta-data dalam $_SESSION superglobal. Adaptor ini hanya disarankan saat aplikasi benar-benar menggunakan sejumlah kecil model. Meta-data refresh setiap kali sesi baru dimulai. Hal ini juga memerlukan penggunaan session_start() untuk memulai sesi sebelum menggunakan model apapun. Phalcon \ MVC \ Model \ metadata \ Session
Apc Adaptor ini menggunakan Alternative PHP Cache (APC) untuk menyimpan meta-data tabel. Anda dapat menentukan masa-pakai meta-data dengan opsinya. Ini adalah cara yang paling dianjurkan untuk menyimpan meta-data bila aplikasi tersebut dalam tahap produksi. Phalcon \ MVC \ Model \ metadata \ APC
XCache Adaptor ini menggunakan XCache untuk menyimpan meta-data tabel. Anda dapat menentukan masa-pakai meta-data dengan opsinya. Ini adalah cara yang paling dianjurkan untuk menyimpan meta-data bila aplikasi tersebut dalam tahap produksi. Phalcon \ MVC \ Model \ metadata \ XCache
Files Adaptor ini menggunakan file biasa untuk menyimpan meta-data. Dengan menggunakan adaptor ini pembacaan-disk meningkat tetapi akses database berkurang Phalcon \ MVC \ Model \ metadata \ Files

Sebagai dependensi lain ORM, metadata-manajer diambil dari wadah layanan:

<?php

$di['modelsMetadata'] = function() {

    // Create a meta-data manager with APC
    $metaData = new \Phalcon\Mvc\Model\MetaData\Apc(array(
        "lifetime" => 86400,
        "prefix"   => "my-prefix"
    ));

    return $metaData;
};

Strategi Meta-Data 

Seperti disebutkan di atas strategi default untuk mendapatkan meta-data model adalah basis data introspeksi. Dalam strategi ini, skema informasi digunakan untuk mengetahui bidang dalam sebuah tabel, kunci primer, bidang nullable, tipe data, dll

Anda dapat mengubah default meta-data introspeksi dengan cara sebagai berikut:

<?php

$di['modelsMetadata'] = function() {

    // Instantiate a meta-data adapter
    $metaData = new \Phalcon\Mvc\Model\MetaData\Apc(array(
        "lifetime" => 86400,
        "prefix"   => "my-prefix"
    ));

    //Set a custom meta-data introspection strategy
    $metaData->setStrategy(new MyInstrospectionStrategy());

    return $metaData;
};

Strategi Introspeksi Database 

Strategi ini tidak memerlukan kostumisasi apapun dan secara implisit digunakan oleh semua adapter meta-data.

Strategi Anotasi 

Strategi ini memanfaatkan Annotations (penjelasan) untuk menggambarkan kolom dalam model:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    /**
     * @Primary
     * @Identity
     * @Column(type="integer", nullable=false)
     */
    public $id;

    /**
     * @Column(type="string", length=70, nullable=false)
     */
    public $name;

    /**
     * @Column(type="string", length=32, nullable=false)
     */
    public $type;

    /**
     * @Column(type="integer", nullable=false)
     */
    public $year;

}

Penjelasan harus ditempatkan dalam properti yang dipetakan ke kolom dalam sumber. Properti tanpa penjelasan @Column ditangani sebagai atribut kelas sederhana.

Penjelasan berikut ini didukung:

Nama Deskripsi
Primary Tanda kolom sebagai bagian dari primary key tabel
Identity Bidang ini adalah auto_increment / kolom serial
Column Ini menandai atribut sebagai pemetaan kolom tabel

Anotasi @Column mendukung parameter berikut:

Nama Deskripsi
type Jenis kolom (string, integer, desimal, boolean)
length Panjang kolom jika ada
nullable Setel apakah kolom menerima nilai null atau tidak

Strategi anotasi dapat dibentuk dengan cara ini:

<?php

use Phalcon\Mvc\Model\MetaData\Apc as ApcMetaData,
    Phalcon\Mvc\Model\MetaData\Strategy\Annotations as StrategyAnnotations;

$di['modelsMetadata'] = function() {

    // Instantiate a meta-data adapter
    $metaData = new ApcMetaData(array(
        "lifetime" => 86400,
        "prefix"   => "my-prefix"
    ));

    //Set a custom meta-data database introspection
    $metaData->setStrategy(new StrategyAnnotations());

    return $metaData;
};

Panduan Meta-Data 

Phalcon dapat memperoleh metadata untuk setiap model secara otomatis tanpa pengembang harus mengatur secara manual dengan menggunakan salah satu strategi introspeksi yang disajikan di atas.

Pengembang juga memiliki pilihan untuk menentukan metadata secara manual. Strategi ini menimpa setiap strategi yang ditetapkan pada manajer meta-data. Kolom baru ditambahkan / diubah / dihapus ke / dari tabel yg dipetakan harus ditambahkan / diubah / dihapus juga agar berfungsi dengan benar.

Contoh berikut ini menunjukkan bagaimana untuk menentukan meta-data secara manual:

<?php

use Phalcon\Mvc\Model,
    Phalcon\Db\Column,
    Phalcon\Mvc\Model\MetaData;

class Robots extends Model
{

    public function metaData()
    {
        return array(

            //Every column in the mapped table
            MetaData::MODELS_ATTRIBUTES => array(
                'id', 'name', 'type', 'year'
            ),

            //Every column part of the primary key
            MetaData::MODELS_PRIMARY_KEY => array(
                'id'
            ),

            //Every column that isn't part of the primary key
            MetaData::MODELS_NON_PRIMARY_KEY => array(
                'name', 'type', 'year'
            ),

            //Every column that doesn't allows null values
            MetaData::MODELS_NOT_NULL => array(
                'id', 'name', 'type', 'year'
            ),

            //Every column and their data types
            MetaData::MODELS_DATA_TYPES => array(
                'id' => Column::TYPE_INTEGER,
                'name' => Column::TYPE_VARCHAR,
                'type' => Column::TYPE_VARCHAR,
                'year' => Column::TYPE_INTEGER
            ),

            //The columns that have numeric data types
            MetaData::MODELS_DATA_TYPES_NUMERIC => array(
                'id' => true,
                'year' => true,
            ),

            //The identity column, use boolean false if the model doesn't have
            //an identity column
            MetaData::MODELS_IDENTITY_COLUMN => 'id',

            //How every column must be bound/casted
            MetaData::MODELS_DATA_TYPES_BIND => array(
                'id' => Column::BIND_PARAM_INT,
                'name' => Column::BIND_PARAM_STR,
                'type' => Column::BIND_PARAM_STR,
                'year' => Column::BIND_PARAM_INT,
            ),

            //Fields that must be ignored from INSERT SQL statements
            MetaData::MODELS_AUTOMATIC_DEFAULT_INSERT => array(
                'year' => true
            ),

            //Fields that must be ignored from UPDATE SQL statements
            MetaData::MODELS_AUTOMATIC_DEFAULT_UPDATE => array(
                'year' => true
            )

        );
    }

}

Menunjuk ke skema/databse yang berbeda 

Jika model dipetakan ke tabel yang berada dalam skema/database yang berbeda dari default. Anda dapat menggunakan metode getSchema untuk menentukan bahwa:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function getSchema()
    {
        return "toys";
    }

}

Mengatur beberapa database 

Dalam Phalcon, semua model dapat berasal dari koneksi database yang sama atau berbeda sendiri. Sebenarnya, ketika Phalcon \ MVC \ Model perlu koneksi ke database itu meminta layanan “db” ke jasa kontainer aplikasi. Anda dapat menimpa pengaturan layanan ini dalam metode initialize:

<?php

//This service returns a MySQL database
$di->set('dbMysql', function() {
     return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => "localhost",
        "username" => "root",
        "password" => "secret",
        "dbname" => "invo"
    ));
});

//This service returns a PostgreSQL database
$di->set('dbPostgres', function() {
     return new \Phalcon\Db\Adapter\Pdo\PostgreSQL(array(
        "host" => "localhost",
        "username" => "postgres",
        "password" => "",
        "dbname" => "invo"
    ));
});

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

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->setConnectionService('dbPostgres');
    }

}

Tapi Phalcon menawarkan fleksibilitas yang lebih, Anda dapat menentukan koneksi yang harus digunakan untuk ‘membaca’ dan ‘menulis’. Hal ini khususnya berguna untuk menyeimbangkan beban ke database Anda untuk menerapkan arsitektur master-slave:

<?php

class Robots extends \Phalcon\Mvc\Model
{

    public function initialize()
    {
        $this->setReadConnectionService('dbSlave');
        $this->setWriteConnectionService('dbMaster');
    }

}

ORM juga menyediakan fasilitas Sharding Horizontal, dengan memungkinkan Anda untuk menerapkan ‘shard’ (pecahan) seleksi menyesuaikan dengan kondisi query saat ini:

<?php

class Robots extends Phalcon\Mvc\Model
{
    /**
     * Dynamically selects a shard
     *
     * @param array $intermediate
     * @param array $bindParams
     * @param array $bindTypes
     */
    public function selectReadConnection($intermediate, $bindParams, $bindTypes)
    {
        //Check if there is a 'where' clause in the select
        if (isset($intermediate['where'])) {

            $conditions = $intermediate['where'];

            //Choose the possible shard according to the conditions
            if ($conditions['left']['name'] == 'id') {
                $id = $conditions['right']['value'];
                if ($id > 0 && $id < 10000) {
                    return $this->getDI()->get('dbShard1');
                }
                if ($id > 10000) {
                    return $this->getDI()->get('dbShard2');
                }
            }
        }

        //Use a default shard
        return $this->getDI()->get('dbShard0');
    }

}

Metode ‘selectReadConnection’ dipanggil untuk memilih koneksi yang tepat, metode ini memotong (intercept) setiap query baru yg dieksekusi:

<?php

$robot = Robots::findFirst('id = 101');

Logging Statement SQL Low-level 

Bila menggunakan abstraksi komponen tingkat-tinggi seperti Phalcon \ MVC \ Model untuk mengakses database, sulit untuk memahami statemen SQL yang akhirnya dikirim ke sistem database. Phalcon \ MVC \ Model didukung secara internal oleh Phalcon \ Db . Phalcon \ Logger berinteraksi dengan Phalcon \ Db , menyediakan kemampuan logging pada lapisan abstraksi database, sehingga memungkinkan kita untuk membuat log pernyataan SQL yg tereksekusi.

<?php

use Phalcon\Logger,
    Phalcon\Db\Adapter\Pdo\Mysql as Connection,
    Phalcon\Events\Manager,
    Phalcon\Logger\Adapter\File;

$di->set('db', function() {

    $eventsManager = new EventsManager();

    $logger = new Logger("app/logs/debug.log");

    //Listen all the database events
    $eventsManager->attach('db', function($event, $connection) use ($logger) {
        if ($event->getType() == 'beforeQuery') {
            $logger->log($connection->getSQLStatement(), Logger::INFO);
        }
    });

    $connection = new Connection(array(
        "host" => "localhost",
        "username" => "root",
        "password" => "secret",
        "dbname" => "invo"
    ));

    //Assign the eventsManager to the db adapter instance
    $connection->setEventsManager($eventsManager);

    return $connection;
});

Sebagaimana model mengakses koneksi database default, semua pernyataan SQL yang dikirim ke sistem database akan dicatat dalam file:

<?php

$robot = new Robots();
$robot->name = "Robby the Robot";
$robot->created_at = "1956-07-21";
if ($robot->save() == false) {
    echo "Cannot save robot";
}

Seperti di atas, aplikasi / file log / db.log akan berisi sesuatu seperti ini:

[Mon, 30 Apr 12 13:47:18 -0500][DEBUG][Resource Id #77] INSERT INTO robots
(name, created_at) VALUES ('Robby the Robot', '1956-07-21')

Profiler Statemen SQL 

Berkat Phalcon \ Db , komponen yang mendasari Phalcon \ MVC \ Model , sangat mungkin untuk membuat profile pernyataan SQL yang dihasilkan oleh ORM dalam rangka untuk menganalisis kinerja operasi database. Dengan ini Anda dapat mendiagnosa masalah kinerja dan untuk menemukan bottleneck.

<?php

$di->set('profiler', function(){
    return new \Phalcon\Db\Profiler();
}, true);

$di->set('db', function() use ($di) {

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

    //Get a shared instance of the DbProfiler
    $profiler = $di->getProfiler();

    //Listen all the database events
    $eventsManager->attach('db', function($event, $connection) use ($profiler) {
        if ($event->getType() == 'beforeQuery') {
            $profiler->startProfile($connection->getSQLStatement());
        }
        if ($event->getType() == 'afterQuery') {
            $profiler->stopProfile();
        }
    });

    $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => "localhost",
        "username" => "root",
        "password" => "secret",
        "dbname" => "invo"
    ));

    //Assign the eventsManager to the db adapter instance
    $connection->setEventsManager($eventsManager);

    return $connection;
});

Profiling beberapa query:

<?php

// Send some SQL statements to the database
Robots::find();
Robots::find(array("order" => "name"));
Robots::find(array("limit" => 30));

//Get the generated profiles from the profiler
$profiles = $di->get('profiler')->getProfiles();

foreach ($profiles as $profile) {
   echo "SQL Statement: ", $profile->getSQLStatement(), "\n";
   echo "Start Time: ", $profile->getInitialTime(), "\n";
   echo "Final Time: ", $profile->getFinalTime(), "\n";
   echo "Total Elapsed Time: ", $profile->getTotalElapsedSeconds(), "\n";
}

Setiap profil yang dihasilkan mengandung durasi dalam milidetik bahwa setiap instruksi yang diperlukan untuk menyelesaikan serta statemen SQL yang dihasilkan.

Injeksi Service Dalam Model 

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

<?php

class Robots extends \Phalcon\Mvc\Model
{

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

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

}

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

Menonaktifkan / Mengaktifkan Fitur 

Dalam ORM kami telah menerapkan mekanisme yang memungkinkan Anda untuk mengaktifkan / menonaktifkan fitur khusus atau opsi global dengan cepat. Sebagaimana Anda menggunakan ORM, Anda dapat menonaktifkan yg tidak Anda gunakan. Opsi ini juga dapat dinonaktifkan sementara jika diperlukan:

<?php

\Phalcon\Mvc\Model::setup(array(
    'events' => false,
    'columnRenaming' => false
));

Pilihan yang tersedia adalah:

Pilihan Deskripsi Kegagalan
events Mengaktifkan / Menonaktifkan callback, kait dan pemberitahuan event dari semua model benar
columnRenaming Mengaktifkan / Menonaktifkan penggantian nama kolom benar
notNullValidations ORM otomatis memvalidasi kolom tidak null hadir dalam tabel yg dipetakan benar
virtualForeignKeys Mengaktifkan / Menonaktifkan foreign key virtual benar
phqlLiterals Mengaktifkan / Menonaktifkan literal dalam parser PHQL benar

Komponen Stand-Alone  

Menggunakan Phalcon \ Mvc \ Model dalam mode stand-alone dapat ditunjukkan di bawah ini:

<?php

use Phalcon\DI,
    Phalcon\Db\Adapter\Pdo\Sqlite as Connection,
    Phalcon\Mvc\Model\Manager as ModelsManager,
    Phalcon\Mvc\Model\Metadata\Memory as MetaData,
    Phalcon\Mvc\Model;

$di = new DI();

//Setup a connection
$di->set('db', new Connection(array(
    "dbname" => "sample.db"
)));

//Set a models manager
$di->set('modelsManager', new ModelsManager());

//Use the memory meta-data adapter or other
$di->set('modelsMetadata', new MetaData());

//Create a model
class Robots extends Model
{

}

//Use the model
echo Robots::count();

 

Terjemah dari Bekerja dengan Model Phalcon
http://docs.phalconphp.com/en/latest/reference/models.html