Skip to content

Fixes: getting immutable_datetime property fails if Date::use(CarbonImmutable::class) is set #3342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
2 changes: 1 addition & 1 deletion src/Eloquent/DocumentModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public function fromDateTime($value): UTCDateTime
*
* @param mixed $value
*/
protected function asDateTime($value): Carbon
protected function asDateTime($value): DateTimeInterface
{
// Convert UTCDateTime instances to Carbon.
if ($value instanceof UTCDateTime) {
Expand Down
43 changes: 43 additions & 0 deletions tests/DateTimeImmutableTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Eloquent;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use MongoDB\Laravel\Tests\Models\Anniversary;
use MongoDB\Laravel\Tests\TestCase;

use function assert;

final class DateTimeImmutableTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Anniversary::truncate();
}

protected function tearDown(): void
{
Date::useDefault();

parent::tearDown();
}

public function testCanReturnCarbonImmutableObject(): void
{
Date::use(CarbonImmutable::class);

Anniversary::create([
'name' => 'John',
'anniversary' => new CarbonImmutable('2020-01-01 00:00:00'),
]);

$anniversary = Anniversary::sole();
assert($anniversary instanceof Anniversary);
self::assertInstanceOf(CarbonImmutable::class, $anniversary->anniversary);
}
}
30 changes: 30 additions & 0 deletions tests/Models/Anniversary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use MongoDB\Laravel\Eloquent\DocumentModel;
use MongoDB\Laravel\Eloquent\Model as Eloquent;
use MongoDB\Laravel\Query\Builder;

/**
* @property string $name
* @property string $anniversary
* @mixin Eloquent
* @method static Builder create(...$values)
* @method static Builder truncate()
* @method static Eloquent sole(...$parameters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These annotations are interesting, I think we should document this practice (something I will ask the doc team).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

credit goes to @Treggats. I followed his HiddenAnimal model.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to help :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GromNaN the thing with Laravel Models is that by default they have the type Model. Which makes sense, as the model extends that class, but then the IDE doesn't know about any of the methods, relations, properties, etc.

These docblocks provide the IDE with the context it should have. Note; the @method docblock can not be used if the method already exists in the class.

Personally I also use @property for the columns of the database table and the relation once fetched.
The @property-read docblock is used for the Builder return type of a relation.

A little gotcha is that sometimes you need a additional docblock on the variable. Like this.

use Tests\Models\Anniversary;

/** @var Anniversary $anniversary */
$anniversary = Anniversary::query()->where('name', 'John')->first();

It then knows about the properties, relations, etc.

Hope this helps.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'm tracking this to work on it later PHPORM-316

*/
class Anniversary extends Model
{
use DocumentModel;

protected $keyType = 'string';
protected $connection = 'mongodb';
protected $table = 'anniversary';
protected $fillable = ['name', 'anniversary'];

protected $casts = ['anniversary' => 'immutable_datetime'];
}
Loading