GreenCheap object-relational mapper (ORM), helps you create model classes of your application data where each property is automatically mapped to the appropriate table column. You can also define relationships between your assets and existing assets from Greencheap (i.e. users).
The following, so run your extension on the install
hook of the scripts.php
file. Tablo oluşturma hakkında daha genel bilgi için veritabanı bölümü'ne bakın.For more general information about creating a table, see the database section
Example:
$util = $app['db']->getUtility();
if ($util->tableExists('@forum_topics') === false) {
$util->createTable('@forum_topics', function ($table) {
$table->addColumn('id', 'integer', ['unsigned' => true, 'length' => 10, 'autoincrement' => true]);
$table->addColumn('user_id', 'integer', ['unsigned' => true, 'length' => 10, 'default' => 0]);
$table->addColumn('title', 'string', ['length' => 255, 'default' => '']);
$table->addColumn('date', 'datetime');
$table->addColumn('modified', 'datetime', ['notnull' => false]);
$table->addColumn('content', 'text');
$table->addIndex(['user_id'], 'FORUM_TOPIC_USER_ID');
$table->setPrimaryKey(['id']);
});
}
Example:
<?php
namespace GreenCheap\Forum\Model;
use GreenCheap\Database\ORM\ModelTrait;
/**
* @Entity(tableClass="@forum_topics")
*/
class Topic
{
use ModelTrait;
/** @Column(type="integer") @Id */
public $id;
/** @Column */
public $title = '';
/** @Column(type="datetime") */
public $date;
/** @Column(type="text") */
public $content = '';
/** @Column(type="integer") */
public $user_id;
/**
* @BelongsTo(targetEntity="GreenCheap\User\Model\User", keyFrom="user_id")
*/
public $user;
}
Model is a flat PHP class that uses the GreenCheap\Database\Orm\ModelTrait
property. Properties allow to include certain behaviors in a class, similar to simple class inheritance. The main difference is that a class can use multiple properties and inherit only from a single class.
Note If you are not familiar with the features, quickly browse official PHP documentation about features.
@Entity(tableClass="@my_table")
notes, Model links to database table gc_my_table
(@
automatically replaced with your installation's database prefix)
Annotations only, multiline interpretation works only if you start with two asterisks, not one asterisk.
// will NOT work:
/* @Column */
// will work:
/** @Column */
// will work:
/**
* @Column
*/
When defining a property in a class, this variable, you can link a table column by placing the annotation /** @Column(type="string") */
directly above the property definition. You can use any type supported by Doctrine DBAL.
The class that you refer to in your Model class must also exist in the database.
The application data that you represent in your database model has certain relation between instances. A blog post has several comments about itself and belongs exactly to an example of a user. GreenCheap ORM, it provides mechanisms to identify these relationships and also to question them programmatically.
Basic description used in different relationship types, A @BelongsTo
note on a model property. In the following example (taken from the blog's Post
model), We specify a $user
property defined to point to an instance of the GreenCheap User
model.
The keyFrom
parameter specifies which resource property to use to point to the user ID. Note how we must define the user_id
property for the relation to be resolved by a query.
For Example:
/** @Column(type="integer") */
public $user_id;
/**
* @BelongsTo(targetEntity="GreenCheap\User\Model\User", keyFrom="user_id")
*/
public $user;
In this relation, an arbitrary example of a single model is
the number of instances of another model. A classic example of this is a Post
.
any number of Comment
instances.
On the reverse side, the comment belongs in exactly one Post
.
GreenCheap\Blog\Model\Post
example from the blog package inside.
/**
* @HasMany(targetEntity="Comment", keyFrom="id", keyTo="post_id")
*/
public $comments;
Define the inverse of the relation
GreenCheap\Blog\Model\Comment
:
/** @Column(type="integer") */
public $post_id;
/** @BelongsTo(targetEntity="Post", keyFrom="post_id") */
public $post;
You can use the ORM class to query the model.
use GreenCheap\Blog\Post;
// ...
// fetch posts without related comments
$posts = Post::findAll();
var_dump($posts);
Output:
array (size=6)
1 =>
object(GreenCheap\Blog\Model\Post)[4513]
public 'id' => int 1
public 'title' => string 'Hello GreenCheap' (length=13)
public 'comments' => null
// ...
2 =>
object(GreenCheap\Blog\Model\Post)[3893]
public 'id' => int 2
public 'title' => string 'Hello World' (length=11)
public 'comments' => null
// ...
// ...
use GreenCheap\Blog\Post;
// ...
// fetch posts including related comments
$posts = Post::query()->related('comments')->get();
var_dump($posts);
Output:
array (size=6)
1 =>
object(GreenCheap\Blog\Model\Post)[4512]
public 'id' => int 1
public 'title' => string 'Hello GreenCheap' (length=13)
public 'comments' =>
array (size=0)
empty
// ...
2 =>
object(GreenCheap\Blog\Model\Post)[3433]
public 'id' => int 2
public 'title' => string 'Hello World' (length=11)
public 'comments' =>
array (size=1)
6 =>
object(GreenCheap\Blog\Model\Comment)[4509]
...
// ...
// ...
A very simple relation is a one-to-one relation. A Forumuser
can be assigned exactly an Avatar
. When including All information about the Avatar in the ForumUser
model, sometimes it makes sense to separate them into separate models.
To implement a one-to-one relation, you can use the @BelongsTo
annotation in each model class.
/** @BelongsTo(targetEntity="Avatar", keyFrom="avatar_id", keyTo="id") */
targetEntity
: Target model classkeyFrom
: foreign key pointing to the corresponding model in this tablekeyTo
: primary key in the corresponding modelExample model ForumUser
:
<?php
namespace GreenCheap\Forum\Model;
use GreenCheap\Database\ORM\ModelTrait;
/**
* @Entity(tableClass="@forum_user")
*/
class ForumUser
{
use ModelTrait;
/** @Column(type="integer") @Id */
public $id;
/** @Column */
public $name = '';
/** @Column(type="integer") */
public $avatar_id;
/** @BelongsTo(targetEntity="Avatar", keyFrom="avatar_id", keyTo="id") */
public $avatar;
}
Example model Avatar
:
<?php
namespace GreenCheap\Forum\Model;
use GreenCheap\Database\ORM\ModelTrait;
/**
* @Entity(tableClass="@forum_avatars")
*/
class Avatar
{
use ModelTrait;
/** @Column(type="integer") @Id */
public $id;
/** @Column(type="string") */
public $path;
/** @Column(type="integer") */
public $user_id;
/** @BelongsTo(targetEntity="ForumUser", keyFrom="user_id", keyTo="id") */
public $user;
}
To ensure that the relevant model is included in a query result, fetch the instance QueryBuilder
from the model class and explicitly list the relationship property in the related()
method.
<?php
use GreenCheap\Forum\Model\ForumUser;
use GreenCheap\Forum\Model\Avatar;
// ...
// get all users including their related $avatar object
$users = ForumUser::query()->related('avatar')->get();
foreach ($users as $user) {
var_dump($user->avatar->path);
}
// get all avatars including their related $user object
$avatars = Avatar::query()->related('user')->get();
foreach ($avatars as $avatar) {
var_dump($avatar->user);
}
Sometimes, two model, in a relationship where there are potentially a large number of examples on both sides of the relation. A example, there may be a relationship between tags and posts: There may be several tags assigned to a post. In the same time, a label can be assigned to multiple posts.
A different example listed below, scenario of favorite topics in a discussion forum. A user can have multiple favorite topics. A topic can be added to favorites by multiple users.
To apply the multiple relation, you need an additional database table. Each entry in this table, represents a link from a Topic
instance to a ForumUser
instance and vice versa. In database modeling, this is called a junction table.
Sample tables (so script.php
inside):
$util = $app['db']->getUtility();
// forum user table
if ($util->tableExists('@forum_users') === false) {
$util->createTable('@forum_users', function ($table) {
$table->addColumn('id', 'integer', ['unsigned' => true, 'length' => 10, 'autoincrement' => true]);
$table->addColumn('name', 'string', ['length' => 255, 'default' => '']);
$table->setPrimaryKey(['id']);
});
}
// topics table
if ($util->tableExists('@forum_topics') === false) {
$util->createTable('@forum_topics', function ($table) {
$table->addColumn('id', 'integer', ['unsigned' => true, 'length' => 10, 'autoincrement' => true]);
$table->addColumn('title', 'string', ['length' => 255, 'default' => '']);
$table->addColumn('content', 'text');
$table->setPrimaryKey(['id']);
});
}
// junction table
if ($util->tableExists('@forum_favorites') === false) {
$util->createTable('@forum_favorites', function ($table) {
$table->addColumn('id', 'integer', ['unsigned' => true, 'length' => 10, 'autoincrement' => true]);
$table->addColumn('user_id', 'integer', ['unsigned' => true, 'length' => 10, 'default' => 0]);
$table->addColumn('topic_id', 'integer', ['unsigned' => true, 'length' => 10, 'default' => 0]);
$table->setPrimaryKey(['id']);
});
}
The relation itself is then defined in each Model class that you want to query. If you only want to list favorite posts for a specific user, but if you don't list all users who have added a particular post to their favorites, you define a relationship only in a model. But in the following example, he @ManyToMany
annotation is available in both model classes.
The` @ManyToMany ' annotation takes the following parameters.
Argument | Description |
---|---|
targetEntity |
Target model class |
tableThrough |
Name of the junction table |
keyThroughFrom |
The name of the foreign key in the" From who" direction |
keyThroughTo |
The name of the foreign key in the" to who" direction |
orderBy |
(isteğe bağlı) Ekstreye göre sırala |
Sample annotation:
/**
* @ManyToMany(targetEntity="ForumUser", tableThrough="@forum_favorites", keyThroughFrom="topic_id", keyThroughTo="forum_user_id")
*/
public $users;
Sample model Topic
:
<?php
namespace GreenCheap\Forum\Model;
use GreenCheap\Database\ORM\ModelTrait;
/**
* @Entity(tableClass="@forum_topics")
*/
class Topic
{
use ModelTrait;
/** @Column(type="integer") @Id */
public $id;
/** @Column */
public $title = '';
/** @Column(type="text") */
public $content = '';
/**
* @ManyToMany(targetEntity="ForumUser", tableThrough="@forum_favorites", keyThroughFrom="topic_id", keyThroughTo="forum_user_id")
*/
public $users;
}
Sample model ForumUser
:
<?php
namespace GreenCheap\Forum\Model;
use GreenCheap\Database\ORM\ModelTrait;
/**
* @Entity(tableClass="@forum_user")
*/
class ForumUser
{
use ModelTrait;
/** @Column(type="integer") @Id */
public $id;
/** @Column */
public $name = '';
/**
* @ManyToMany(targetEntity="Topic", tableThrough="@forum_favorites", keyThroughFrom="forum_user_id", keyThroughTo="topic_id")
*/
public $topics;
}
Sample queries:
// resolve many-to-many relation in query
// fetch favorite ropics for given user
$user_id = 1;
$user = ForumUser::query()->where('id = ?', [$user_id])->related('topics')->first();
foreach ($user->topics as $topic) {
//
}
// fetch users that have favorited a given topic
$topic_id = 1;
$topic = Topic::query()->where('id = ?', [$topic_id])->related('users')->first();
foreach ($topic->users as $user) {
// ...
}
Fetch an instance of a model with a specific ID.
$post = Post::find(23)
Fetch all instances of a model.
$posts = Post::findAll();
Relations with the above queries, it will not be expanded to include relevant examples. In the above example, The $comments
property of the Post
instance will not be initialized.
// related objects are not fetched by default
$post->comments == null;
The reason for this is performance. By default, required subqueries are not performed, this saves execution time. So, if you need related objects, you can use the related()
method on QueryBuilder
to explicitly specify which relation to resolve in this query.
Therefore, to retrieve a Post
instance and include Associated Comment
instances, you must create a query that fetches related objects.
// fetch all, including related objects
$posts = Post::query()->related('comments')->get();
// fetch single instance, include related objects
$id = 23;
$post = Post::query()->related('comments')->where('id = ?', [$id])->first();
Note how find(23)
is replaced with -> where('id = ?',[$id])->first()
. the reason for this, find()
is a method defined on the Model. But in the second example, we have a GreenCheap\Database\Orm\QueryBuilder
instance.
For more details about Orm queries and regular queries, see the documentation for database queries
You can create and save a new model by calling the save()
method on a new model instance.
$user = new ForumUser();
$user->name = "bruce";
$user->save();
Alternatively, you can call the create()
method directly in the model class and provide a set of existing data to start the instance. Call save()
later to store the instance in the database.
$user = ForumUser::create(["name" => "peter"]);
$user->save();
Bring an existing sample, make any changes to the object and then call the save()
method to store the changes in the database.
$user = ForumUser::find(2);
$user->name = "david";
$user->save();
Take an existing model instance and call the delete()
method to remove it from the database.
$user = ForumUser::find(2);
$user->delete();
We'll let you know about new announcements, publications and everything else on our social media accounts.
Contact us directly at support@greencheap.net
♥ GreenCheap is developed with love and caffeine.