1
0
Fork 0
mirror of https://github.com/archtechx/virtualcolumn.git synced 2025-12-12 17:04:04 +00:00
virtualcolumn/tests/VirtualColumnTest.php

258 lines
7.9 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Stancl\VirtualColumn\Tests;
use Orchestra\Testbench\TestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Model;
use Stancl\VirtualColumn\VirtualColumn;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class VirtualColumnTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
$this->loadMigrationsFrom(__DIR__ . '/etc/migrations');
}
public function testKeysWhichDontHaveTheirOwnColumnGoIntoDataJsonColumn()
{
$model = MyModel::create([
'foo' => 'bar',
]);
// Test that model works correctly
$this->assertSame('bar', $model->foo);
$this->assertSame(null, $model->data);
// Low level test to assert database structure
$this->assertSame(['foo' => 'bar'], json_decode(DB::table('my_models')->where('id', $model->id)->first()->data, true));
$this->assertSame(null, DB::table('my_models')->where('id', $model->id)->first()->foo ?? null);
// Model has the correct structure when retrieved
$model = MyModel::first();
$this->assertSame('bar', $model->foo);
$this->assertSame('bar', $model->getOriginal('foo'));
$this->assertSame(null, $model->data);
// Model can be updated
$model->update([
'foo' => 'baz',
'abc' => 'xyz',
]);
$this->assertSame('baz', $model->foo);
$this->assertSame('baz', $model->getOriginal('foo'));
$this->assertSame('xyz', $model->abc);
$this->assertSame('xyz', $model->getOriginal('abc'));
$this->assertSame(null, $model->data);
// Model can be retrieved after update & is structured correctly
$model = MyModel::first();
$this->assertSame('baz', $model->foo);
$this->assertSame('xyz', $model->abc);
$this->assertSame(null, $model->data);
}
public function testModelIsAlwaysDecodedWhenAccessedByUserEvent()
{
MyModel::retrieved(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::saving(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::updating(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::creating(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::saved(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::updated(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
MyModel::created(function (MyModel $model) {
$this->assertFalse($model->dataEncoded);
});
$model = MyModel::create(['foo' => 'bar']);
$model->update(['foo' => 'baz']);
MyModel::first();
}
public function testColumnNamesAreGeneratedCorrectly()
{
// FooModel's virtual data column name is 'virtual'
$virtualColumnName = 'virtual->foo';
$customColumnName = 'custom1';
/** @var FooModel $model */
$model = FooModel::create([
'custom1' => $customColumnName,
'foo' => $virtualColumnName
]);
$this->assertSame($customColumnName, $model->getColumnForQuery('custom1'));
$this->assertSame($virtualColumnName, $model->getColumnForQuery('foo'));
}
public function testModelsExtendingAParentModelUsingVirtualcolumnGetEncodedCorrectly()
{
// Create a model that extends a parent model using VirtualColumn
// 'foo' is a custom column, 'data' is the virtual column
FooChild::create(['foo' => 'foo']);
$encodedFoo = DB::select('select * from foo_childs limit 1')[0];
// Assert that the model was encoded correctly
$this->assertSame($encodedFoo->data, '[]');
$this->assertSame($encodedFoo->foo, 'foo');
// Create another child model of the same parent
// 'bar' is a custom column, 'data' is the virtual column
BarChild::create(['bar' => 'bar']);
$encodedBar = DB::select('select * from bar_childs limit 1')[0];
$this->assertSame($encodedBar->data, '[]');
$this->assertSame($encodedBar->bar, 'bar');
}
// maybe add an explicit test that the saving() and updating() listeners don't run twice?
public function testEncryptedCastsWorkWithVirtualColumn() {
// Custom encrypted castables have to be specified in the $customEncryptedCastables static property
MyModel::$customEncryptedCastables = [EncryptedCast::class];
/** @var MyModel $model */
$model = MyModel::create($encryptedAttributes = [
'password' => 'foo', // 'encrypted'
'array' => ['foo', 'bar'], // 'encrypted:array'
'collection' => collect(['foo', 'bar']), // 'encrypted:collection'
'json' => json_encode(['foo', 'bar']), // 'encrypted:json'
'object' => (object) json_encode(['foo', 'bar']), // 'encrypted:object'
'custom' => 'foo', // Custom castable 'EncryptedCast::class'
'null_value' => null, // 'encrypted'
]);
foreach($encryptedAttributes as $key => $expectedValue) {
$savedValue = $model->getAttributes()[$key]; // Encrypted
if ($savedValue !== null) {
$this->assertTrue($model->valueEncrypted($savedValue));
$this->assertNotEquals($expectedValue, $savedValue);
}
$retrievedValue = $model->$key; // Decrypted
$this->assertEquals($expectedValue, $retrievedValue);
}
// Reset static property
MyModel::$customEncryptedCastables = [];
}
public function testUpdatingModelDoesNotStoreTimestampsInTheVirtualColumn() {
/** @var TimestampModel $model */
$model = TimestampModel::create();
$dbRecordDataColumn = fn () => DB::selectOne('select * from timestamp_models where id = ?', [$model->id])->data;
$this->assertStringNotContainsString('created_at', $dbRecordDataColumn());
$this->assertStringNotContainsString('updated_at', $dbRecordDataColumn());
$model->update(['data' => ['virtual' => 'bar']]);
$this->assertStringNotContainsString('created_at', $dbRecordDataColumn());
$this->assertStringNotContainsString('updated_at', $dbRecordDataColumn());
}
}
class TimestampModel extends Model
{
use VirtualColumn;
public $timestamps = true;
protected $guarded = [];
}
class ParentModel extends Model
{
use VirtualColumn;
public $timestamps = false;
protected $guarded = [];
}
class MyModel extends ParentModel
{
public $casts = [
'password' => 'encrypted',
'array' => 'encrypted:array',
'collection' => 'encrypted:collection',
'json' => 'encrypted:json',
'object' => 'encrypted:object',
'custom' => EncryptedCast::class,
'null_value' => 'encrypted',
];
}
class FooModel extends ParentModel
{
public static function getCustomColumns(): array
{
return [
'id',
'custom1',
'custom2',
];
}
public static function getDataColumn(): string
{
return 'virtual';
}
}
class EncryptedCast implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return Crypt::decryptString($value);
}
public function set($model, $key, $value, $attributes)
{
return Crypt::encryptString($value);
}
}
class FooChild extends ParentModel
{
public $table = 'foo_childs';
public static function getCustomColumns(): array
{
return [
'id',
'foo',
];
}
}
class BarChild extends ParentModel
{
public $table = 'bar_childs';
public static function getCustomColumns(): array
{
return [
'id',
'bar',
];
}
}