Working with Models

A model represents the information (data) of the application and the rules to manipulate that data. Models are primarily used for managing the rules of interaction with a corresponding database table. In most cases, each table in your database will correspond to one model in your application. The bulk of your application’s business logic will be concentrated in the models.

Phalcon\Mvc\Model is the base for all models in a Phalcon application. It provides database independence, basic
CRUD functionality, advanced finding capabilities, and the ability to relate models to one another, among other services. Phalcon\Mvc\Model avoids the need of having to use SQL statements because it translates
methods dynamically to the respective database engine operations.

Models are intended to work with the database on a high layer of abstraction. If you need to work with databases at a lower level check out the Phalcon\Db component documentation.

Creating Models

A model is a class that extends from Phalcon\Mvc\Model. Its class name should be in camel case notation:

The model RobotParts now maps to toys_robot_parts table. The initialize() method helps with setting up this model with a custom behavior i.e. a different table.

The initialize() method is only called once during the request. This method is intended to perform initializations that apply for all instances of the model created within the application. If you want to perform initialization tasks for every instance created you can use the onConstruct() method:

Another implementation is to use getters and setter functions, which control which properties are publicly available for that model. The benefit of using getters and setters is that the developer can perform transformations and validation checks on the values set for the model, which is impossible when using public properties. Additionally getters and setters allow for future changes without changing the interface of the model class. So if a field name changes, the only change needed will be in the private property of the model referenced in the relevant getter/setter and nowhere else in the code.

<?phpnamespaceStore\Toys;useInvalidArgumentException;usePhalcon\Mvc\Model;classRobotsextendsModel{protected$id;protected$name;protected$price;publicfunctiongetId(){return$this->id;}publicfunctionsetName($name){// The name is too short?if(strlen($name)<10){thrownewInvalidArgumentException('The name is too short');}$this->name=$name;}publicfunctiongetName(){return$this->name;}publicfunctionsetPrice($price){// Negative prices aren't allowedif($price<0){thrownewInvalidArgumentException("Price can't be negative");}$this->price=$price;}publicfunctiongetPrice(){// Convert the value to double before be usedreturn(double)$this->price;}}

Public properties provide less complexity in development. However getters/setters can heavily increase the testability,
extensibility and maintainability of applications. Developers can decide which strategy is more appropriate for the
application they are creating, depending on the needs of the application. The ORM is compatible with both schemes of defining properties.

Underscores in property names can be problematic when using getters and setters.

If you use underscores in your property names, you must still use camel case in your getter/setter declarations for use
with magic methods. (e.g. $model->getPropertyName instead of $model->getProperty_name, $model->findByPropertyName
instead of $model->findByProperty_name, etc.). As much of the system expects camel case, and underscores are commonly
removed, it is recommended to name your properties in the manner shown throughout the documentation. You can use a
column map (as described above) to ensure proper mapping of your properties to their database counterparts.

Understanding Records To Objects

Every instance of a model represents a row in the table. You can easily access record data by reading object properties. For example, for a table ‘robots’ with the records:

As you can see, there is no need to use raw SQL statements. Phalcon\Mvc\Model provides high database abstraction for web applications.

Finding Records

Phalcon\Mvc\Model also offers several methods for querying records. The following examples will show you how to query one or more records from a model:

<?phpuseStore\Toys\Robots;// 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(["type = 'virtual'",'order'=>'name',]);foreach($robotsas$robot){echo$robot->name,"\n";}// Get first 100 virtual robots ordered by name$robots=Robots::find(["type = 'virtual'",'order'=>'name','limit'=>100,]);foreach($robotsas$robot){echo$robot->name,"\n";}

If you want find record by external data (such as user input) or variable data you must use Binding Parameters`.

You could also use the findFirst() method to get only the first record matching the given criteria:

<?phpuseStore\Toys\Robots;// 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(["type = 'virtual'",'order'=>'name',]);echo'The first virtual robot name is ',$robot->name,"\n";

Both find() and findFirst() methods accept an associative array specifying the search criteria:

All the queries are internally handled as PHQL queries. PHQL is a high-level, object-oriented and SQL-like language. This language provide you more features to perform queries like joining other models, define groupings, add aggregations etc.

Lastly, there is the findFirstBy<property-name>() method. This method expands on the findFirst() method mentioned earlier. It allows you to quickly perform a retrieval from a table by using the property name in the method itself and passing it a parameter that contains the data you want to search for in that column. An example is in order, so taking our Robots model mentioned earlier:

We have three properties to work with here: $id, $name and $price. So, let’s say you want to retrieve the first record in the table with the name ‘Terminator’. This could be written like:

<?phpuseStore\Toys\Robots;$name='Terminator';$robot=Robots::findFirstByName($name);if($robot){echo'The first robot with the name '.$name.' cost '.$robot->price.'.';}else{echo'There were no robots found in our table with the name '.$name.'.';}

Notice that we used ‘Name’ in the method call and passed the variable $name to it, which contains the name we are looking for in our table. Notice also that when we find a match with our query, all the other properties are available to us as well.

Model Resultsets

While findFirst() returns directly an instance of the called class (when there is data to be returned), the find() method returns a Phalcon\Mvc\Model\Resultset\Simple. This is an object that encapsulates all the functionality a resultset has like traversing, seeking specific records, counting, etc.

These objects are more powerful than standard arrays. One of the greatest features of the Phalcon\Mvc\Model\Resultset is that at any time there is only one record in memory. This greatly helps in memory management especially when working with large amounts of data.

<?phpuseStore\Toys\Robots;// Get all robots$robots=Robots::find();// Traversing with a foreachforeach($robotsas$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 resultsetechocount($robots);// Alternative way to count the resultsetecho$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 positionif(isset($robots[3])){$robot=$robots[3];}// Get the first record in the resultset$robot=$robots->getFirst();// Get the last record$robot=$robots->getLast();

Phalcon’s resultsets emulate scrollable cursors, you can get any row just by accessing its position, or seeking the internal pointer to a specific position. Note that some database systems don’t support scrollable cursors, this forces to re-execute the query in order to rewind the cursor to the beginning and obtain the record at the requested position. Similarly, if a resultset is traversed several times, the query must be executed the same number of times.

As storing large query results in memory could consume many resources, resultsets are obtained from the database in chunks of 32 rows - reducing the need to re-execute the request in several cases.

Note that resultsets can be serialized and stored in a cache backend. Phalcon\Cache can help with that task. However, serializing data causes Phalcon\Mvc\Model to retrieve all the data from the database in an array, thus consuming more memory while this process takes place.

<?php// Query all records from model parts$parts=Parts::find();// Store the resultset into a filefile_put_contents('cache.txt',serialize($parts));// Get parts from file$parts=unserialize(file_get_contents('cache.txt'));// Traverse the partsforeach($partsas$part){echo$part->id;}

Custom Resultsets

There are times that the application logic requires additional manipulation of the data as it is retrieved from the database. Previously, we would just extend the model and encapsulate the functionality in a class in the model or a trait, returning back to the caller usually an array of transformed data.

With custom resultsets, you no longer need to do that. The custom resultset will encapsulate the functionality that otherwise would be in the model and can be reused by other models, thus keeping the code DRY. This way, the find() method will no longer return the default Phalcon\Mvc\Model\Resultset, but instead the custom one. Phalcon allows you to do this by using the getResultsetClass() in your model.

<?php/**
* Find the robots
*/$robots=Robots::find(['conditions'=>'date between "2017-01-01" AND "2017-12-31"','order'=>'date']);/**
* Pass the data to the view
*/$this->view->mydata=$robots->getSomeData();

Filtering Resultsets

The most efficient way to filter data is setting some search criteria, databases will use indexes set on tables to return data faster. Phalcon additionally allows you to filter the data using PHP using any resource that is not available in the database:

<?php$customers=Customers::find();$customers=$customers->filter(function($customer){// Return only customers with a valid e-mailif(filter_var($customer->email,FILTER_VALIDATE_EMAIL)){return$customer;}});

Binding Parameters

Bound parameters are also supported in Phalcon\Mvc\Model. You are encouraged to use this methodology so as to eliminate the possibility of your code being subject to SQL injection attacks. Both string and integer placeholders are supported. Binding parameters can simply be achieved as follows:

When using numeric placeholders, you will need to define them as integers i.e. 1 or 2. In this case '1' or '2' are considered strings and not numbers, so the placeholder could not be successfully replaced.

Strings are automatically escaped using PDO. This function takes into account the connection charset, so its recommended to define the correct charset in the connection parameters or in the database configuration, as a wrong charset will produce undesired effects when storing or retrieving data.

Additionally you can set the parameter bindTypes, this allows defining how the parameters should be bound according to its data type:

Initializing/Preparing fetched records

May be the case that after obtaining a record from the database is necessary to initialise the data before being used by the rest of the application. You can implement the afterFetch() method in a model, this event will be executed just after create the instance and assign the data to it:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{public$id;public$name;public$status;publicfunctionbeforeSave(){// Convert the array into a string$this->status=join(',',$this->status);}publicfunctionafterFetch(){// Convert the string to an array$this->status=explode(',',$this->status);}publicfunctionafterSave(){// Convert the string to an array$this->status=explode(',',$this->status);}}

If you use getters/setters instead of/or together with public properties, you can initialize the field once it is accessed:

Generating Calculations

Calculations (or aggregations) are helpers for commonly used functions of database systems such as COUNT, SUM, MAX, MIN or AVG. Phalcon\Mvc\Model allows to use these functions directly from the exposed methods.

Count examples:

<?php// How many employees are?$rowcount=Employees::count();// How many different areas are assigned to employees?$rowcount=Employees::count(['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(['group'=>'area',]);foreach($groupas$row){echo'There are ',$row->rowcount,' in ',$row->area;}// Count employees grouping by their area and ordering the result by count$group=Employees::count(['group'=>'area','order'=>'rowcount',]);// Avoid SQL injections using bound parameters$group=Employees::count(['type > ?0','bind'=>[$type],]);

Sum examples:

<?php// How much are the salaries of all employees?$total=Employees::sum(['column'=>'salary',]);// How much are the salaries of all employees in the Sales area?$total=Employees::sum(['column'=>'salary','conditions'=>"area = 'Sales'",]);// Generate a grouping of the salaries of each area$group=Employees::sum(['column'=>'salary','group'=>'area',]);foreach($groupas$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(['column'=>'salary','group'=>'area','order'=>'sumatory DESC',]);// Avoid SQL injections using bound parameters$group=Employees::sum(['conditions'=>'area > ?0','bind'=>[$area],]);

Average examples:

<?php// What is the average salary for all employees?$average=Employees::average(['column'=>'salary',]);// What is the average salary for the Sales's area employees?$average=Employees::average(['column'=>'salary','conditions'=>"area = 'Sales'",]);// Avoid SQL injections using bound parameters$average=Employees::average(['column'=>'age','conditions'=>'area > ?0','bind'=>[$area],]);

Max/Min examples:

<?php// What is the oldest age of all employees?$age=Employees::maximum(['column'=>'age',]);// What is the oldest of employees from the Sales area?$age=Employees::maximum(['column'=>'age','conditions'=>"area = 'Sales'",]);// What is the lowest salary of all employees?$salary=Employees::minimum(['column'=>'salary',]);

Creating/Updating Records

The Phalcon\Mvc\Model::save() method allows you to create/update records according to whether they already exist in the table associated with a model. The save method is called internally by the create and update methods of Phalcon\Mvc\Model. For this to work as expected it is necessary to have properly defined a primary key in the entity to determine whether a record should be updated or created.

Also the method executes associated validators, virtual foreign keys and events that are defined in the model:

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

An array could be passed to save to avoid assign every column manually. Phalcon\Mvc\Model will check if there are setters implemented for the columns passed in the array giving priority to them instead of assign directly the values of the attributes:

Values assigned directly or via the array of attributes are escaped/sanitized according to the related attribute data type. So you can pass an insecure array without worrying about possible SQL injections:

<?phpuseStore\Toys\Robots;$robot=newRobots();$robot->save($_POST);

Without precautions mass assignment could allow attackers to set any database column’s value. Only use this feature if you want to permit a user to insert/update every column in the model, even if those fields are not in the submitted form.

You can set an additional parameter in save to set a whitelist of fields that only must taken into account when doing the mass assignment:

Create/Update with Confidence

When an application has a lot of competition, we could be expecting create a record but it is actually updated. This could happen if we use Phalcon\Mvc\Model::save() to persist the records in the database. If we want to be absolutely sure that a record is created or updated, we can change the save() call with create() or update():

<?phpuseStore\Toys\Robots;$robot=newRobots();$robot->type='mechanical';$robot->name='Astro Boy';$robot->year=1952;// This record only must be createdif($robot->create()===false){echo"Umh, We can't store robots right now: \n";$messages=$robot->getMessages();foreach($messagesas$message){echo$message,"\n";}}else{echo'Great, a new robot was created successfully!';}

The methods create and update also accept an array of values as parameter.

Deleting Records

The Phalcon\Mvc\Model::delete() method allows to delete a record. You can use it as follows:

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

You can also delete many records by traversing a resultset with a foreach:

The following events are available to define custom business rules that can be executed when a delete operation is performed:

Operation

Name

Can stop operation?

Explanation

Deleting

afterDelete

No

Runs after the delete operation was made

Deleting

beforeDelete

Yes

Runs before the delete operation is made

With the above events can also define business rules in the models:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{publicfunctionbeforeDelete(){if($this->status==='A'){echo"The robot is active, it can't be deleted";returnfalse;}returntrue;}}

Hydration Modes

As mentioned previously, resultsets are collections of complete objects, this means that every returned result is an object representing a row in the database. These objects can be modified and saved again to persistence:

Sometimes records are obtained only to be presented to a user in read-only mode, in these cases it may be useful to change the way in which records are represented to facilitate their handling. The strategy used to represent objects returned in a resultset is called ‘hydration mode’:

<?phpusePhalcon\Mvc\Model\Resultset;useStore\Toys\Robots;$robots=Robots::find();// Return every robot as an array$robots->setHydrateMode(Resultset::HYDRATE_ARRAYS);foreach($robotsas$robot){echo$robot['year'],PHP_EOL;}// Return every robot as a stdClass$robots->setHydrateMode(Resultset::HYDRATE_OBJECTS);foreach($robotsas$robot){echo$robot->year,PHP_EOL;}// Return every robot as a Robots instance$robots->setHydrateMode(Resultset::HYDRATE_RECORDS);foreach($robotsas$robot){echo$robot->year,PHP_EOL;}

Auto-generated identity columns

Some models may have identity columns. These columns usually are the primary key of the mapped table. Phalcon\Mvc\Model can recognize the identity column omitting it in the generated SQL INSERT, so the database system can generate an auto-generated value for it. Always after creating a record, the identity field will be registered with the value generated in the database system for it:

<?php$robot->save();echo'The generated id is: ',$robot->id;

Phalcon\Mvc\Model is able to recognize the identity column. Depending on the database system, those columns may be serial columns like in PostgreSQL or auto_increment columns in the case of MySQL.

PostgreSQL uses sequences to generate auto-numeric values, by default, Phalcon tries to obtain the generated value from the sequence table_field_seq, for example: robots_id_seq, if that sequence has a different name, the getSequenceName() method needs to be implemented:

Skipping Columns

To tell Phalcon\Mvc\Model that always omits some fields in the creation and/or update of records in order to delegate the database system the assignation of the values by a trigger or a default:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{publicfunctioninitialize(){// Skips fields/columns on both INSERT/UPDATE operations$this->skipAttributes(['year','price',]);// Skips only when inserting$this->skipAttributesOnCreate(['created_at',]);// Skips only when updating$this->skipAttributesOnUpdate(['modified_in',]);}}

This will ignore globally these fields on each INSERT/UPDATE operation on the whole application. If you want to ignore different attributes on different INSERT/UPDATE operations, you can specify the second parameter (boolean) - true for replacement. Forcing a default value can be done as follows:

Never use a Phalcon\Db\RawValue to assign external data (such as user input) or variable data. The value of these fields is ignored when binding parameters to the query. So it could be used to attack the application injecting SQL.

Dynamic Updates

SQL UPDATE statements are by default created with every column defined in the model (full all-field SQL update). You can change specific models to make dynamic updates, in this case, just the fields that had changed are used to create the final SQL statement.

In some cases this could improve the performance by reducing the traffic between the application and the database server, this specially helps when the table has blob/text fields:

Independent Column Mapping

The ORM supports an independent column map, which allows the developer to use different column names in the model to the ones in the table. Phalcon will recognize the new column names and will rename them accordingly to match the respective columns in the database. This is a great feature when one needs to rename fields in the database without having to worry about all the queries in the code. A change in the column map in the model will take care of the rest. For example:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{public$code;public$theName;public$theType;public$theYear;publicfunctioncolumnMap(){// Keys are the real names in the table and// the values their names in the applicationreturn['id'=>'code','the_name'=>'theName','the_type'=>'theType','the_year'=>'theYear',];}}

Then you can use the new names naturally in your code:

<?phpuseStore\Toys\Robots;// Find a robot by its name$robot=Robots::findFirst("theName = 'Voltron'");echo$robot->theName,"\n";// Get robots ordered by type$robot=Robots::find(['order'=>'theType DESC',]);foreach($robotsas$robot){echo'Code: ',$robot->code,"\n";}// Create a robot$robot=newRobots();$robot->code='10101';$robot->theName='Bender';$robot->theType='Industrial';$robot->theYear=2999;$robot->save();

Consider the following when renaming your columns:

References to attributes in relationships/validators must use the new names

Refer the real column names will result in an exception by the ORM

The independent column map allows you to:

Write applications using your own conventions

Eliminate vendor prefixes/suffixes in your code

Change column names without change your application code

Record Snapshots

Specific models could be set to maintain a record snapshot when they’re queried. You can use this feature to implement auditing or just to know what fields are changed according to the data queried from the persistence:

When activating this feature the application consumes a bit more of memory to keep track of the original values obtained from the persistence. In models that have this feature activated you can check what fields changed as follows:

<?phpuseStore\Toys\Robots;// 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'));// truevar_dump($robot->hasChanged('type'));// false

Snapshots are updated on model creation/update. Using hasUpdated() and getUpdatedFields() can be used to check if fields were updated after a create/save/update but it could potentially cause problems to your application if you execute getChangedFields() in afterUpdate(), afterSave() or afterCreate().

Setting multiple databases

In Phalcon, all models can belong to the same database connection or have an individual one. Actually, when Phalcon\Mvc\Model needs to connect to the database it requests the db service in the application’s services container. You can overwrite this service setting it in the initialize() method:

<?phpusePhalcon\Db\Adapter\Pdo\MysqlasMysqlPdo;usePhalcon\Db\Adapter\Pdo\PostgreSQLasPostgreSQLPdo;// This service returns a MySQL database$di->set('dbMysql',function(){returnnewMysqlPdo(['host'=>'localhost','username'=>'root','password'=>'secret','dbname'=>'invo',]);});// This service returns a PostgreSQL database$di->set('dbPostgres',function(){returnnewPostgreSQLPdo(['host'=>'localhost','username'=>'postgres','password'=>'','dbname'=>'invo',]);});

Then, in the initialize() method, we define the connection service for the model:

But Phalcon offers you more flexibility, you can define the connection that must be used to read and for write. This is specially useful to balance the load to your databases implementing a master-slave architecture:

The ORM also provides Horizontal Sharding facilities, by allowing you to implement a ‘shard’ selection according to the current query conditions:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{/**
* Dynamically selects a shard
*
* @param array $intermediate
* @param array $bindParams
* @param array $bindTypes
*/publicfunctionselectReadConnection($intermediate,$bindParams,$bindTypes){// Check if there is a 'where' clause in the selectif(isset($intermediate['where'])){$conditions=$intermediate['where'];// Choose the possible shard according to the conditionsif($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 shardreturn$this->getDI()->get('dbShard0');}}

The selectReadConnection() method is called to choose the right connection, this method intercepts any new query executed:

<?phpuseStore\Toys\Robots;$robot=Robots::findFirst('id = 101');

Injecting services into Models

You may be required to access the application services within a model, the following example explains how to do that:

<?phpnamespaceStore\Toys;usePhalcon\Mvc\Model;classRobotsextendsModel{publicfunctionnotSaved(){// Obtain the flash service from the DI container$flash=$this->getDI()->getFlash();$messages=$this->getMessages();// Show validation messagesforeach($messagesas$message){$flash->error($message);}}}

The notSaved event is triggered every time that a create or update action fails. So we’re flashing the validation messages obtaining the flash service from the DI container. By doing this, we don’t have to print messages after each save.

Disabling/Enabling Features

In the ORM we have implemented a mechanism that allow you to enable/disable specific features or options globally on the fly. According to how you use the ORM you can disable that you aren’t using. These options can also be temporarily disabled if required:

Enables/Disables callbacks, hooks and event notifications from all the models

null

cacheLevel

Sets the cache level for the ORM

3

castOnHydrate

false

columnRenaming

Enables/Disables the column renaming

true

disableAssignSetters

Allow disabling setters in your model

false

enableImplicitJoins

true

enableLiterals

true

escapeIdentifiers

true

events

Enables/Disables callbacks, hooks and event notifications from all the models

true

exceptionOnFailedSave

Enables/Disables throwing an exception when there is a failed save()

false

forceCasting

false

ignoreUnknownColumns

Enables/Disables ignoring unknown columns on the model

false

lateStateBinding

Enables/Disables late state binding of the Phalcon\Mvc\Model::cloneResultMap() method

false

notNullValidations

The ORM automatically validate the not null columns present in the mapped table

true

parserCache

null

phqlLiterals

Enables/Disables literals in the PHQL parser

true

uniqueCacheId

3

updateSnapshotOnSave

Enables/Disables updating snapshots on save()

true

virtualForeignKeys

Enables/Disables the virtual foreign keys

true

NOTEPhalcon\Mvc\Model::assign() (which is used also when creating/updating/saving model) is always using setters if they exist when have data arguments passed, even when it's required or necessary. This will add some additional overhead to your application. You can change this behavior by adding phalcon.orm.disable_assign_setters = 1 to your ini file, it will just simply use $this->property = value.

Stand-Alone component

<?phpusePhalcon\Di;usePhalcon\Mvc\Model;usePhalcon\Mvc\Model\ManagerasModelsManager;usePhalcon\Db\Adapter\Pdo\SqliteasConnection;usePhalcon\Mvc\Model\Metadata\MemoryasMetaData;$di=newDi();// Setup a connection$di->set('db',newConnection(['dbname'=>'sample.db',]));// Set a models manager$di->set('modelsManager',newModelsManager());// Use the memory meta-data adapter or other$di->set('modelsMetadata',newMetaData());// Create a modelclassRobotsextendsModel{}// Use the modelechoRobots::count();