Skip to content
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"require-dev": {
"doctrine/annotations": "^1.14.3 || ^2.0.1",
"phpunit/phpunit": "^10.1",
"vimeo/psalm": "^5.26",
"vimeo/psalm": "^5.26 || ^6.10",
"spiral/code-style": "^2.2",
"spiral/dumper": "^3.3"
},
Expand Down
8 changes: 7 additions & 1 deletion src/Annotation/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Cycle\Annotated\Annotation;

use Cycle\ORM\Parser\Typecast;
use Doctrine\Common\Annotations\Annotation\Target;
use JetBrains\PhpStorm\ExpectedValues;
use Spiral\Attributes\NamedArgumentConstructor;
Expand Down Expand Up @@ -46,6 +45,7 @@ class Column
* @param bool $readonlySchema Set to true to disable schema synchronization for the assigned column.
* @param mixed ...$attributes Other database specific attributes. Use named notation to define them.
* For example: #[Column('smallInt', unsigned: true, zerofill: true)]
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
#[ExpectedValues(values: ['primary', 'bigPrimary', 'enum', 'boolean',
Expand All @@ -68,6 +68,7 @@ public function __construct(
protected mixed $typecast = null,
protected bool $castDefault = false,
protected bool $readonlySchema = false,
protected bool $obsolete = false,
mixed ...$attributes,
) {
if ($default !== null) {
Expand Down Expand Up @@ -135,6 +136,11 @@ public function isReadonlySchema(): bool
return $this->readonlySchema;
}

public function isObsolete(): bool
{
return $this->obsolete;
}

/**
* @return array<non-empty-string, mixed>
*/
Expand Down
4 changes: 3 additions & 1 deletion src/Annotation/Relation/BelongsTo.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class BelongsTo extends Relation
* Defaults to {@see $fkAction}.
* @param bool $indexCreate Create an index on innerKey.
* @param non-empty-string $load Relation load approach.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
Expand All @@ -55,9 +56,10 @@ public function __construct(
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'lazy',
?Inverse $inverse = null,
bool $obsolete = false,
) {
$this->inverse = $inverse;

parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}
}
4 changes: 3 additions & 1 deletion src/Annotation/Relation/Embedded.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ class Embedded extends Relation
* @param non-empty-string $target Entity to embed.
* @param 'eager'|'lazy' $load Relation load approach.
* @param string|null $prefix Prefix for embedded entity columns.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'eager',
?string $prefix = null,
bool $obsolete = false,
) {
$this->embeddedPrefix = $prefix;

parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}

public function getInverse(): ?Inverse
Expand Down
4 changes: 3 additions & 1 deletion src/Annotation/Relation/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class HasMany extends Relation
* @param bool $indexCreate Create an index on outerKey.
* @param non-empty-string|null $collection Collection that will contain loaded entities.
* @param non-empty-string $load Relation load approach.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
Expand All @@ -60,9 +61,10 @@ public function __construct(
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'lazy',
?Inverse $inverse = null,
bool $obsolete = false,
) {
$this->inverse = $inverse;

parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}
}
4 changes: 3 additions & 1 deletion src/Annotation/Relation/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class HasOne extends Relation
* Defaults to {@see $fkAction}.
* @param bool $indexCreate Create index on outerKey.
* @param non-empty-string $load Relation load approach.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
Expand All @@ -55,9 +56,10 @@ public function __construct(
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'lazy',
?Inverse $inverse = null,
bool $obsolete = false,
) {
$this->inverse = $inverse;

parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}
}
4 changes: 3 additions & 1 deletion src/Annotation/Relation/ManyToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ManyToMany extends Relation
* @param bool $indexCreate Create index on [throughInnerKey, throughOuterKey].
* @param non-empty-string|null $collection Collection that will contain loaded entities.
* @param non-empty-string $load Relation load approach.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
Expand Down Expand Up @@ -71,9 +72,10 @@ public function __construct(
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'lazy',
?Inverse $inverse = null,
bool $obsolete = false,
) {
$this->inverse = $inverse;

parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}
}
4 changes: 3 additions & 1 deletion src/Annotation/Relation/RefersTo.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class RefersTo extends Relation
* Defaults to {@see $fkAction}.
* @param bool $indexCreate Create an index on outerKey.
* @param non-empty-string $load Relation load approach.
* @param bool $obsolete The property should not be displayed in schema but must remains in the database.
*/
public function __construct(
string $target,
Expand All @@ -55,8 +56,9 @@ public function __construct(
#[ExpectedValues(values: ['lazy', 'eager'])]
string $load = 'lazy',
?Inverse $inverse = null,
bool $obsolete = false,
) {
$this->inverse = $inverse;
parent::__construct($target, $load);
parent::__construct($target, $load, $obsolete);
}
}
2 changes: 2 additions & 0 deletions src/Annotation/Relation/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ abstract class Relation implements RelationInterface
/**
* @param non-empty-string|null $target
* @param non-empty-string $load
* @param bool $obsolete The property should not be displayed in schema but must remains in the database. Useful for the further safe DROP COLUMN.
*/
public function __construct(
protected ?string $target,
protected string $load = 'lazy',
protected bool $obsolete = false,
) {}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/Configurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ public function initField(string $name, Column $column, \ReflectionClass $class,
$field->getAttributes()->set($k, $v);
}

$field->getAttributes()->set('obsolete', $column->isObsolete());

return $field;
}

Expand Down
31 changes: 31 additions & 0 deletions tests/Annotated/Fixtures/Fixtures26/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Cycle\Annotated\Tests\Fixtures\Fixtures26;

use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Embeddable;

/**
* @Embeddable(columnPrefix="address_")
*/
#[Embeddable(columnPrefix: 'address_')]
class Address
{
/** @Column(type="string") */
#[Column(type: 'string')]
protected $city;

/** @Column(type="string") */
#[Column(type: 'string')]
protected $country;

/** @Column(type="string") */
#[Column(type: 'string')]
protected $address;

/** @Column(type="int") */
#[Column(type: 'integer')]
protected $zipcode;
}
28 changes: 28 additions & 0 deletions tests/Annotated/Fixtures/Fixtures26/City.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Cycle\Annotated\Tests\Fixtures\Fixtures26;

use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Relation\HasMany;

/**
* @Entity(table="city")
*/
#[Entity(table: 'city')]
class City
{
/** @Column(type="primary") */
#[Column(type: 'primary')]
public $id;

/** @Column(type="string") */
#[Column(type: 'string')]
public $name;

/** @HasMany(target=User::class, fkCreate=false, obsolete=true) */
#[HasMany(target: User::class, fkCreate: false, obsolete: true)]
private array $bornUsers = [];
}
30 changes: 30 additions & 0 deletions tests/Annotated/Fixtures/Fixtures26/Passport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Cycle\Annotated\Tests\Fixtures\Fixtures26;

use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Relation\BelongsTo;

/**
* @Entity(table="passport")
*/
#[Entity(table: 'passport')]
class Passport
{
/** @Column(type="primary") */
#[Column(type: 'primary')]
protected $id;

/** @Column(type="string") */
#[Column(type: 'string')]
protected $number;

/**
* @BelongsTo(target=User::class, obsolete=true)
*/
#[BelongsTo(target: User::class, innerKey: 'passport_id', outerKey: 'id', obsolete: true)]
protected User $user;
}
52 changes: 52 additions & 0 deletions tests/Annotated/Fixtures/Fixtures26/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Cycle\Annotated\Tests\Fixtures\Fixtures26;

use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Relation\Embedded;
use Cycle\Annotated\Annotation\Relation\HasOne;
use Cycle\Annotated\Annotation\Relation\RefersTo;

/**
* @Entity(table="user")
*/
#[Entity(table: 'user')]
class User
{
/** @Column(type="primary") */
#[Column(type: 'primary')]
public $id;

/**
* @Column(type="integer", nullable=true, obsolete=true)
*
* @deprecated Since May 5, 2025
*/
#[Column(type: 'string', nullable: true, obsolete: true)]
public $skype = null;

/**
* @Embedded(target=Address::class, obsolete=true)
*/
#[Embedded(target: Address::class, obsolete: true)]
public Address $address;

/**
* @HasOne(target=Passport::class, obsolete=true)
*/
#[HasOne(target: Passport::class, obsolete: true)]
public Passport $passport;

/** @RefersTo(target=City::class, innerKey="born_city_id", outerKey="id", obsolete=true) */
#[RefersTo(target: City::class, innerKey: 'born_city_id', outerKey: 'id', obsolete: true)]
public City $bornCity;

public function __construct(City $bornCity)
{
$this->address = new Address();
$this->bornCity = $bornCity;
}
}
Loading
Loading