diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9f64211..74cd16c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,26 +1,28 @@ name: Documentation - on: push: branches: [master] +permissions: + contents: write jobs: - publish: + deploy: runs-on: ubuntu-latest - name: 'Publish documentation' steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@v4 + - name: Configure Git Credentials + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + - uses: actions/setup-python@v5 with: - php-version: '8.0' - - name: Install halsey/journal - run: composer global require halsey/journal - - name: Generate - run: composer global exec 'journal generate' - - name: Push - uses: peaceiris/actions-gh-pages@v3 + python-version: 3.x + - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - uses: actions/cache@v4 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./.tmp_journal/ + key: mkdocs-material-${{ env.cache_id }} + path: .cache + restore-keys: | + mkdocs-material- + - run: pip install mkdocs-material + - run: mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore index 9d5cbb4..6c09361 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /vendor /.phpunit.result.cache /.phpunit.cache +/.cache diff --git a/.journal b/.journal deleted file mode 100644 index 233bb63..0000000 --- a/.journal +++ /dev/null @@ -1,74 +0,0 @@ -package('formal', 'access-layer', 'formal-php') - ->menu( - Entry::markdown( - 'Getting started', - Path::of('readme.md'), - ), - Entry::section( - 'Connections', - Entry::markdown( - 'PDO', - Path::of('connections/pdo.md'), - ), - Entry::markdown( - 'Lazy', - Path::of('connections/lazy.md'), - ), - Entry::markdown( - 'Logger', - Path::of('connections/logger.md'), - ), - Entry::markdown( - 'Create your own', - Path::of('connections/own.md'), - ), - ), - Entry::section( - 'Queries', - Entry::markdown( - 'SQL', - Path::of('queries/sql.md'), - ), - Entry::markdown( - 'Create table', - Path::of('queries/create_table.md'), - ), - Entry::markdown( - 'Drop table', - Path::of('queries/drop_table.md'), - ), - Entry::markdown( - 'Insert', - Path::of('queries/insert.md'), - ), - Entry::markdown( - 'Select', - Path::of('queries/select.md'), - ), - Entry::markdown( - 'Update', - Path::of('queries/update.md'), - ), - Entry::markdown( - 'Delete', - Path::of('queries/delete.md'), - ), - Entry::markdown( - 'Transactions', - Path::of('queries/transactions.md'), - ), - ), - ); -}; diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6b5c6f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +# This command is intended to be run on your computer +serve-doc: + docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material + +build-doc: + docker run --rm -it -v ${PWD}:/docs squidfunk/mkdocs-material build diff --git a/documentation/assets/favicon.png b/documentation/assets/favicon.png new file mode 100644 index 0000000..348566e Binary files /dev/null and b/documentation/assets/favicon.png differ diff --git a/documentation/assets/fonts/MonaspaceNeon-Regular.woff b/documentation/assets/fonts/MonaspaceNeon-Regular.woff new file mode 100644 index 0000000..ce0168b Binary files /dev/null and b/documentation/assets/fonts/MonaspaceNeon-Regular.woff differ diff --git a/documentation/assets/logo.svg b/documentation/assets/logo.svg new file mode 100644 index 0000000..8526fb4 --- /dev/null +++ b/documentation/assets/logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/assets/stylesheets/extra.css b/documentation/assets/stylesheets/extra.css new file mode 100644 index 0000000..e4aa2d4 --- /dev/null +++ b/documentation/assets/stylesheets/extra.css @@ -0,0 +1,113 @@ +@font-face { + font-family: "Monaspace Neon"; + font-weight: normal; + font-style: normal; + src: url("../fonts/MonaspaceNeon-Regular.woff"); +} + +:root { + --md-code-font: "Monaspace Neon"; +} + +:root { + --light-md-code-hl-number-color: #f76d47; + --light-md-code-hl-function-color: #6384b9; + --light-md-code-hl-operator-color: #39adb5; + --light-md-code-hl-constant-color: #7c4dff; + --light-md-code-hl-string-color: #9fc06f; + --light-md-code-hl-punctuation-color: #39adb5; + --light-md-code-hl-keyword-color: #7c4dff; + --light-md-code-hl-variable-color: #80cbc4; + --light-md-code-hl-comment-color: #ccd7da; + --light-md-code-bg-color: #fafafa; + --light-md-code-fg-color: #ffb62c; + --light-md-code-hl-variable-color: #6384b9; + --dark-md-code-hl-number-color: #f78c6c; + --dark-md-code-hl-function-color: #82aaff; + --dark-md-code-hl-operator-color: #89ddff; + --dark-md-code-hl-constant-color: #c792ea; + --dark-md-code-hl-string-color: #c3e88d; + --dark-md-code-hl-punctuation-color: #89ddff; + --dark-md-code-hl-keyword-color: #c792ea; + --dark-md-code-hl-variable-color: #e8f9f9; + --dark-md-code-hl-comment-color: #546e7a; + --dark-md-code-bg-color: #263238; + --dark-md-code-fg-color: #ffcb6b; + --dark-md-code-hl-variable-color: #82aaff; +} + +@media (prefers-color-scheme: light) { + .language-php > * { + --md-code-hl-number-color: var(--light-md-code-hl-number-color); + --md-code-hl-function-color: var(--light-md-code-hl-function-color); + --md-code-hl-operator-color: var(--light-md-code-hl-operator-color); + --md-code-hl-constant-color: var(--light-md-code-hl-constant-color); + --md-code-hl-string-color: var(--light-md-code-hl-string-color); + --md-code-hl-punctuation-color: var(--light-md-code-hl-punctuation-color); + --md-code-hl-keyword-color: var(--light-md-code-hl-keyword-color); + --md-code-hl-variable-color: var(--light-md-code-hl-variable-color); + --md-code-hl-comment-color: var(--light-md-code-hl-comment-color); + --md-code-bg-color: var(--light-md-code-bg-color); + --md-code-fg-color: var(--light-md-code-fg-color); + } + + .language-php .na { + --md-code-hl-variable-color: var(--light-md-code-hl-variable-color); + } +} + +[data-md-color-media="(prefers-color-scheme: light)"] .language-php > * { + --md-code-hl-number-color: var(--light-md-code-hl-number-color); + --md-code-hl-function-color: var(--light-md-code-hl-function-color); + --md-code-hl-operator-color: var(--light-md-code-hl-operator-color); + --md-code-hl-constant-color: var(--light-md-code-hl-constant-color); + --md-code-hl-string-color: var(--light-md-code-hl-string-color); + --md-code-hl-punctuation-color: var(--light-md-code-hl-punctuation-color); + --md-code-hl-keyword-color: var(--light-md-code-hl-keyword-color); + --md-code-hl-variable-color: var(--light-md-code-hl-variable-color); + --md-code-hl-comment-color: var(--light-md-code-hl-comment-color); + --md-code-bg-color: var(--light-md-code-bg-color); + --md-code-fg-color: var(--light-md-code-fg-color); +} + +[data-md-color-media="(prefers-color-scheme: light)"] .language-php .na { + --md-code-hl-variable-color: var(--light-md-code-hl-variable-color); +} + +@media (prefers-color-scheme: dark) { + .language-php > * { + --md-code-hl-number-color: var(--dark-md-code-hl-number-color); + --md-code-hl-function-color: var(--dark-md-code-hl-function-color); + --md-code-hl-operator-color: var(--dark-md-code-hl-operator-color); + --md-code-hl-constant-color: var(--dark-md-code-hl-constant-color); + --md-code-hl-string-color: var(--dark-md-code-hl-string-color); + --md-code-hl-punctuation-color: var(--dark-md-code-hl-punctuation-color); + --md-code-hl-keyword-color: var(--dark-md-code-hl-keyword-color); + --md-code-hl-variable-color: var(--dark-md-code-hl-variable-color); + --md-code-hl-comment-color: var(--dark-md-code-hl-comment-color); + --md-code-bg-color: var(--dark-md-code-bg-color); + --md-code-fg-color: var(--dark-md-code-fg-color); + } + + .language-php .na { + --md-code-hl-variable-color: var(--dark-md-code-hl-variable-color); + } +} + +[data-md-color-media="(prefers-color-scheme: dark)"] .language-php > * { + --md-code-hl-number-color: var(--dark-md-code-hl-number-color); + --md-code-hl-function-color: var(--dark-md-code-hl-function-color); + --md-code-hl-operator-color: var(--dark-md-code-hl-operator-color); + --md-code-hl-constant-color: var(--dark-md-code-hl-constant-color); + --md-code-hl-string-color: var(--dark-md-code-hl-string-color); + --md-code-hl-punctuation-color: var(--dark-md-code-hl-punctuation-color); + --md-code-hl-keyword-color: var(--dark-md-code-hl-keyword-color); + --md-code-hl-variable-color: var(--dark-md-code-hl-variable-color); + --md-code-hl-comment-color: var(--dark-md-code-hl-comment-color); + --md-code-bg-color: var(--dark-md-code-bg-color); + --md-code-fg-color: var(--dark-md-code-fg-color); +} + +[data-md-color-media="(prefers-color-scheme: dark)"] .language-php .na { + --md-code-hl-variable-color: var(--dark-md-code-hl-variable-color); +} diff --git a/documentation/connections/lazy.md b/documentation/connections/lazy.md index 9bf6df3..c03ec65 100644 --- a/documentation/connections/lazy.md +++ b/documentation/connections/lazy.md @@ -11,7 +11,11 @@ use Formal\AccessLayer\{ }; use Innmind\Url\Url; -$connection = new Lazy(static fn() => PDO::of(Url::of('mysql://user:pwd@127.0.0.1:3306/database_name'))); +$connection = new Lazy( + static fn() => PDO::of( + Url::of('mysql://user:pwd@127.0.0.1:3306/database_name'), + ), +); ``` By passing a callable to the constructor allows you to use [whatever implementation](own.md) of a `Connection` you wish to lazy load. diff --git a/documentation/connections/logger.md b/documentation/connections/logger.md index 40ca3e1..38f5825 100644 --- a/documentation/connections/logger.md +++ b/documentation/connections/logger.md @@ -15,8 +15,8 @@ $connection = Logger::psr( ); ``` -> [!NOTE] -> it doesn't log any information about the returned rows to prevent _unwrapping_ the deferred `Sequence` returned by [`PDO`](pdo.md). +!!! note "" + It doesn't log any information about the returned rows to prevent _unwrapping_ the deferred `Sequence` returned by [`PDO`](pdo.md). -> [!IMPORTANT] -> it won't log any errors for lazy queries since the query is not executed until the first call on the sequence. +!!! warning "" + It won't log any errors for lazy queries since the query is not executed until the first call on the sequence. diff --git a/documentation/connections/own.md b/documentation/connections/own.md index 8f92b01..4b4adbd 100644 --- a/documentation/connections/own.md +++ b/documentation/connections/own.md @@ -40,63 +40,30 @@ final class Sentry implements Connection An important part of extending the behaviour of the connection with your own logic is to not change the current behaviour that other code may rely upon. This library helps you make sure you don't break these behaviours by providing you properties. -Below is an example of a PHPUnit test case that you can extend to add your specific test cases: +Below is an example of running properties via [BlackBox](https://innmind.github.io/BlackBox/): ```php -use PHPUnit\Framework\TestCase; -use Innmind\BlackBox\PHPUnit\BlackBox; -use Properties\Formal\AccessLayer\Connection; - -class SentryTest extends TestCase -{ - use BlackBox; - - public function setUp(): void - { - Connection::seed($this->connection()); - } - - // you can add here test cases like in any other PHPUnit class - - /** - * @dataProvider properties - */ - public function testHoldProperty($property) - { - $this - ->forAll($property) - ->then(function($property) { - $connection = $this->connection(); - - if (!$property->applicableTo($connection)) { - $this->markTestSkipped(); - } - - $property->ensureHeldBy($connection); - }); - } - - public function testHoldProperties() - { - $this - ->forAll(Connection::properties()) - ->disableShrinking() - ->then(function($properties) { - $properties->ensureHeldBy($this->connection()); - }); - } - - public function properties(): iterable - { - foreach (Connection::list() as $property) { - yield [$property]; - } - } - - private function connection(): PDO - { - return new Sentry(/* add the arguments of your implementation here */); - } +use Innmind\BlackBox\Set; +use Properties\Formal\AccessLayer\Connection as Properties; + +$sentry = new Sentry(/* add the arguments of your implementation here */); +$connection = Set\Call::of(static function() use ($sentry) { + Properties::seed($sentry); + + return $sentry; +}); + +yield properties( + 'Sentry properties', + Properties::any(), + $connection, +); + +foreach (Properties::list() as $property) { + yield property( + $property, + $connection, + )->named('Sentry'); } ``` diff --git a/documentation/connections/pdo.md b/documentation/connections/pdo.md index bee256b..7a908e7 100644 --- a/documentation/connections/pdo.md +++ b/documentation/connections/pdo.md @@ -13,5 +13,5 @@ $connection = PDO::of(Url::of('mysql://user:pwd@127.0.0.1:3306/database_name?cha When executing a [query](../queries/sql.md) through this connection it will return a [deferred `Sequence`](https://innmind.github.io/Immutable/SEQUENCE.html#defer) of rows. This means that the rows returned from the database are only loaded once you iterate over the sequence. (Queries with the named constructor `::onDemand()` will return a lazy `Sequence`). -> [!IMPORTANT] -> as soon as you instanciate the class it will open a connection to the database, if you want to open it upon first query take a look at the [`Lazy` connection](lazy.md). +!!! note "" + As soon as you instanciate the class it will open a connection to the database, if you want to open it upon first query take a look at the [`Lazy` connection](lazy.md). diff --git a/documentation/readme.md b/documentation/index.md similarity index 50% rename from documentation/readme.md rename to documentation/index.md index c342998..067064c 100644 --- a/documentation/readme.md +++ b/documentation/index.md @@ -1,10 +1,17 @@ +--- +hide: + - navigation + - toc +--- + # Getting started This library is designed to eliminate state wherever possible when dealing with a database connection. -The result is an api can consist of only one method on the connection (`__invoke`) and one kind of argument (`Query`). Both can easily be extended through composition. +The result is an api that consist of only one method on the connection (`__invoke`) and one kind of argument (`Query`). Both can easily be extended through composition. -**Important**: you must use [`vimeo/psalm`](https://packagist.org/packages/vimeo/psalm) to make sure you use this library correctly. +!!! note "" + You must use [`vimeo/psalm`](https://packagist.org/packages/vimeo/psalm) to make sure you use this library correctly. ## Installation @@ -16,7 +23,6 @@ composer require formal/access-layer ```php use Formal\AccessLayer\{ - Connection\Lazy, Connection\PDO, Query\SQL, Row, @@ -24,7 +30,7 @@ use Formal\AccessLayer\{ use Innmind\Url\Url; use Innmind\Immutable\Sequence; -$connection = new Lazy(static fn() => PDO::of(Url::of('mysql://user:pwd@127.0.0.1:3306/database_name'))); +$connection = PDO::of(Url::of('mysql://user:pwd@127.0.0.1:3306/database_name')); $rows = $connection(SQL::of('SELECT * FROM `some_table`')); $rows; // instanceof Sequence diff --git a/documentation/queries/create_table.md b/documentation/queries/create_table.md index b67c0e8..e1f868a 100644 --- a/documentation/queries/create_table.md +++ b/documentation/queries/create_table.md @@ -84,5 +84,5 @@ $create = $create->foreignKey( $connection($create); ``` -> [!NOTE] -> this will name the foreign key `FK_user_id` so it's easier to reference it afterwards. +!!! note "" + This will name the foreign key `FK_user_id` so it's easier to reference it afterwards. diff --git a/documentation/queries/delete.md b/documentation/queries/delete.md index 495be32..544f405 100644 --- a/documentation/queries/delete.md +++ b/documentation/queries/delete.md @@ -60,5 +60,5 @@ $delete = Delete::from(new Name('users'))->where( $connection($delete); ``` -> [!NOTE] -> the property name can include the name of the table to match by using the format `'{table}.{column}'`. +!!! note "" + The property name can include the name of the table to match by using the format `'{table}.{column}'`. diff --git a/documentation/queries/select.md b/documentation/queries/select.md index 29ae381..c8c3787 100644 --- a/documentation/queries/select.md +++ b/documentation/queries/select.md @@ -12,8 +12,8 @@ $users = $connection($select); This will return all the content of the `users` table. -> [!NOTE] -> if you replace the constructor `::from()` by `::onDemand()` it will run your query lazily by returning a lazy `Sequence`, meaning it won't keep the results in memory allowing you to handle very large results. +!!! note "" + If you replace the constructor `::from()` by `::onDemand()` it will run your query lazily by returning a lazy `Sequence`, meaning it won't keep the results in memory allowing you to handle very large results. ## Specifying columns to return @@ -80,5 +80,7 @@ $select = Select::from(new Name('users'))->where( $users = $connection($select); ``` -> [!NOTE] -> the property name can include the name of the table to match by using the format `'{table}.{column}'`. The value of the specification can also be a query (this will translated to a sub query). +!!! note "" + The property name can include the name of the table to match by using the format `'{table}.{column}'`. + + The value of the specification can also be a query (this will translated to a sub query). diff --git a/documentation/queries/sql.md b/documentation/queries/sql.md index 0543b6d..9990efb 100644 --- a/documentation/queries/sql.md +++ b/documentation/queries/sql.md @@ -18,15 +18,15 @@ $tables->foreach(function(Row $row): void { }); ``` -> [!NOTE] -> if you replace the constructor `::of()` by `::onDemand()` it will run your query lazily by returning a lazy `Sequence`, meaning it won't keep the results in memory allowing you to handle very large results. This is particularly useful for `SELECT` queries. +!!! note "" + If you replace the constructor `::of()` by `::onDemand()` it will run your query lazily by returning a lazy `Sequence`, meaning it won't keep the results in memory allowing you to handle very large results. This is particularly useful for `SELECT` queries. ## Parameters For some queries you will need to specify parameters to provide values, you can bind them either by specifying their name or by an index -> [!IMPORTANT] -> do not copy the values directly in the sql query as you'll be vulnerable to sql injection. +!!! warning "" + Do not copy the values directly in the sql query as you'll be vulnerable to sql injection. ### Bound by name @@ -54,5 +54,5 @@ $insert = $insert $connection($insert); ``` -> [!NOTE] -> traditionally the index value rely on the user (you) to be specified (see [`PDOStatement::bindValue`](https://www.php.net/manual/en/pdostatement.bindvalue.php)), but this increase the probability for you to make an error. This problem is resolved here as the order in which the parameters are provided is always respected, this allows the connection to correctly provide the index to `\PDO`. +!!! note "" + Traditionally the index value rely on the user (you) to be specified (see [`PDOStatement::bindValue`](https://www.php.net/manual/en/pdostatement.bindvalue.php)), but this increase the probability for you to make an error. This problem is resolved here as the order in which the parameters are provided is always respected, this allows the connection to correctly provide the index to `\PDO`. diff --git a/documentation/queries/update.md b/documentation/queries/update.md index a812437..47cce9f 100644 --- a/documentation/queries/update.md +++ b/documentation/queries/update.md @@ -73,5 +73,5 @@ $update = $update->where( $connection($update); ``` -> [!NOTE] -> the property name can include the name of the table to match by using the format `'{table}.{column}'`. +!!! note "" + The property name can include the name of the table to match by using the format `'{table}.{column}'`. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..8d4ce8d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,105 @@ +site_name: formal/access-layer +repo_name: formal/access-layer +docs_dir: documentation/ + +nav: + - Home: index.md + - Connections: + - PDO: connections/pdo.md + - Lazy: connections/lazy.md + - Logger: connections/logger.md + - Create your own: connections/own.md + - Queries: + - SQL: queries/sql.md + - Create table: queries/create_table.md + - Drop table: queries/drop_table.md + - Insert: queries/insert.md + - Select: queries/select.md + - Update: queries/update.md + - Delete: queries/delete.md + - Transactions: queries/transactions.md + +theme: + name: material + logo: assets/logo.svg + favicon: assets/favicon.png + font: false + features: + - content.code.copy + - content.code.annotate + - navigation.tracking + - navigation.tabs + - navigation.tabs.sticky + - navigation.sections + - navigation.expand + - navigation.indexes + - navigation.top + - navigation.footer + - search.suggest + - search.highlight + - content.action.edit + palette: + # Palette toggle for automatic mode + - media: "(prefers-color-scheme)" + toggle: + icon: material/brightness-auto + name: Switch to light mode + primary: blue + accent: deep orange + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + primary: blue + accent: deep orange + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to system preference + primary: blue + accent: deep orange + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + extend_pygments_lang: + - name: php + lang: php + options: + startinline: true + - pymdownx.inlinehilite + - pymdownx.snippets + - attr_list + - md_in_html + - pymdownx.superfences + - abbr + - admonition + - pymdownx.details: + - pymdownx.tabbed: + alternate_style: true + - toc: + permalink: true + - footnotes + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + +extra_css: + - assets/stylesheets/extra.css + +plugins: + - search + - privacy + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/formal-php + - icon: fontawesome/brands/x-twitter + link: https://twitter.com/Baptouuuu