ThinkORM 4.0 Documentation

repository·4.0·Indexed 19 days ago

https://github.com/top-think/think-orm

A lightweight, high-performance PHP ORM built on PDO and PHP 8.0+. ThinkORM 4.0 supports ActiveRecord and Repository patterns, featuring a refactored Model layer for Entity models and layered architectures. It includes a flexible query builder, LazyCollection for memory-efficient large dataset handling, and specialized support for MongoDB aggregation and commands. Key capabilities include automatic parameter binding, model events, type auto-conversion, and support for distributed transactions and PSR-16/PSR-3 standards.

Tokens
10.4K
Snippets
38
Records
44
Agent score
65%

What's inside ThinkORM

  1. Overview of ThinkORM 4.0 features

    4.0

    ThinkORM 4.0 is a lightweight ORM implemented using PHP 8.0+ and PDO. It features a completely refactored Model layer that supports both Entity models and layered architectures. It is designed to be largely compatible with version 3.0.

    Key capabilities include:

    • Querying: Native query support, flexible query builder with chainable methods, automatic parameter binding, and aggregate queries.
    • Modeling: Powerful model and association definitions, support for ActiveRecord and Repository patterns, model events, and type auto-conversion.
    • Data Handling: Model accessors and modifiers, support for JSON and Enum classes, automatic data validation on write, and lazy/automatic writing.
    • Advanced Features: Virtual models, Entity and View models, searchers, query scopes, and preloading/lazy-loading of associations.
    • Infrastructure: Support for multiple databases (including MongoDb), distributed transactions, breakpoint reconnection, PSR-16 cache, and PSR-3 logging.
  2. What is LazyCollection and when to use it

    4.0

    A LazyCollection is a memory-efficient collection class designed for handling large datasets. Unlike a standard collection that loads all items into memory at once, LazyCollection uses PHP Generators to iterate through items one by one.

    This makes it ideal for processing database results via a cursor or large arrays where loading everything into memory would cause exhaustion. Most operations on a LazyCollection (like map, filter, take, skip) return a new LazyCollection instance, allowing you to chain operations without actually executing them until you iterate over the collection or convert it to an array.

    // Example: Using a cursor from a query to create a LazyCollection
    $lazyCollection = LazyCollection::make($query->cursor());
    
    foreach ($lazyCollection as $item) {
        // Items are fetched one by one, saving memory
        echo $item->name;
    }
  3. Manage many-to-many relationships with BelongsToMany

    4.0

    The BelongsToMany class handles many-to-many relationships between models using a pivot (middle) table. It allows you to retrieve, attach, detach, and synchronize related models.

    Key Capabilities:

    • Retrieve related data: Use getRelation() to fetch related models with optional closure constraints.
    • Attach/Save relations: Use attach(), save(), or saveAll() to create new links in the pivot table. You can pass an array of data, a model instance, or a primary key.
    • Detach relations: Use detach() to remove links from the pivot table. Optionally, you can delete the actual related model records by setting $relationDel to true.
    • Synchronize relations: Use sync() to make the pivot table match a specific set of IDs. It automatically handles detaching old IDs and attaching new ones.
    • Check existence: Use attached() to check if a specific model or ID is currently linked to the parent model.
    • Pivot customization: You can define a custom pivot model using pivot() and customize the name of the pivot data attribute using name().
    // Example: Attaching a relation
    $user->roles()->attach($roleId, ['extra_field' => 'value']);
    
    // Example: Synchronizing relations
    $user->roles()->sync([1, 2, 3]);
    
    // Example: Detaching a relation
    $user->roles()->detach($roleId);
  4. Implement a MorphTo polymorphic relationship

    4.0

    The MorphTo class allows a model to belong to more than one other type of model using a single association. This is achieved by using two columns: a morphType (storing the class name or alias of the related model) and a morphKey (storing the primary key of the related model).

    To use this in your model, you typically define a relationship method that returns a MorphTo instance. You can also provide an alias array to map short strings (stored in the morphType column) to full model class names, which simplifies database storage and avoids tight coupling to class namespaces.

    Key capabilities include:

    • Eager Loading: Use with() to preload polymorphic relations efficiently.
    • Association Management: Use associate() to link a model and dissociate() to remove the link.
    • Querying: Use hasWhere() to filter the parent model based on conditions in the polymorphic related models.
    // Example conceptual usage in a Model class
    public function commentable()
    {
        // morphType: 'commentable_type', morphKey: 'commentable_id'
        return $this->morphTo('commentable_type', 'commentable_id', ['post' => Post::class]);
    }
  5. Manage model instances with Collection

    4.0
    The think\model\Collection class is a specialized collection designed to manage sets of model instances. It extends the base think\Collection and provides bulk operations that apply to every model within the collection, such as loading relations, updating data, or setting visibility rules.
  6. Define a Polymorphic One-to-One relationship

    4.0

    In ThinkORM, a MorphOne relationship allows a model to belong to a single related model through a polymorphic interface. This is useful when multiple different models share a single related table (e.g., a Comment model that can belong to either a Post or a Video).

    To implement this, you define the relationship in your parent model using the following parameters:

    • Model: The target model class.
    • Morph Key: The foreign key column in the related table that stores the parent's ID.
    • Morph Type: The column in the related table that stores the type (class name or identifier) of the parent model.
    • Type: The specific type value used to identify the current parent model in the polymorphic field.
  7. Configure polymorphic aliases with setAlias()

    4.0

    To avoid storing long, fully-qualified class names in your morphType database column, you can use aliases. The setAlias(array $alias) method allows you to map short identifiers to actual model class names.

    When parseModel is called during relationship resolution, it checks this alias map first.

    // Define aliases so the DB stores 'post' instead of 'App\Model\Post'
    $relation->setAlias(['post' => Post::class, 'video' => Video::class]);
  8. Transform and filter LazyCollection items

    4.0

    You can manipulate the data within a LazyCollection using several functional methods. These methods return a new LazyCollection and do not execute immediately:

    • map(callable $callback): Transforms each item using the provided callback.
    • filter(?callable $callback = null): Filters items. If no callback is provided, it filters by truthiness.
    • take(int $limit): Returns a new collection containing only the first $limit items.
    • skip(int $offset): Skips the first $offset items.
    • page(int $page, int $listRows = 15): Returns a subset of the collection based on pagination logic (starting from page 1).
    $results = LazyCollection::make($largeDataset)
        ->filter(fn($item) => $item->active)
        ->map(fn($item) => $item->name)
        ->take(10);
    
    foreach ($results as $name) {
        echo $name;
    }
  9. Fetch the raw SQL string without executing

    4.0

    If you want to inspect the generated SQL query before it is executed, use the fetchSql() method. This returns a Fetch object that allows you to retrieve the SQL string.

    • fetchSql(bool $fetch = true): Sets the mode to fetch SQL. If $fetch is true, it returns a Fetch instance which can then be used to call methods like select(), update(), etc., to get the string.
    // Get the SQL string for a select query
    $sql = Db::name('user')->where('id', 1)->fetchSql()->select();
    // Output: SELECT * FROM `user` WHERE `id` = 1
  10. Configure Where clause enclosure

    4.0

    The enclose(bool $enclose = true) method determines whether the resulting parsed array will be wrapped in an extra set of parentheses. This is useful when the Where object represents a sub-clause that needs to be isolated within a larger SQL statement.

    • If $enclose is true, parse() returns [ [$condition1, $condition2, ...] ].
    • If $enclose is false, parse() returns [ $condition1, $condition2, ... ].
    $where = new Where(['id' => 1]);
    
    $where->enclose(true);
    $parsed = $where->parse();
    // Result: [ [['id', '=', 1]] ]
    
    $where->enclose(false);
    $parsed = $where->parse();
    // Result: [['id', '=', 1]]
  11. Bulk load relations in a Collection

    4.0

    Use the load() method to perform lazy eager loading on all models within the collection. This is useful for resolving relationships for a set of models in a single query rather than one by one.

    Parameters:

    • array $relation: The name(s) of the relation(s) to load.
    • mixed $cache: Whether to use cache for the relation (default false).
    • bool $withJoin: Whether to use a JOIN for the relation (default false).
    // Eager load the 'user' relation for all models in the collection
    $collection->load(['user']);
    
    // Eager load with cache and JOIN
    $collection->load(['profile'], true, true);