PHPackages                             eseperio/yii2-model-virtual-fields - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. eseperio/yii2-model-virtual-fields

ActiveYii2-extension[Utility &amp; Helpers](/categories/utility)

eseperio/yii2-model-virtual-fields
==================================

Yii2 extension for adding virtual (dynamic) fields to ActiveRecord models without modifying database tables

1.0.0(7mo ago)027[1 PRs](https://github.com/Eseperio/yii2-model-virtual-fields/pulls)MITPHPPHP &gt;=8.0

Since Nov 25Pushed 6mo agoCompare

[ Source](https://github.com/Eseperio/yii2-model-virtual-fields)[ Packagist](https://packagist.org/packages/eseperio/yii2-model-virtual-fields)[ RSS](/packages/eseperio-yii2-model-virtual-fields/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (5)Versions (3)Used By (0)

yii2-model-virtual-fields
=========================

[](#yii2-model-virtual-fields)

A Yii2 extension for adding virtual (dynamic) fields to ActiveRecord models without modifying database tables.

Overview
--------

[](#overview)

This library allows developers to define new fields for any ActiveRecord entity at runtime. These virtual fields:

- Have a name, datatype, and validation rules
- Are stored in dedicated tables managed by the extension
- Are exposed on the model as **native properties** (`$model->virtualFieldName`)
- Automatically integrate with:
    - ActiveForm
    - DetailView
    - GridView
    - Model validation
    - Model persistence

Features
--------

[](#features)

- ✅ Add dynamic fields to existing models without altering database schemas
- ✅ Support for multiple data types: string, int, float, bool, date, datetime, json, text
- ✅ Automatic validation based on field type and requirements
- ✅ Collision-safe field naming (prevents conflicts with existing properties)
- ✅ Seamless integration with Yii2 widgets (forms, grids, detail views)
- ✅ Caching support for improved performance
- ✅ Full test coverage

Installation
------------

[](#installation)

Install via Composer:

```
composer require eseperio/yii2-model-virtual-fields
```

Configuration
-------------

[](#configuration)

### 1. Configure the Module

[](#1-configure-the-module)

Add the module to your application configuration:

```
'modules' => [
    'virtualFields' => [
        'class' => 'eseperio\virtualfields\Module',
        'entityMap' => [
            1 => 'app\models\User',
            2 => 'app\models\Product',
            3 => 'app\models\Order',
            // ... more entity type mappings
        ],
    ],
],
```

The `entityMap` property maps **integer IDs** to fully qualified class names of your ActiveRecord models. The extension uses these integer IDs internally to identify entity types.

### 2. Run Migrations

[](#2-run-migrations)

Apply the database migrations:

```
php yii migrate --migrationPath=@vendor/eseperio/yii2-model-virtual-fields/migrations
```

This will create the necessary tables:

- `virtual_field_definition` - stores field definitions
- `virtual_field_value` - stores field values

### 3. Attach Behavior to Models

[](#3-attach-behavior-to-models)

Add the behavior to any ActiveRecord model you want to support virtual fields:

```
namespace app\models;

use yii\db\ActiveRecord;
use eseperio\virtualfields\behaviors\VirtualFieldsBehavior;

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'virtualFields' => [
                'class' => VirtualFieldsBehavior::class,
            ],
        ];
    }

    /**
     * Return the entity type ID from the module configuration
     */
    public function getObjectType()
    {
        return 1; // Must match the ID in entityMap
    }
}
```

Usage
-----

[](#usage)

### Creating Virtual Fields

[](#creating-virtual-fields)

Create virtual field definitions programmatically or through a UI:

```
use eseperio\virtualfields\models\VirtualFieldDefinition;

$field = new VirtualFieldDefinition([
    'entity_type' => 1, // User entity type
    'name' => 'phone_number',
    'label' => 'Phone Number',
    'data_type' => 'string',
    'required' => true,
    'active' => true,
]);
$field->save();

$field2 = new VirtualFieldDefinition([
    'entity_type' => 1,
    'name' => 'birth_date',
    'label' => 'Date of Birth',
    'data_type' => 'date',
    'required' => false,
    'active' => true,
]);
$field2->save();
```

### Using Virtual Fields

[](#using-virtual-fields)

Once defined, virtual fields work like native model properties:

```
$user = User::findOne(1);

// Get virtual field value
echo $user->phone_number;

// Set virtual field value
$user->phone_number = '+1234567890';
$user->birth_date = '1990-01-15';

// Save (automatically saves virtual fields)
$user->save();

// Mass assignment works too
$user->load(Yii::$app->request->post());
$user->save();
```

Virtual fields are automatically saved when you call `save()` on the model. The behavior hooks into Yii2's `afterInsert` and `afterUpdate` events to persist virtual field changes.

**Note:** A `saveVirtualFields()` method is also available if you need to manually trigger saving of virtual fields, though this is rarely necessary in typical usage.

### Using in Forms

[](#using-in-forms)

Virtual fields integrate seamlessly with ActiveForm:

```
use eseperio\virtualfields\helpers\VirtualFieldRenderer;

$form = ActiveForm::begin();

// Render standard fields
echo $form->field($model, 'username');
echo $form->field($model, 'email');

// Get virtual field definitions
$module = Yii::$app->getModule('virtualFields');
$service = $module->get('service');
$definitions = $service->getDefinitions($model->getObjectType());

// Render all virtual fields
echo VirtualFieldRenderer::renderFields($form, $model, $definitions);

// Or render individual fields
foreach ($definitions as $definition) {
    echo VirtualFieldRenderer::renderField($form, $model, $definition);
}

ActiveForm::end();
```

### Using in DetailView

[](#using-in-detailview)

```
use yii\widgets\DetailView;
use eseperio\virtualfields\helpers\DetailViewHelper;

// Get virtual field definitions
$module = Yii::$app->getModule('virtualFields');
$service = $module->get('service');
$definitions = $service->getDefinitions($model->getObjectType());

// Build attributes array
$attributes = [
    'id',
    'username',
    'email',
];

// Add virtual field attributes
$attributes = array_merge($attributes, DetailViewHelper::getAttributes($definitions));

// Render DetailView
echo DetailView::widget([
    'model' => $model,
    'attributes' => $attributes,
]);
```

### Using in GridView

[](#using-in-gridview)

```
use yii\grid\GridView;
use eseperio\virtualfields\helpers\GridViewHelper;

// Get virtual field definitions
$module = Yii::$app->getModule('virtualFields');
$service = $module->get('service');
$definitions = $service->getDefinitions(1); // User entity type

// Build columns array
$columns = [
    'id',
    'username',
    'email',
];

// Add virtual field columns
$columns = array_merge($columns, GridViewHelper::getColumns($definitions));

// Render GridView
echo GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => $columns,
]);
```

Supported Data Types
--------------------

[](#supported-data-types)

The extension supports the following data types out of the box:

TypeDescriptionPHP TypeExample`string`Short textstring"John Doe"`text`Long textstring"Lorem ipsum..."`int`Integer numberinteger42`float`Decimal numberfloat3.14`bool`Booleanbooleantrue/false`date`Datestring"2024-01-15"`datetime`Date and timestring"2024-01-15 14:30:00"`json`JSON dataarray{"key": "value"}### Custom Data Types

[](#custom-data-types)

You can register custom data types:

```
$module = Yii::$app->getModule('virtualFields');
$service = $module->get('service');

$service->registerDataType(
    'custom_type',
    function($value) { /* cast */ return $value; },
    function($value) { /* serialize */ return (string)$value; },
    function($value) { /* deserialize */ return $value; }
);
```

Field Name Validation
---------------------

[](#field-name-validation)

The extension automatically validates field names to prevent collisions:

- ✅ Checks against database columns
- ✅ Checks against existing properties
- ✅ Checks against getter/setter methods
- ✅ Validates naming patterns (alphanumeric + underscore)
- ✅ Prevents use of reserved names

Architecture
------------

[](#architecture)

### Entity Type Mapping

[](#entity-type-mapping)

The extension uses **integer IDs** to identify entity types internally. This design:

- Provides a stable, efficient identifier
- Allows flexibility in class naming/refactoring
- Enables multi-tenant scenarios

Configure the mapping in the module's `entityMap` property.

### Database Schema

[](#database-schema)

**virtual\_field\_definition** table stores:

- Entity type (integer)
- Field name
- Data type
- Validation rules (required, multiple values)
- Options (JSON)
- Active status

**virtual\_field\_value** table stores:

- Definition reference
- Entity type and ID
- Value (stored as text, cast by type)

### Caching

[](#caching)

Field definitions are cached for performance. Cache is automatically invalidated when definitions change.

Best Practices
--------------

[](#best-practices)

1. **Choose appropriate entity type IDs**: Use a systematic numbering scheme
2. **Be mindful of field names**: Avoid names that might conflict with future model properties
3. **Use appropriate data types**: This ensures proper validation and rendering
4. **Test thoroughly**: Virtual fields should be tested like any other model attribute
5. **Consider performance**: Virtual fields require additional database queries

Troubleshooting
---------------

[](#troubleshooting)

### Virtual fields not appearing

[](#virtual-fields-not-appearing)

- Ensure the behavior is attached to your model
- Verify `getObjectType()` returns the correct entity type ID
- Check that field definitions are active
- Clear cache: `Yii::$app->cache->flush()`

### Validation not working

[](#validation-not-working)

- Ensure validation rules are properly set in the field definition
- Check that the behavior's `beforeValidate` event is being triggered

### Name collision errors

[](#name-collision-errors)

- Choose different field names that don't conflict with existing properties
- Review the validation error message for specific conflicts

Testing
-------

[](#testing)

This library includes comprehensive functional tests using Codeception and SQLite.

### Running Tests

[](#running-tests)

1. Install dependencies:

```
composer install
```

2. Run migrations to set up the test database:

```
composer test-migrate
```

3. Run functional tests:

```
composer test-functional
```

### Migration Structure

[](#migration-structure)

The library has two sets of migrations:

- **`migrations/`** - Library migrations (virtual field tables)

    - `m000000_000000_create_virtual_field_definition_table.php`
    - `m000000_000001_create_virtual_field_value_table.php`
- **`tests/_app/migrations/`** - Test app migrations (test models)

    - `m000000_000002_create_test_model_table.php`
    - `m000000_000003_create_product_table.php`

The `composer test-migrate` script runs both sets of migrations in the correct order.

License
-------

[](#license)

MIT

Contributing
------------

[](#contributing)

Contributions are welcome! Please submit pull requests or open issues on GitHub.

Credits
-------

[](#credits)

Developed by Eseperio.

###  Health Score

32

—

LowBetter than 69% of packages

Maintenance65

Regular maintenance activity

Popularity7

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 58.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

220d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b1e173755eb4a5abae378ed4c8a8e8066f578c3192105c5e3f9b8ea3ef0086e7?d=identicon)[Eseperio](/maintainers/Eseperio)

---

Top Contributors

[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (18 commits)")[![Eseperio](https://avatars.githubusercontent.com/u/5459366?v=4)](https://github.com/Eseperio "Eseperio (13 commits)")

---

Tags

yii2extensionactiverecorddynamic-fieldsvirtual fields

###  Code Quality

TestsCodeception

### Embed Badge

![Health badge](/badges/eseperio-yii2-model-virtual-fields/health.svg)

```
[![Health](https://phpackages.com/badges/eseperio-yii2-model-virtual-fields/health.svg)](https://phpackages.com/packages/eseperio-yii2-model-virtual-fields)
```

###  Alternatives

[dmstr/yii2-cookie-consent

Yii2 Cookie Consent Widget

1455.6k](/packages/dmstr-yii2-cookie-consent)[imanilchaudhari/yii2-currency-converter

This extension will help to find out current currency conversion rate.

2111.7k](/packages/imanilchaudhari-yii2-currency-converter)[richardfan1126/yii2-js-register

Yii2 widget to register JS into view

1359.3k7](/packages/richardfan1126-yii2-js-register)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
