Skip to content

Commit

Permalink
Merge pull request #14 from byjg/5.0
Browse files Browse the repository at this point in the history
Implement PHP 8.1 with Breaking change features
  • Loading branch information
byjg authored Oct 29, 2024
2 parents 2bf9043 + ea80e23 commit 8d9a0c9
Show file tree
Hide file tree
Showing 86 changed files with 2,776 additions and 1,022 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ jobs:
strategy:
matrix:
php-version:
- "8.3"
- "8.2"
- "8.1"
- "8.0"
- "7.4"

steps:
- uses: actions/checkout@v4
- run: composer install
- run: ./vendor/bin/phpunit
- run: ./vendor/bin/psalm

Documentation:
if: github.ref == 'refs/heads/master'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ vendor
.idea/*
!.idea/runConfigurations
.phpunit.result.cache
phpunit.xml.dist.bak
6 changes: 6 additions & 0 deletions .idea/runConfigurations/PHPUnit.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 0 additions & 83 deletions .vscode/launch.json

This file was deleted.

92 changes: 91 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,97 @@ These are the key components:
* DbDriverIntarce is the implementation to the Database connection.
* Repository put all this together


## Getting Started

### Table Structure

We have the following table structure in the database for this example:

```sql
CREATE TABLE `mytable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`company_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

We want to be able to interact with this table using the ORM.

### Defining the Model

A Model in our context is a class that symbolizes the data you wish to store or fetch from the database.
This Model class can be as simple as a class with public properties.
Alternatively, it can be a class equipped with getter and setter methods for more controlled access and
manipulation of the data.

To map the database fields, you can add attributes to the Model class. Each property in the Model class represents a field in the database.

Let's look at an example:
```php
#[TableAttribute(tableName: 'mytable')]
class MyModel
{
#[FieldAttribute(primaryKey: true)]
public ?int $id;

#[FieldAttribute()]
public ?string $name;

#[FieldAttribute(fieldName: 'company_id')
public ?int $companyId;
}
```

In this example, we have a class `MyModel` with three properties: `id`, `name`, and `companyId`.

The `id` property is marked as a primary key. The `name` property is a simple field.
The `companyId` property is a field with a different name in the database `company_id`.

The `TableAttribute` is used to define the table name in the database.

### Connecting the repository

After defining the Model, you can connect the Model with the repository.

```php
$dbDriver = \ByJG\AnyDataset\Db\Factory::getDbRelationalInstance('mysql://user:password@server/schema');

$repository = new \ByJG\MicroOrm\Repository($dbDriver, MyModel::class);
```

### Querying the database

You can query the database using the repository.

```php
$myModel = $repository->get(1);
```

or

```php
$query = Query::getInstance()
->field('name')
->where('company_id = :cid', ['cid' => 1]);

$result = $repository->getByQuery($query);
```

or, the same example above:

```php
$filterModel = $repository->entity([
'company_id' => 1
]);

$query = $repository->queryInstance($filterModel);
$query->field('name');

$result = $repository->getByQuery($query);
```

## Basics

* [Defining the Model](docs/getting-started-model.md)
Expand All @@ -72,7 +163,6 @@ These are the key components:
* [Tables without auto increments fields](docs/tables-without-auto-increment-fields.md)
* [Using With Recursive SQL Command](docs/using-with-recursive-sql-command.md)


## Install

Just type:
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@
},
"autoload-dev": {
"psr-4": {
"Test\\": "tests/"
"Tests\\": "tests/"
}
},
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"php": ">=7.4",
"php": ">=8.1 <8.4",
"ext-json": "*",
"byjg/anydataset-db": "4.9.*"
"byjg/anydataset-db": "^5.0"
},
"require-dev": {
"phpunit/phpunit": "5.7.*|7.4.*|^9.6"
"phpunit/phpunit": "^9.6",
"vimeo/psalm": "^5.9"
},
"suggest": {
"ext-curl": "*",
Expand Down
126 changes: 126 additions & 0 deletions docs/model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# The Model Attributes

The Model Attributes are used to define the table structure in the database.

The attributes are:

* `TableAttribute`: Used in the class level. Define that the Model is referencing a table in the database.
* `FieldAttribute`: Define the properties in the class that are fields in the database.

## Example

```php
#[TableAttribute(tableName: 'mytable')]
class MyModel
{
#[FieldAttribute(primaryKey: true)]
public ?int $id;

#[FieldAttribute()]
public ?string $name;

#[FieldAttribute(fieldName: 'company_id')
public ?int $companyId;

#[FieldAttribute(fieldName: 'created_at')]
protected ?string $createdAt;

#[FieldAttribute(fieldName: 'updated_at')]
protected ?string $updatedAt;

public function getCreatedAt(): ?string
{
return $this->createdAt;
}

public function setCreatedAt(?string $createdAt): void
{
$this->createdAt = $createdAt;
}

public function getUpdatedAt(): ?string
{
return $this->updatedAt;
}

public function setUpdatedAt(?string $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
}
```

In this example, we have a class `MyModel` with five properties: `id`, `name`, `companyId`, `createdAt`, and `updatedAt`.

The `id` property is marked as a primary key. The `name` property is a simple field.
The `companyId` property is a field with a different name in the database `company_id`.
The same for `createdAt` and `updatedAt`. These properties are fields with a different name in the database `created_at` and `updated_at`.

The `TableAttribute` is used to define the table name in the database.

## Where to use FieldAttribute

The `FieldAttribute` can be used in the following properties:

* Public properties
* Protected properties
* Private properties

**Do not use the `FieldAttribute` in any _method_, _getter_ or _setter_.**

## Rules for the properties

* If the property has a type, then must be nullable. If the property is not nullable, you must set a default value.
* You can use mixed or not typed properties.
* If the property is protected or private, you must have a getter and setter for this property.

## Table Attributes parameters

The `TableAttribute` has the following parameters:

* `tableName`: The name of the table in the database.
* `primaryKeySeedFunction` (optional): A function that returns the seed for the primary key. The function must return a value.

## Field Attributes parameters

The `FieldAttribute` has the following parameters:

* primaryKey (optional): If the field is a primary key.
* fieldName (optional): The name of the field in the database. If not set, the field name is the same as the property name.
* fieldAlias (optional): The alias of the field in the database. If not set, the field alias is the same as the property name.
* syncWithDb (optional): If the field should be synchronized with the database. Default is true.
* updateFunction (optional): A function that is called when the field is updated. The function must return a value.
* selectFunction (optional): A function that is called when the field is selected. The function must return a value.

```tip
To use a function as a parameter, you must inherit from the `FieldAttribute` and
in the constructor call the parent with the function.
```

## Special Field Attributes: FieldReadOnlyAttribute

* It is used to define a field that is read-only.
* It sets the MapperClosure::readonly() method to the updateFunction.

## Closure Function Signature

### primaryKeySeedFunction:

```php
function (object $instance) {
// $instance is the instance of the model with the properties set
return mixed;
}
```

### selectFunction and updateFunction:

```php
function (mixed $fieldValue, mixed $data) {
// $value is the value to be set in the property
// $data is an array with the value properties set
return $fieldValue;
}
```


4 changes: 2 additions & 2 deletions docs/observers.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ An observer is a class will be called after an insert, update or delete record i
```mermaid
flowchart TD
A[MyRepository] --> |1. addObserver| B[Subject]
C[ObserverdRepository] --> |2. Notify Update| B
C[WatchedRepository] --> |2. Notify Update| B
B --> |3. Execute Callback| A
```

Expand All @@ -27,7 +27,7 @@ $myRepository->addObserver(new class($this->infoMapper->getTable()) implements O
// Do something here
}

public function getObserverdTable(): string
public function getObservedTable(): string
{
return $this->table;
}
Expand Down
Loading

0 comments on commit 8d9a0c9

Please sign in to comment.