Mastering ThinkPHP 4.0+ Entity Models: A Complete Backend Guide

This guide explains ThinkPHP 4.0+ entity models, covering their layered architecture, installation, entity and model definitions, automatic relation queries, new type casting, accessors, configuration options, virtual and view models, with full code examples and practical tips for backend developers.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Mastering ThinkPHP 4.0+ Entity Models: A Complete Backend Guide

Overview

ThinkPHP 4.0+ introduced the concept of an entity model, separating the traditional Model layer into a repository Model for low‑level data operations and an Entity layer for data definition, presentation, business logic, and event handling. This layered design improves clarity, safety, and usability, especially in large projects.

Entity Model Advantages

More intuitive : define fields and relations via properties.

More secure : strong‑typed field definitions with new types.

More usable : view models, virtual models, auto‑relation and other new features simplify usage.

Model layering : Entity handles data display and processing; Model handles database connections, events, and relation definitions.

Current 4.0 version is still in testing; adjustments may occur. Do not use in production.

Installation

To try the 4.0 entity model, install the development version via Composer:

composer require topthink/think-orm:4.0.x-dev

Model Definition

Entity classes share the same name as their corresponding Model classes but reside in a different namespace. Example:

<?php
namespace app\entity;
use think\Entity;
class Blog extends Entity {}
?>

Custom model binding can be achieved by overriding parseModel:

<?php
namespace app\entity;
use think\Entity;
use app\model\Blog as Other;
class Blog extends Entity {
    protected function parseModel(): string {
        return Other::class;
    }
}
?>

Properties can be defined explicitly with type hints, e.g.:

<?php
namespace app\entity;
use think\Entity;
use think\model\type\DateTime;
class Blog extends Entity {
    protected int $id;
    protected string $title;
    protected string $content;
    protected int $user_id;
    protected DateTime $create_time;
    protected DateTime $update_time;
    protected User $user;
}
?>

Fields must match the database column names; relationships are still defined in the Model class.

<?php
namespace app\model;
use think\Model;
class Blog extends Model {
    public function user() {
        return $this->belongsTo(User::class);
    }
}
?>

Automatic Relation Query

By configuring auto_relation in the Entity’s getOptions method, related data can be fetched without repeatedly calling with:

protected function getOptions(): array {
    return [
        'auto_relation' => ['user'],
    ];
}

Then a simple Blog::find(1) automatically loads the associated user.

New Property Types

ThinkPHP adds several built‑in type classes that can be used in the type option to cast fields automatically: \think\model\type\Json – JSON formatted field. \think\model\type\DateTime – DateTime or timestamp field. \think\model\type\Date – Date field.

Even without explicit property definitions, the entity will convert these types after a query.

Accessors (属性器)

Instead of the older setXXXAttr / getXXXAttr methods, an Entity can define a single camel‑cased method that returns an array with get and set closures. Example for a name field:

protected function name() {
    return [
        'get' => function ($value) {
            return strtoupper((string) $value);
        },
        'set' => function ($value) {
            return strtolower($value);
        },
    ];
}

Accessors can also be defined for virtual (non‑database) fields.

Entity Options

Most settings are optional. Common options include: type – field‑type map. model_class – associated Model class name. strict – case‑sensitivity flag (default true). disuse, readonly, hidden, visible, append, mapping, auto_relation – various array‑based configurations. virtual, view – flags for virtual or view models. create_time, update_time – automatic timestamp fields.

Options are returned from a protected getOptions(): array method. Setting strict => false makes attribute access case‑insensitive, allowing camelCase property names while the underlying columns remain snake_case.

protected function getOptions(): array {
    return [
        'strict' => false,
        'type'   => [
            'status' => StatusEnum::class,
        ],
    ];
}

Virtual Model

A virtual model extends think\entity\Virtual and does not correspond to a database table. It can be created and mutated but cannot be persisted.

<?php
namespace app\entity;
use think\entity\Virtual;
class Blog extends Virtual {}
// Create data
$blog = Blog::create($data);
$blog->name = 'thinkphp';
?>

View Model

View models allow you to compose queries that join multiple tables and return a read‑only result set without a backing Model class.

<?php
namespace app\entity;
use think\db\Query;
use think\entity\View;
class Test extends View {
    public function query(Query $query) {
        $this->view(Blog::class, 'id,title')
             ->view(User::class, 'name,email', 'Blog.user_id = User.id')
             ->where('status', '>', 0);
    }
}
?>

Execution example:

use app\entity\Test;
$result = Test::find(1);
 dump($result);
If you do not need the entity model, you can continue using the traditional Model layer without any code changes, making migration safe.

Feel free to leave comments with suggestions or feedback about the new ORM and entity model.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

databaseBackend DevelopmentORMPHPThinkPHPEntity Model
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.