diff --git a/README.md b/README.md index 5b4c969..8d94950 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Esensi Model Traits Package -> Version 1 +> Version 3 An [Esensi](https://github.com/esensi) package, coded by [SiteRocket Labs®](https://www.siterocket.com). @@ -8,7 +8,7 @@ The `Esensi/Model` package is just one package that makes up [Esensi](https://gi ## Note -This code is specifically designed to be compatible with the [Laravel Framework](https://laravel.com) and may not be compatible as a stand-alone dependency or as part of another framework. +This code is specifically designed to be compatible with the [Laravel Framework ^10](https://laravel.com) and may not be compatible as a stand-alone dependency or as part of another framework. ### Extend the Default Model @@ -92,7 +92,7 @@ class Post extends SoftModel { Add the `esensi/model` package as a dependency to the application. Using [Composer](https://getcomposer.org), this can be done from the command line: ```bash -composer require esensi/model 0.6.* +composer require esensi/model ``` Or manually it can be added to the `composer.json` file: @@ -100,7 +100,7 @@ Or manually it can be added to the `composer.json` file: ```json { "require": { - "esensi/model": "0.6.*" + "esensi/model": "^3.0" } } ``` @@ -126,7 +126,6 @@ This Esensi package has been featured in various places from university classroo > **Model validation** is the method of establishing rules to ensure when you’re creating, or updating, an object based on a model, that all of its field values are set appropriately. That all required fields are filled, that all date fields are formatted properly, etc. -- [Read _Laravel 8 Model Validation With the Esensi Model Traits Package_](https://selftaughtcoders.com/from-idea-to-launch/lesson-24/laravel-8-model-validation-esensi-model-traits-package/) - [Signup for _From Ideas to Launch_](https://selftaughtcoders.com/from-idea-to-launch/) ### Auto-Validating On Save @@ -537,7 +536,7 @@ This package includes the [`JugglingModelTrait`](https://github.com/esensi/model - create custom types to cast to with magic model methods like: - Example: `fooBar` => `juggleFooBar()` -Like all the traits, it is self-contained and can be used individually. Be aware, however, that using this trait does overload the magic `__get()` and `__set()` methods of the model (see [Esensi\Model\Model](https://github.com/esensi/model/blob/master/src/Model.php) source code for how to deal with overloading conflicts). Special credit goes to the brilliant [Dayle Rees](https://github.com/daylerees), author of [Code Bright book](https://leanpub.com/codebright), who inspired this trait with his [pull request to Laravel](https://github.com/laravel/framework/pull/4948) which eventually arrived in [Laravel 8 as Attribute Casting](http://laravel.com/docs/eloquent-mutators#attribute-casting) which supports basic type casting. +Like all the traits, it is self-contained and can be used individually. Be aware, however, that using this trait does overload the magic `__get()` and `__set()` methods of the model (see [Esensi\Model\Model](https://github.com/esensi/model/blob/master/src/Model.php) source code for how to deal with overloading conflicts). Special credit goes to the brilliant [Dayle Rees](https://github.com/daylerees), author of [Code Bright book](https://leanpub.com/codebright), who inspired this trait with his [pull request to Laravel](https://github.com/laravel/framework/pull/4948) which eventually arrived in [Laravel as Attribute Casting](http://laravel.com/docs/eloquent-mutators#attribute-casting) which supports basic type casting. ### Auto-Juggling on Access @@ -791,8 +790,8 @@ This package uses [PHPUnit](http://phpunit.de) to automate the code testing proc ```json { "require-dev": { - "phpunit/phpunit": "4.1.*", - "mockery/mockery": "0.9.*" + "phpunit/phpunit": "10.0.7", + "mockery/mockery": "1.5.1" } } ``` diff --git a/composer.json b/composer.json index e400787..2994d81 100644 --- a/composer.json +++ b/composer.json @@ -14,20 +14,24 @@ ], "license": "MIT", "require": { - "php": "^7.3|^8.0", - "nesbot/carbon": "^2.53.1", - "illuminate/contracts": "^8.0|^9.0", - "illuminate/database": "^8.0|^9.0", - "illuminate/encryption": "^8.0|^9.0", - "illuminate/events": "^8.0|^9.0", - "illuminate/hashing": "^8.0|^9.0", - "illuminate/support": "^8.0|^9.0", - "illuminate/validation": "^8.0|^9.0", + "php": "^8.1", + "nesbot/carbon": "^2.67", + "illuminate/contracts": "^9.0|^10.0|^11.0", + "illuminate/database": "^10.0", + "illuminate/encryption": "^10.0", + "illuminate/events": "^10.0", + "illuminate/hashing": "^10.0", + "illuminate/support": "^10.0", + "illuminate/validation": "^10.0", "paragonie/random_compat": "^8.0|^9.0", "symfony/polyfill-php81": "^1.23", - "watson/validating": "^6.1" + "watson/validating": "^8.1" }, + "require-dev": { + "phpunit/phpunit": "10.0.7", + "mockery/mockery": "1.5.1" + }, "autoload": { "psr-4": { "Esensi\\Model\\": "src/" diff --git a/src/Model.php b/src/Model.php index e9084d7..ad10896 100644 --- a/src/Model.php +++ b/src/Model.php @@ -8,6 +8,8 @@ use Esensi\Model\Contracts\PurgingModelInterface; use Esensi\Model\Contracts\RelatingModelInterface; use Esensi\Model\Contracts\ValidatingModelInterface; +use Esensi\Model\Traits\BackwardCompatibleDatesTrait; +use Esensi\Model\Traits\DatesToCastsTrait; use Esensi\Model\Traits\EncryptingModelTrait; use Esensi\Model\Traits\HashingModelTrait; use Esensi\Model\Traits\JugglingModelTrait; @@ -76,6 +78,22 @@ abstract class Model extends Eloquent implements */ use RelatingModelTrait; + /* + * This trait is designed for automatic conversion of the $dates property to the $casts property in Laravel Eloquent models. + * When a model is being saved, updated, or retrieved from the database, the trait checks for the presence of the $dates property + * and adds corresponding values to the $casts array if they are not already defined. + * + * @see Esensi\Model\Traits\DatesToCastsTrait + */ + use DatesToCastsTrait; + + /* + * Get the attributes that should be converted to dates. + * + * @see Esensi\Model\Traits\BackwardCompatibleDatesTrait + */ + use BackwardCompatibleDatesTrait; + /** * The attributes that should be mutated to dates. * diff --git a/src/Traits/BackwardCompatibleDatesTrait.php b/src/Traits/BackwardCompatibleDatesTrait.php new file mode 100644 index 0000000..b553f11 --- /dev/null +++ b/src/Traits/BackwardCompatibleDatesTrait.php @@ -0,0 +1,18 @@ +dates, $defaults)); + } +} diff --git a/src/Traits/DatesToCastsTrait.php b/src/Traits/DatesToCastsTrait.php new file mode 100644 index 0000000..5915468 --- /dev/null +++ b/src/Traits/DatesToCastsTrait.php @@ -0,0 +1,38 @@ +convertDatesToCasts(); + }); + } + } + + /** + * Convert $dates to $casts automatically. + * + * @return void + */ + protected function convertDatesToCasts() + { + if (property_exists($this, 'dates') && property_exists($this, 'casts')) { + foreach ($this->dates as $dateColumn) { + if (!array_key_exists($dateColumn, $this->casts)) { + $this->casts[$dateColumn] = 'datetime'; + } + } + } + } +} diff --git a/tests/EncryptingModelTraitTest.php b/tests/EncryptingModelTraitTest.php index f058d56..92ca784 100644 --- a/tests/EncryptingModelTraitTest.php +++ b/tests/EncryptingModelTraitTest.php @@ -2,7 +2,7 @@ use Esensi\Model\Model; use Illuminate\Encryption\Encrypter; -use PHPUnit_Framework_TestCase as PHPUnit; +use PHPUnit\Framework\TestCase as PHPUnit; /** * Tests for the Encrypting Model Trait. @@ -13,7 +13,7 @@ class EncryptingModelTraitTest extends PHPUnit /** * Set Up and Prepare Tests. */ - public function setUp() + public function setUp(): void { // Mock the Model that uses the custom trait $this->model = Mockery::mock('ModelEncryptingStub'); @@ -23,7 +23,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } @@ -267,7 +267,7 @@ public function testGettingEncrypter() // Check that its an Encrypter $model = new ModelEncryptingStub(); $encrypter = $model->getEncrypter(); - $this->assertInstanceOf('\Illuminate\Encryption\Encrypter', $encrypter, $encrypter); + $this->assertInstanceOf('\Illuminate\Encryption\Encrypter', $encrypter); } /** @@ -515,7 +515,7 @@ public function __construct() parent::__construct(); // Assign a default encrypter for mocking purposes - $this->encrypter = EncrypterStub::newInstance(); + $this->encryptor = EncrypterStub::newInstance(); } } diff --git a/tests/HashingModelObserverTest.php b/tests/HashingModelObserverTest.php index b881319..569cfdc 100644 --- a/tests/HashingModelObserverTest.php +++ b/tests/HashingModelObserverTest.php @@ -1,7 +1,7 @@ observer = new HashingModelObserver(); @@ -24,7 +24,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } diff --git a/tests/HashingModelTraitTest.php b/tests/HashingModelTraitTest.php index 82b361f..82cf6bf 100644 --- a/tests/HashingModelTraitTest.php +++ b/tests/HashingModelTraitTest.php @@ -3,7 +3,7 @@ use Esensi\Model\Model; use Illuminate\Contracts\Hashing\Hasher; use Illuminate\Hashing\BcryptHasher; -use PHPUnit_Framework_TestCase as PHPUnit; +use PHPUnit\Framework\TestCase as PHPUnit; /** * Tests for the Hashing Model Trait. @@ -14,7 +14,7 @@ class HashingModelTraitTest extends PHPUnit /** * Set Up and Prepare Tests. */ - public function setUp() + public function setUp(): void { // Mock the Model that uses the custom trait $this->model = Mockery::mock('ModelHashingStub'); @@ -24,7 +24,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } @@ -267,7 +267,8 @@ public function testGettingHasher() // Check that its an Hasher $model = new ModelHashingStub(); $hasher = $model->getHasher(); - $this->assertInstanceOf('\Illuminate\Hashing\BcryptHasher', $hasher, $hasher); + + $this->assertInstanceOf('\Illuminate\Hashing\BcryptHasher', $hasher); } /** diff --git a/tests/JugglingModelTraitTest.php b/tests/JugglingModelTraitTest.php index c98cf48..484be3f 100644 --- a/tests/JugglingModelTraitTest.php +++ b/tests/JugglingModelTraitTest.php @@ -3,7 +3,7 @@ use Carbon\Carbon; use Esensi\Model\Model; use Illuminate\Database\Connection; -use PHPUnit_Framework_TestCase as PHPUnit; +use PHPUnit\Framework\TestCase as PHPUnit; /** * Tests for the Purging Model Trait. @@ -14,7 +14,7 @@ class JugglingModelTraitTest extends PHPUnit /** * Set Up and Prepare Tests. */ - public function setUp() + public function setUp(): void { // Mock the Model that uses the custom trait $this->model = Mockery::mock('ModelJugglingStub'); @@ -27,7 +27,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } @@ -419,17 +419,17 @@ public function testJuggleAttributes() $this->assertCount($count, $attributes); // Check that the attributes are set and return the correct types - $this->assertInternalType('string', $this->model->myString); + $this->assertIsString($this->model->myString); $this->assertInstanceOf('\Carbon\Carbon', $this->model->myDate); - $this->assertInternalType('string', $this->model->myDateTime); - $this->assertInternalType('integer', $this->model->myTimestamp); - $this->assertInternalType('integer', $this->model->myInt); - $this->assertInternalType('integer', $this->model->myInteger); - $this->assertInternalType('boolean', $this->model->myBool); - $this->assertInternalType('boolean', $this->model->myBoolean); - $this->assertInternalType('float', $this->model->myDouble); - $this->assertInternalType('float', $this->model->myFloat); - $this->assertInternalType('array', $this->model->myArray); + $this->assertIsString($this->model->myDateTime); + $this->assertIsInt($this->model->myTimestamp); + $this->assertIsInt($this->model->myInt); + $this->assertIsInt($this->model->myInteger); + $this->assertIsBool($this->model->myBool); + $this->assertIsBool($this->model->myBoolean); + $this->assertIsFloat($this->model->myDouble); + $this->assertIsFloat($this->model->myFloat); + $this->assertIsArray($this->model->myArray); } /** @@ -473,7 +473,7 @@ public function testJuggleDateTime() public function testJuggleTimestamp() { $timestamp = $this->model->juggleTimestamp('1970-01-01'); - $this->assertInternalType('integer', $timestamp); + $this->assertIsInt($timestamp); $this->assertEquals(18000, $timestamp); } @@ -490,14 +490,14 @@ public function testJuggleBoolean() // Test true values foreach ([true, 1, '1'] as $value) { $boolean = $this->model->juggleBoolean($value); - $this->assertInternalType('boolean', $boolean); + $this->assertIsBool($boolean); $this->assertTrue($boolean); } // Test false values foreach ([false, 0, '0'] as $value) { $boolean = $this->model->juggleBoolean($value); - $this->assertInternalType('boolean', $boolean); + $this->assertIsBool($boolean); $this->assertFalse($boolean); } } @@ -508,11 +508,11 @@ public function testJuggleBoolean() public function testJuggleInteger() { $integer = $this->model->juggleInteger('1'); - $this->assertInternalType('integer', $integer); + $this->assertIsInt($integer); $this->assertEquals(1, $integer); $integer = $this->model->juggleInteger('1 large pizza'); - $this->assertInternalType('integer', $integer); + $this->assertIsInt($integer); $this->assertEquals(1, $integer); } @@ -522,11 +522,11 @@ public function testJuggleInteger() public function testJuggleFloat() { $float = $this->model->juggleFloat('1.23456789'); - $this->assertInternalType('float', $float); + $this->assertIsFloat($float); $this->assertEquals(1.23456789, $float); $float = $this->model->juggleFloat(1 / 4); - $this->assertInternalType('float', $float); + $this->assertIsFloat($float); $this->assertEquals(0.25, $float); } @@ -536,7 +536,7 @@ public function testJuggleFloat() public function testJuggleString() { $string = $this->model->juggleString(1 / 4); - $this->assertInternalType('string', $string); + $this->assertIsString($string); $this->assertEquals('0.25', $string); } @@ -546,11 +546,11 @@ public function testJuggleString() public function testJuggleArray() { $array = $this->model->juggleArray([]); - $this->assertInternalType('array', $array); + $this->assertIsArray($array); $this->assertEmpty($array); $array = $this->model->juggleArray('foo'); - $this->assertInternalType('array', $array); + $this->assertIsArray($array); $this->assertEquals(['foo'], $array); } } diff --git a/tests/ModelTest.php b/tests/ModelTest.php index fa37df6..44d3325 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -1,7 +1,7 @@ model = Mockery::mock('ModelStub'); @@ -22,7 +22,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } diff --git a/tests/PurgingModelObserverTest.php b/tests/PurgingModelObserverTest.php index abf2ff2..9b83136 100644 --- a/tests/PurgingModelObserverTest.php +++ b/tests/PurgingModelObserverTest.php @@ -1,7 +1,7 @@ observer = new PurgingModelObserver(); @@ -24,7 +24,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } diff --git a/tests/PurgingModelTraitTest.php b/tests/PurgingModelTraitTest.php index 1f2c69b..b73d059 100644 --- a/tests/PurgingModelTraitTest.php +++ b/tests/PurgingModelTraitTest.php @@ -1,7 +1,7 @@ model = Mockery::mock('ModelPurgingStub'); @@ -22,7 +22,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } diff --git a/tests/RelatingModelTraitTest.php b/tests/RelatingModelTraitTest.php index f323238..a995afb 100644 --- a/tests/RelatingModelTraitTest.php +++ b/tests/RelatingModelTraitTest.php @@ -4,7 +4,7 @@ use Illuminate\Database\Connection; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphTo; -use PHPUnit_Framework_TestCase as PHPUnit; +use PHPUnit\Framework\TestCase as PHPUnit; /** * Tests for the Relating Model Trait. @@ -15,7 +15,7 @@ class RelatingModelTraitTest extends PHPUnit /** * Set Up and Prepare Tests. */ - public function setUp() + public function setUp(): void { // Mock the Model that uses the custom trait $this->model = Mockery::mock('ModelRelatingStub'); @@ -25,7 +25,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); } diff --git a/tests/SoftModelTest.php b/tests/SoftModelTest.php index e2d093a..bb9423b 100644 --- a/tests/SoftModelTest.php +++ b/tests/SoftModelTest.php @@ -1,7 +1,7 @@ model = Mockery::mock('SoftModelStub'); @@ -22,7 +22,7 @@ public function setUp() /** * Tear Down and Clean Up Tests. */ - public function tearDown() + public function tearDown(): void { Mockery::close(); }