Skip to content

Commit

Permalink
Support PHP8 attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
iquito committed Dec 18, 2020
1 parent 6dc38c0 commit f60c632
Show file tree
Hide file tree
Showing 14 changed files with 562 additions and 74 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ before_script:

script:
- composer phpunit_clover
- composer phpstan
- composer psalm
- if [ "${TRAVIS_PHP_VERSION:0:1}" == "8" ]; then composer phpstan; fi
- if [ "${TRAVIS_PHP_VERSION:0:1}" == "8" ]; then composer psalm; fi
- composer phpcs
- if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build -t clover --exit-code $TRAVIS_TEST_RESULT; fi
- if [ "$TRAVIS_PULL_REQUEST" == "false" -a "${TRAVIS_PHP_VERSION:0:1}" == "8" ]; then ./cc-test-reporter after-build -t clover --exit-code $TRAVIS_TEST_RESULT; fi

notifications:
email: false
86 changes: 51 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,43 @@ class User
}
```

Or if you are using PHP8+, use the new attributes:

```php
namespace Application\Entity;

use Squirrel\Entities\Annotation\Entity;
use Squirrel\Entities\Annotation\Field;

#[Entity("users")]
class User
{
#[Field("user_id", autoincrement: true)]
private int $userId;

#[Field("active")]
private bool $active;

#[Field("street_name")]
private ?string $streetName;

#[Field("street_number")]
private ?string $streetNumber;

#[Field("city")]
private string $city;

#[Field("balance")]
private float $balance;

#[Field("picture_file", blob: true)]
private ?string $picture;

#[Field("visits")]
private int $visitsNumber;
}
```

The class is defined as an entity with the table name, and each class property is defined as a table field with the column name in the database, where the type is taken from the PHP property type (string, int, float, bool). If the property type is nullable, the column type is assumed to be nullable too. You can also define if it is an autoincrement column (called SERIAL in Postgres) and if it is a blob column (binary large object, called "blob" in most databases or "bytea" in Postgres).

Whether the class properties are private, protected or public does not matter, you can choose whatever names you want, and you can design the rest of the class however you want. You can even make the classes read-only, by having private properties and only defining getters - see [Read-only entity objects](#read-only-entity-objects) for more details on why you would want to do that.
Expand Down Expand Up @@ -464,24 +501,16 @@ namespace Application\Entity;
use Squirrel\Entities\Annotation\Entity;
use Squirrel\Entities\Annotation\Field;

/**
* @Entity("users_visits")
*/
#[Entity("users_visits")]
class Visit
{
/**
* @Field("visit_id", autoincrement=true)
*/
#[Field("visit_id", autoincrement: true)]
private int $visitId = 0;

/**
* @Field("user_id")
*/
#[Field("user_id")]
private int $userId = 0;

/**
* @Field("created_timestamp")
*/
#[Field("created_timestamp")]
private int $timestamp = 0;
}
```
Expand Down Expand Up @@ -750,33 +779,25 @@ namespace Application\Entity;
use Squirrel\Entities\Annotation\Entity;
use Squirrel\Entities\Annotation\Field;

/**
* @Entity("users")
*/
#[Entity("users")]
class User
{
/**
* @Field("user_id", autoincrement=true)
*/
#[Field("user_id", autoincrement=true)]
private int $userId = 0;

/**
* @Field("active")
*/
#[Field("active")]
private bool $active = false;

/**
* @Field("note_data")
*
* @var string JSON data in the database
*/
#[Field("note_data")]
private string $notes = '';

/**
* @Field("created")
*
* @var string datetime in the database
*/
#[Field("created")]
private string $createDate = '';

public function getUserId(): int
Expand Down Expand Up @@ -815,8 +836,8 @@ class GeoPoint

public function __construct(float $lat, float $lng)
{
$this->lat = lat;
$this->lng = lng;
$this->lat = $lat;
$this->lng = $lng;
}

public function getLatitude(): float
Expand All @@ -838,21 +859,16 @@ use Application\Value\GeoPoint;
use Squirrel\Entities\Annotation\Entity;
use Squirrel\Entities\Annotation\Field;

/**
* @Entity("users_locations")
*/
#[Entity("users_locations")]
class UserLocation
{
/**
* @Field("user_id")
*/
#[Field("user_id")]
private int $userId = 0;

/**
* @Field("location")
*
* @var string "point" in Postgres
*/
#[Field("location")]
private string $locationPoint = '';

public function getUserId(): int
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
"psalm_base": "vendor/bin/psalm --set-baseline=psalm-baseline.xml",
"phpunit": "vendor/bin/phpunit --colors=always",
"phpunit_clover": "vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml",
"coverage": "vendor/bin/phpunit --coverage-html tests/_reports",
"phpcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache=.phpcs-cache --colors src",
"phpcsfix": "vendor/bin/phpcbf --standard=ruleset.xml --extensions=php --cache=.phpcs-cache src",
"coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html tests/_reports",
"phpcs": "vendor/bin/phpcs --standard=ruleset.xml --extensions=php --cache=.phpcs-cache --ignore=src/Annotation/Entity.php,src/Annotation/Field.php --colors src",
"phpcsfix": "vendor/bin/phpcbf --standard=ruleset.xml --extensions=php --cache=.phpcs-cache --ignore=src/Annotation/Entity.php,src/Annotation/Field.php src",
"binupdate": "@composer bin all update --ansi",
"bininstall": "@composer bin all install --ansi"
}
Expand Down
20 changes: 20 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ parameters:
count: 1
path: src/Annotation/EntityProcessor.php

-
message: "#^Method Squirrel\\\\Entities\\\\Annotation\\\\EntityProcessor\\:\\:getEntityFromAttribute\\(\\) has parameter \\$class with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Annotation/EntityProcessor.php

-
message: "#^Method Squirrel\\\\Entities\\\\Annotation\\\\EntityProcessor\\:\\:getEntityFromAttribute\\(\\) should return Squirrel\\\\Entities\\\\Annotation\\\\Entity\\|null but returns object\\.$#"
count: 1
path: src/Annotation/EntityProcessor.php

-
message: "#^Method Squirrel\\\\Entities\\\\Annotation\\\\EntityProcessor\\:\\:getEntityFromAnnotation\\(\\) has parameter \\$class with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Annotation/EntityProcessor.php

-
message: "#^Method Squirrel\\\\Entities\\\\Annotation\\\\EntityProcessor\\:\\:getFieldFromAttribute\\(\\) should return Squirrel\\\\Entities\\\\Annotation\\\\Field\\|null but returns object\\.$#"
count: 1
path: src/Annotation/EntityProcessor.php

-
message: "#^Result of && is always false\\.$#"
count: 1
Expand Down
44 changes: 42 additions & 2 deletions src/Annotation/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,55 @@
* @Annotation
* @Target({"CLASS"})
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class Entity
{
/**
* @var string Name of the SQL table
*/
public string $name = '';
private string $name = '';

/**
* @var string Database connection - if empty the default connection is used
*/
public string $connection = '';
private string $connection = '';

/**
* @param string|array{value?: string, name?: string, connection?: string} $name
*/
public function __construct($name, string $connection = '')
{
// Doctrine annotations always provides an array as a first argument - this is for backwards compatibility
if (\is_array($name)) {
// First value is provided directly for the name
if (isset($name['value'])) {
$this->name = $name['value'];
}

// All values as "named parameters" from annotations
if (isset($name['name'])) {
$this->name = $name['name'];
}
if (isset($name['connection'])) {
$this->connection = $name['connection'];
}
} else {
$this->name = $name;
$this->connection = $connection;
}

if (\strlen($this->name) === 0) {
throw new \InvalidArgumentException('No name provided for entity');
}
}

public function getName(): string
{
return $this->name;
}

public function getConnection(): string
{
return $this->connection;
}
}
Loading

0 comments on commit f60c632

Please sign in to comment.