diff --git a/assets/controllers/timer_controller.js b/assets/controllers/timer_controller.js new file mode 100644 index 0000000..fc88ee3 --- /dev/null +++ b/assets/controllers/timer_controller.js @@ -0,0 +1,151 @@ +import { Controller } from '@hotwired/stimulus'; +import { useDebounce } from 'stimulus-use'; +import axios from 'axios'; +import { DateTime, Duration } from 'luxon'; + +/* stimulusFetch: 'lazy */ +export default class extends Controller { + #intervalId; + #startIcon; + #stopIcon; + + static debounces = ['runTimer', 'startTimer', 'stopTimer'] + + static values = { + timerId: String, + timerRunning: Boolean, + timerStartTime: Number, + timerAccumulatedTime: Number, + } + + static targets = [ + 'timerDurationCounter', + 'timerStartButton', + 'timerStopButton', + ] + + connect() { + useDebounce(this); + + this.setButtonVisibility(); + this.#startIcon = this.timerStartButtonTarget.innerHTML; + this.#stopIcon = this.timerStopButtonTarget.innerHTML; + + if (this.timerRunningValue) { + this.initTimer(); + } + } + + setButtonVisibility() { + if (this.timerRunningValue) { + this.timerStartButtonTarget.classList.toggle('hidden', true); + this.timerStopButtonTarget.classList.toggle('hidden', false); + + return; + } + + this.timerStartButtonTarget.classList.toggle('hidden', false); + this.timerStopButtonTarget.classList.toggle('hidden', true); + } + + // Called when page is first loaded to start any timers that are already running. + initTimer() { + let startedAt = DateTime.fromSeconds(this.timerStartTimeValue); + + // Negate the diff, otherwise we'll get a negative int. + let diff = startedAt.diffNow(['seconds']).negate(); + + this.runTimer(diff); + } + + // Called when starting a timer AFTER the initial page load + runTimer(diff) { + // let totalTime = Duration.fromObject({seconds: this.timerAccumulatedTimeValue}); + let totalTime = diff.plus({seconds: this.timerAccumulatedTimeValue}); + + this.#intervalId = setInterval(() => { + totalTime = totalTime.plus({seconds: 1}); + + this.timerDurationCounterTarget.innerHTML = totalTime.toFormat('h:mm:ss'); + }, 1000); + } + + startTimer() { + this.timerStartButtonTarget.innerHTML = '~'; + + this.restartTimer(); + + let diff = Duration.fromObject({seconds: 0}) + + this.runTimer(diff); + } + + stopTimer() { + this.timerStopButtonTarget.innerHTML = '~'; + + clearInterval(this.#intervalId); + + this.timerRunningValue = false; + + this.persistTimer(); + } + + async restartTimer() { + let response = await axios + .post(`/timer/start/${this.timerIdValue}`) + .then((response) => { + return response.data; + }) + .catch(function (error) { + console.log(error); + + return false; + }) + ; + + if (response === false) { + // @todo do something + this.timerStartButtonTarget.innerHTML = 'Oops'; + + clearInterval(this.#intervalId); + + return; + } + + this.timerAccumulatedTimeValue = response.accumulatedSeconds; + this.timerStartTimeValue = response.restartedAt; + + this.timerStartButtonTarget.classList.toggle('hidden', true); + this.timerStopButtonTarget.classList.toggle('hidden', false); + this.timerStartButtonTarget.innerHTML = this.#startIcon; + } + + async persistTimer() { + let response = await axios + .post(`/timer/pause/${this.timerIdValue}`) + .then((response) => { + return response.data.accumulatedSeconds; + }) + .catch(function (error) { + console.log(error); + + return false; + }) + ; + + if (response === false) { + // @todo do something + this.timerStopButtonTarget.innerHTML = 'Oops'; + + this.runTimer(); + + return; + } + + this.timerAccumulatedTimeValue = response; + + this.timerStartButtonTarget.classList.toggle('hidden', false); + this.timerStopButtonTarget.classList.toggle('hidden', true); + this.timerStopButtonTarget.innerHTML = this.#stopIcon; + } +} \ No newline at end of file diff --git a/assets/controllers/timer_dashboard_controller.js b/assets/controllers/timer_dashboard_controller.js new file mode 100644 index 0000000..879403a --- /dev/null +++ b/assets/controllers/timer_dashboard_controller.js @@ -0,0 +1,44 @@ +import { Controller } from '@hotwired/stimulus'; +import axios from 'axios'; + +/* stimulusFetch: 'lazy */ +export default class extends Controller { + static values = { + // todoListId: String, + } + + static targets = [ + 'timerList', + ] + + async startTimer() { + let response = await axios + .post('/timer/create') + .then((response) => { + if (response.status !== 200) { + // @TODO Show an alert of something... + + return false; + } + + return response.data; + }) + ; + + if (response === false) { + // @TODO Show an alert of something... + + console.log('Ooops, something went wrong....'); + + return; + } + + // console.log(response.html.content); + + const div = document.createElement('div'); + div.classList.add('row'); + div.innerHTML = response.html.content; + + this.timerListTarget.prepend(div); + } +} \ No newline at end of file diff --git a/assets/styles/app.css b/assets/styles/app.css index 5a4260f..2a18183 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -1,2 +1,6 @@ :root { } + +.hidden { + display: none; +} \ No newline at end of file diff --git a/composer.json b/composer.json index 93d07a5..a8519dd 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.0", "league/commonmark": "^2.4", + "nesbot/carbon": "^3.1", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.25", "rushlow-development/serialize-type-bundle": "dev-main", @@ -44,6 +45,7 @@ "symfony/twig-bundle": "7.0.*", "symfony/uid": "7.0.*", "symfony/ux-turbo": "^2.14", + "symfony/ux-twig-component": "^2.16", "symfony/validator": "7.0.*", "symfony/web-link": "7.0.*", "symfony/yaml": "7.0.*", diff --git a/composer.lock b/composer.lock index 802c205..e049b07 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,77 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a366a039ed3c9e573c6a7e4891f49fba", + "content-hash": "0bb23cab6cebb24ed97e53bd0e14d3e1", "packages": [ + { + "name": "carbonphp/carbon-doctrine-types", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "conflict": { + "doctrine/dbal": "<4.0.0 || >=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, { "name": "composer/semver", "version": "3.4.0", @@ -257,16 +326,16 @@ }, { "name": "doctrine/collections", - "version": "2.1.4", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "72328a11443a0de79967104ad36ba7b30bded134" + "reference": "420480fc085bc65f3c956af13abe8e7546f94813" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/72328a11443a0de79967104ad36ba7b30bded134", - "reference": "72328a11443a0de79967104ad36ba7b30bded134", + "url": "https://api.github.com/repos/doctrine/collections/zipball/420480fc085bc65f3c956af13abe8e7546f94813", + "reference": "420480fc085bc65f3c956af13abe8e7546f94813", "shasum": "" }, "require": { @@ -278,7 +347,7 @@ "ext-json": "*", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^10.5", "vimeo/psalm": "^5.11" }, "type": "library", @@ -323,7 +392,7 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.1.4" + "source": "https://github.com/doctrine/collections/tree/2.2.1" }, "funding": [ { @@ -339,20 +408,20 @@ "type": "tidelift" } ], - "time": "2023-10-03T09:22:33+00:00" + "time": "2024-03-05T22:28:45+00:00" }, { "name": "doctrine/dbal", - "version": "4.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "53df8c432978b716a805143eb701436d54ec705e" + "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/53df8c432978b716a805143eb701436d54ec705e", - "reference": "53df8c432978b716a805143eb701436d54ec705e", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9e588fe1f38a443cb17de6b86b803d9e028e2156", + "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156", "shasum": "" }, "require": { @@ -365,16 +434,16 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.2", - "phpstan/phpstan": "1.10.57", + "phpstan/phpstan": "1.10.58", "phpstan/phpstan-phpunit": "1.3.15", "phpstan/phpstan-strict-rules": "^1.5", "phpunit/phpunit": "10.5.9", "psalm/plugin-phpunit": "0.18.4", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.8.1", + "squizlabs/php_codesniffer": "3.9.0", "symfony/cache": "^6.3.8|^7.0", "symfony/console": "^5.4|^6.3|^7.0", - "vimeo/psalm": "5.16.0" + "vimeo/psalm": "5.21.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -431,7 +500,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.0.0" + "source": "https://github.com/doctrine/dbal/tree/4.0.1" }, "funding": [ { @@ -447,7 +516,7 @@ "type": "tidelift" } ], - "time": "2024-02-03T19:11:19+00:00" + "time": "2024-03-03T15:59:11+00:00" }, { "name": "doctrine/deprecations", @@ -498,16 +567,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.11.3", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "492725310ae9a1b5b20d6ae09fb5ae6404616e68" + "reference": "5418e811a14724068e95e0ba43353b903ada530f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/492725310ae9a1b5b20d6ae09fb5ae6404616e68", - "reference": "492725310ae9a1b5b20d6ae09fb5ae6404616e68", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/5418e811a14724068e95e0ba43353b903ada530f", + "reference": "5418e811a14724068e95e0ba43353b903ada530f", "shasum": "" }, "require": { @@ -545,6 +614,7 @@ "symfony/property-info": "^5.4 || ^6.0 || ^7.0", "symfony/proxy-manager-bridge": "^5.4 || ^6.0 || ^7.0", "symfony/security-bundle": "^5.4 || ^6.0 || ^7.0", + "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", "symfony/string": "^5.4 || ^6.0 || ^7.0", "symfony/twig-bridge": "^5.4 || ^6.0 || ^7.0", "symfony/validator": "^5.4 || ^6.0 || ^7.0", @@ -562,7 +632,7 @@ "type": "symfony-bundle", "autoload": { "psr-4": { - "Doctrine\\Bundle\\DoctrineBundle\\": "" + "Doctrine\\Bundle\\DoctrineBundle\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -597,7 +667,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.11.3" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.12.0" }, "funding": [ { @@ -613,7 +683,7 @@ "type": "tidelift" } ], - "time": "2024-02-10T20:56:20+00:00" + "time": "2024-03-19T07:20:37+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -1037,16 +1107,16 @@ }, { "name": "doctrine/migrations", - "version": "3.7.2", + "version": "3.7.4", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "47af29eef49f29ebee545947e8b2a4b3be318c8a" + "reference": "954e0a314c2f0eb9fb418210445111747de254a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/47af29eef49f29ebee545947e8b2a4b3be318c8a", - "reference": "47af29eef49f29ebee545947e8b2a4b3be318c8a", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/954e0a314c2f0eb9fb418210445111747de254a6", + "reference": "954e0a314c2f0eb9fb418210445111747de254a6", "shasum": "" }, "require": { @@ -1119,7 +1189,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.7.2" + "source": "https://github.com/doctrine/migrations/tree/3.7.4" }, "funding": [ { @@ -1135,32 +1205,32 @@ "type": "tidelift" } ], - "time": "2023-12-05T11:35:05+00:00" + "time": "2024-03-06T13:41:11+00:00" }, { "name": "doctrine/orm", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "2a250b5814de192a23438c0a43e15da7e77890a7" + "reference": "716fc97b70cf8116f74eaa0588eef51420874bf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/2a250b5814de192a23438c0a43e15da7e77890a7", - "reference": "2a250b5814de192a23438c0a43e15da7e77890a7", + "url": "https://api.github.com/repos/doctrine/orm/zipball/716fc97b70cf8116f74eaa0588eef51420874bf9", + "reference": "716fc97b70cf8116f74eaa0588eef51420874bf9", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/collections": "^2.1", + "doctrine/collections": "^2.2", "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", "doctrine/lexer": "^3", - "doctrine/persistence": "^3.1.1", + "doctrine/persistence": "^3.3.1", "ext-ctype": "*", "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", @@ -1170,12 +1240,12 @@ "require-dev": { "doctrine/coding-standard": "^12.0", "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "1.10.35", + "phpstan/phpstan": "1.10.59", "phpunit/phpunit": "^10.4.0", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^5.4 || ^6.2 || ^7.0", - "vimeo/psalm": "5.16.0" + "vimeo/psalm": "5.22.2" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -1221,22 +1291,22 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.0.1" + "source": "https://github.com/doctrine/orm/tree/3.1.0" }, - "time": "2024-02-22T12:23:53+00:00" + "time": "2024-03-03T17:45:20+00:00" }, { "name": "doctrine/persistence", - "version": "3.2.0", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "63fee8c33bef740db6730eb2a750cd3da6495603" + "reference": "477da35bd0255e032826f440b94b3e37f2d56f42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/63fee8c33bef740db6730eb2a750cd3da6495603", - "reference": "63fee8c33bef740db6730eb2a750cd3da6495603", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/477da35bd0255e032826f440b94b3e37f2d56f42", + "reference": "477da35bd0255e032826f440b94b3e37f2d56f42", "shasum": "" }, "require": { @@ -1305,7 +1375,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.2.0" + "source": "https://github.com/doctrine/persistence/tree/3.3.2" }, "funding": [ { @@ -1321,7 +1391,7 @@ "type": "tidelift" } ], - "time": "2023-05-17T18:32:04+00:00" + "time": "2024-03-12T14:54:36+00:00" }, { "name": "doctrine/sql-formatter", @@ -1731,6 +1801,112 @@ ], "time": "2023-10-27T15:32:31+00:00" }, + { + "name": "nesbot/carbon", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2", + "reference": "34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "*", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.18.0", + "kylekatarnls/multi-tester": "^2.2.0", + "ondrejmirtes/better-reflection": "^6.11.0.0", + "phpmd/phpmd": "^2.13.0", + "phpstan/extension-installer": "^1.3.0", + "phpstan/phpstan": "^1.10.20", + "phpunit/phpunit": "^10.2.2", + "squizlabs/php_codesniffer": "^3.7.2" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2024-03-13T12:42:37+00:00" + }, { "name": "nette/schema", "version": "v1.3.0", @@ -2526,16 +2702,16 @@ }, { "name": "symfony/asset-mapper", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/asset-mapper.git", - "reference": "537b9575df2f0a809abe9dd1117bb4ec578f7a21" + "reference": "07133d369eb9f644985584d0877d294c8847a4f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/537b9575df2f0a809abe9dd1117bb4ec578f7a21", - "reference": "537b9575df2f0a809abe9dd1117bb4ec578f7a21", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/07133d369eb9f644985584d0877d294c8847a4f0", + "reference": "07133d369eb9f644985584d0877d294c8847a4f0", "shasum": "" }, "require": { @@ -2584,7 +2760,7 @@ "description": "Maps directories of assets & makes them available in a public directory with versioned filenames.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset-mapper/tree/v7.0.3" + "source": "https://github.com/symfony/asset-mapper/tree/v7.0.5" }, "funding": [ { @@ -2600,20 +2776,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T19:26:06+00:00" + "time": "2024-03-04T12:47:58+00:00" }, { "name": "symfony/cache", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "2207eceb2433d74df81232d97439bf508cb9e050" + "reference": "fc822951dd360a593224bb2cef90a087d0dff60f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/2207eceb2433d74df81232d97439bf508cb9e050", - "reference": "2207eceb2433d74df81232d97439bf508cb9e050", + "url": "https://api.github.com/repos/symfony/cache/zipball/fc822951dd360a593224bb2cef90a087d0dff60f", + "reference": "fc822951dd360a593224bb2cef90a087d0dff60f", "shasum": "" }, "require": { @@ -2680,7 +2856,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.0.3" + "source": "https://github.com/symfony/cache/tree/v7.0.4" }, "funding": [ { @@ -2696,7 +2872,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/cache-contracts", @@ -2776,16 +2952,16 @@ }, { "name": "symfony/clock", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "1c680e565dc0044d8ed3baeb57835fcacd9c6aed" + "reference": "8b9d08887353d627d5f6c3bf3373b398b49051c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/1c680e565dc0044d8ed3baeb57835fcacd9c6aed", - "reference": "1c680e565dc0044d8ed3baeb57835fcacd9c6aed", + "url": "https://api.github.com/repos/symfony/clock/zipball/8b9d08887353d627d5f6c3bf3373b398b49051c2", + "reference": "8b9d08887353d627d5f6c3bf3373b398b49051c2", "shasum": "" }, "require": { @@ -2830,7 +3006,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.0.3" + "source": "https://github.com/symfony/clock/tree/v7.0.5" }, "funding": [ { @@ -2846,20 +3022,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-03-02T12:46:12+00:00" }, { "name": "symfony/config", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16" + "reference": "44deeba7233f08f383185ffa37dace3b3bc87364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16", - "reference": "86a5027869ca3d6bdecae6d5d6c2f77c8f2c1d16", + "url": "https://api.github.com/repos/symfony/config/zipball/44deeba7233f08f383185ffa37dace3b3bc87364", + "reference": "44deeba7233f08f383185ffa37dace3b3bc87364", "shasum": "" }, "require": { @@ -2905,7 +3081,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.0.3" + "source": "https://github.com/symfony/config/tree/v7.0.4" }, "funding": [ { @@ -2921,20 +3097,20 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:34:29+00:00" + "time": "2024-02-26T07:52:39+00:00" }, { "name": "symfony/console", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c5010d50f1ee4b25cfa0201d9915cf1b14071456" + "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c5010d50f1ee4b25cfa0201d9915cf1b14071456", - "reference": "c5010d50f1ee4b25cfa0201d9915cf1b14071456", + "url": "https://api.github.com/repos/symfony/console/zipball/6b099f3306f7c9c2d2786ed736d0026b2903205f", + "reference": "6b099f3306f7c9c2d2786ed736d0026b2903205f", "shasum": "" }, "require": { @@ -2998,7 +3174,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.3" + "source": "https://github.com/symfony/console/tree/v7.0.4" }, "funding": [ { @@ -3014,20 +3190,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e915c6684b8e3ae90a4441f6823ebbb40edf0b92" + "reference": "47f37af245df8457ea63409fc242b3cc825ce5eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e915c6684b8e3ae90a4441f6823ebbb40edf0b92", - "reference": "e915c6684b8e3ae90a4441f6823ebbb40edf0b92", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/47f37af245df8457ea63409fc242b3cc825ce5eb", + "reference": "47f37af245df8457ea63409fc242b3cc825ce5eb", "shasum": "" }, "require": { @@ -3078,7 +3254,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.0.3" + "source": "https://github.com/symfony/dependency-injection/tree/v7.0.4" }, "funding": [ { @@ -3094,7 +3270,7 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:34:29+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3165,16 +3341,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "fbea8d2b5f5c6cf0a2aab882571a047ee9238cb4" + "reference": "e3cf34996df541c62acc1bd5f187aacc18a204d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/fbea8d2b5f5c6cf0a2aab882571a047ee9238cb4", - "reference": "fbea8d2b5f5c6cf0a2aab882571a047ee9238cb4", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/e3cf34996df541c62acc1bd5f187aacc18a204d2", + "reference": "e3cf34996df541c62acc1bd5f187aacc18a204d2", "shasum": "" }, "require": { @@ -3251,7 +3427,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.0.3" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.0.5" }, "funding": [ { @@ -3267,20 +3443,20 @@ "type": "tidelift" } ], - "time": "2024-01-30T13:55:15+00:00" + "time": "2024-02-27T12:34:35+00:00" }, { "name": "symfony/doctrine-messenger", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-messenger.git", - "reference": "2e31535147212328570717d091e082326963d40e" + "reference": "5a9ebba1b0be17af7b1e6b6433ad2cb6e35e97ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/2e31535147212328570717d091e082326963d40e", - "reference": "2e31535147212328570717d091e082326963d40e", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/5a9ebba1b0be17af7b1e6b6433ad2cb6e35e97ca", + "reference": "5a9ebba1b0be17af7b1e6b6433ad2cb6e35e97ca", "shasum": "" }, "require": { @@ -3323,7 +3499,7 @@ "description": "Symfony Doctrine Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-messenger/tree/v7.0.3" + "source": "https://github.com/symfony/doctrine-messenger/tree/v7.0.4" }, "funding": [ { @@ -3339,20 +3515,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/dotenv", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "4c69bf8ff41bd959050033eccb28ebe4b5c9b012" + "reference": "8017ea2f0ff4fbda6ae1bf3f5409d5ecff982067" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/4c69bf8ff41bd959050033eccb28ebe4b5c9b012", - "reference": "4c69bf8ff41bd959050033eccb28ebe4b5c9b012", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/8017ea2f0ff4fbda6ae1bf3f5409d5ecff982067", + "reference": "8017ea2f0ff4fbda6ae1bf3f5409d5ecff982067", "shasum": "" }, "require": { @@ -3397,7 +3573,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v7.0.3" + "source": "https://github.com/symfony/dotenv/tree/v7.0.4" }, "funding": [ { @@ -3413,20 +3589,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-09T10:53:15+00:00" }, { "name": "symfony/error-handler", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "9441608b79577176b6d8e44012cc3d20b4b45242" + "reference": "677b24759decff69e65b1e9d1471d90f95ced880" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/9441608b79577176b6d8e44012cc3d20b4b45242", - "reference": "9441608b79577176b6d8e44012cc3d20b4b45242", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/677b24759decff69e65b1e9d1471d90f95ced880", + "reference": "677b24759decff69e65b1e9d1471d90f95ced880", "shasum": "" }, "require": { @@ -3472,7 +3648,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.0.3" + "source": "https://github.com/symfony/error-handler/tree/v7.0.4" }, "funding": [ { @@ -3488,7 +3664,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/event-dispatcher", @@ -3838,16 +4014,16 @@ }, { "name": "symfony/flex", - "version": "v2.4.4", + "version": "v2.4.5", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "bec213c39511eda66663baa2ee7440c65f89c695" + "reference": "b0a405f40614c9f584b489d54f91091817b0e26e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/bec213c39511eda66663baa2ee7440c65f89c695", - "reference": "bec213c39511eda66663baa2ee7440c65f89c695", + "url": "https://api.github.com/repos/symfony/flex/zipball/b0a405f40614c9f584b489d54f91091817b0e26e", + "reference": "b0a405f40614c9f584b489d54f91091817b0e26e", "shasum": "" }, "require": { @@ -3883,7 +4059,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v2.4.4" + "source": "https://github.com/symfony/flex/tree/v2.4.5" }, "funding": [ { @@ -3899,20 +4075,20 @@ "type": "tidelift" } ], - "time": "2024-02-05T18:04:53+00:00" + "time": "2024-03-02T08:16:47+00:00" }, { "name": "symfony/form", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "76bfa17bf31d86bb00938725f276a84e697491b9" + "reference": "5cfe85c74caf924c7cec2134e169320b464ede84" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/76bfa17bf31d86bb00938725f276a84e697491b9", - "reference": "76bfa17bf31d86bb00938725f276a84e697491b9", + "url": "https://api.github.com/repos/symfony/form/zipball/5cfe85c74caf924c7cec2134e169320b464ede84", + "reference": "5cfe85c74caf924c7cec2134e169320b464ede84", "shasum": "" }, "require": { @@ -3979,7 +4155,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.0.3" + "source": "https://github.com/symfony/form/tree/v7.0.4" }, "funding": [ { @@ -3995,20 +4171,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-12T11:15:03+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "3584457e3dbea9d6d43726e52c18672489669ff5" + "reference": "b58bcb2f9c32405b8fbaa24a1e38c8a10bad7b21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3584457e3dbea9d6d43726e52c18672489669ff5", - "reference": "3584457e3dbea9d6d43726e52c18672489669ff5", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/b58bcb2f9c32405b8fbaa24a1e38c8a10bad7b21", + "reference": "b58bcb2f9c32405b8fbaa24a1e38c8a10bad7b21", "shasum": "" }, "require": { @@ -4046,7 +4222,7 @@ "symfony/mime": "<6.4", "symfony/property-access": "<6.4", "symfony/property-info": "<6.4", - "symfony/scheduler": "<6.4.3|>=7.0.0,<7.0.3", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", "symfony/security-core": "<6.4", "symfony/security-csrf": "<6.4", "symfony/serializer": "<6.4", @@ -4084,7 +4260,7 @@ "symfony/process": "^6.4|^7.0", "symfony/property-info": "^6.4|^7.0", "symfony/rate-limiter": "^6.4|^7.0", - "symfony/scheduler": "^6.4.3|^7.0.3", + "symfony/scheduler": "^6.4.4|^7.0.4", "symfony/security-bundle": "^6.4|^7.0", "symfony/semaphore": "^6.4|^7.0", "symfony/serializer": "^6.4|^7.0", @@ -4125,7 +4301,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v7.0.3" + "source": "https://github.com/symfony/framework-bundle/tree/v7.0.4" }, "funding": [ { @@ -4141,20 +4317,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-26T07:52:39+00:00" }, { "name": "symfony/http-client", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "3d2605c07cd14aec294f72f5bf8147702f7a5ada" + "reference": "425f462a59d8030703ee04a9e1c666575ed5db3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/3d2605c07cd14aec294f72f5bf8147702f7a5ada", - "reference": "3d2605c07cd14aec294f72f5bf8147702f7a5ada", + "url": "https://api.github.com/repos/symfony/http-client/zipball/425f462a59d8030703ee04a9e1c666575ed5db3b", + "reference": "425f462a59d8030703ee04a9e1c666575ed5db3b", "shasum": "" }, "require": { @@ -4217,7 +4393,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.0.3" + "source": "https://github.com/symfony/http-client/tree/v7.0.5" }, "funding": [ { @@ -4233,7 +4409,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-03-02T12:46:12+00:00" }, { "name": "symfony/http-client-contracts", @@ -4315,16 +4491,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f24e2568376e98978022fd09ce45e2dd049e67c8" + "reference": "439fdfdd344943254b1ef6278613e79040548045" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f24e2568376e98978022fd09ce45e2dd049e67c8", - "reference": "f24e2568376e98978022fd09ce45e2dd049e67c8", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/439fdfdd344943254b1ef6278613e79040548045", + "reference": "439fdfdd344943254b1ef6278613e79040548045", "shasum": "" }, "require": { @@ -4372,7 +4548,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.0.3" + "source": "https://github.com/symfony/http-foundation/tree/v7.0.4" }, "funding": [ { @@ -4388,20 +4564,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-08T19:22:56+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "6352029d6667e8ac5b54aae95afe10b2706b31ac" + "reference": "37c24ca28f65e3121a68f3dd4daeb36fb1fa2a72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6352029d6667e8ac5b54aae95afe10b2706b31ac", - "reference": "6352029d6667e8ac5b54aae95afe10b2706b31ac", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/37c24ca28f65e3121a68f3dd4daeb36fb1fa2a72", + "reference": "37c24ca28f65e3121a68f3dd4daeb36fb1fa2a72", "shasum": "" }, "require": { @@ -4449,7 +4625,7 @@ "symfony/process": "^6.4|^7.0", "symfony/property-access": "^6.4|^7.0", "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/serializer": "^6.4.4|^7.0.4", "symfony/stopwatch": "^6.4|^7.0", "symfony/translation": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3", @@ -4484,7 +4660,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.0.3" + "source": "https://github.com/symfony/http-kernel/tree/v7.0.5" }, "funding": [ { @@ -4500,7 +4676,7 @@ "type": "tidelift" } ], - "time": "2024-01-31T07:32:56+00:00" + "time": "2024-03-04T21:05:24+00:00" }, { "name": "symfony/intl", @@ -4586,16 +4762,16 @@ }, { "name": "symfony/mailer", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "2f71c0f6d62d28784783fdc5477e19dd57065d78" + "reference": "72e16d87bf50a3ce195b9470c06bb9d7b816ea85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/2f71c0f6d62d28784783fdc5477e19dd57065d78", - "reference": "2f71c0f6d62d28784783fdc5477e19dd57065d78", + "url": "https://api.github.com/repos/symfony/mailer/zipball/72e16d87bf50a3ce195b9470c06bb9d7b816ea85", + "reference": "72e16d87bf50a3ce195b9470c06bb9d7b816ea85", "shasum": "" }, "require": { @@ -4646,7 +4822,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.0.3" + "source": "https://github.com/symfony/mailer/tree/v7.0.4" }, "funding": [ { @@ -4662,20 +4838,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-03T21:34:19+00:00" }, { "name": "symfony/messenger", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "6271373f5dd4cc1750eccb73839d20797bd66072" + "reference": "804a8997f93313a8f7ed19e8cca3b44fdd18bdec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/6271373f5dd4cc1750eccb73839d20797bd66072", - "reference": "6271373f5dd4cc1750eccb73839d20797bd66072", + "url": "https://api.github.com/repos/symfony/messenger/zipball/804a8997f93313a8f7ed19e8cca3b44fdd18bdec", + "reference": "804a8997f93313a8f7ed19e8cca3b44fdd18bdec", "shasum": "" }, "require": { @@ -4732,7 +4908,7 @@ "description": "Helps applications send and receive messages to/from other applications or via message queues", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/messenger/tree/v7.0.3" + "source": "https://github.com/symfony/messenger/tree/v7.0.4" }, "funding": [ { @@ -4748,7 +4924,7 @@ "type": "tidelift" } ], - "time": "2024-01-30T13:55:15+00:00" + "time": "2024-02-26T07:52:39+00:00" }, { "name": "symfony/mime", @@ -5139,16 +5315,16 @@ }, { "name": "symfony/password-hasher", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "c2447171293bd73dabeae293c8d9d824b444babf" + "reference": "0eba656c16ecdf5588b3ddd2b2337b06173d839f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/c2447171293bd73dabeae293c8d9d824b444babf", - "reference": "c2447171293bd73dabeae293c8d9d824b444babf", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/0eba656c16ecdf5588b3ddd2b2337b06173d839f", + "reference": "0eba656c16ecdf5588b3ddd2b2337b06173d839f", "shasum": "" }, "require": { @@ -5191,7 +5367,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v7.0.3" + "source": "https://github.com/symfony/password-hasher/tree/v7.0.4" }, "funding": [ { @@ -5207,7 +5383,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-12T11:15:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5774,16 +5950,16 @@ }, { "name": "symfony/process", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "937a195147e0c27b2759ade834169ed006d0bc74" + "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/937a195147e0c27b2759ade834169ed006d0bc74", - "reference": "937a195147e0c27b2759ade834169ed006d0bc74", + "url": "https://api.github.com/repos/symfony/process/zipball/0e7727191c3b71ebec6d529fa0e50a01ca5679e9", + "reference": "0e7727191c3b71ebec6d529fa0e50a01ca5679e9", "shasum": "" }, "require": { @@ -5815,7 +5991,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.0.3" + "source": "https://github.com/symfony/process/tree/v7.0.4" }, "funding": [ { @@ -5831,20 +6007,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/property-access", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "5c7814d1a84bc11254c5bc761d9878b04e708dec" + "reference": "44e3746d4de8d0961a44ee332c74dd0918266127" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/5c7814d1a84bc11254c5bc761d9878b04e708dec", - "reference": "5c7814d1a84bc11254c5bc761d9878b04e708dec", + "url": "https://api.github.com/repos/symfony/property-access/zipball/44e3746d4de8d0961a44ee332c74dd0918266127", + "reference": "44e3746d4de8d0961a44ee332c74dd0918266127", "shasum": "" }, "require": { @@ -5891,7 +6067,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v7.0.3" + "source": "https://github.com/symfony/property-access/tree/v7.0.4" }, "funding": [ { @@ -5907,7 +6083,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-16T13:44:10+00:00" }, { "name": "symfony/property-info", @@ -5994,16 +6170,16 @@ }, { "name": "symfony/routing", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "858b26756ffc35a11238b269b484ee3a393a74d3" + "reference": "ba6bf07d43289c6a4b4591ddb75bc3bc5f069c19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/858b26756ffc35a11238b269b484ee3a393a74d3", - "reference": "858b26756ffc35a11238b269b484ee3a393a74d3", + "url": "https://api.github.com/repos/symfony/routing/zipball/ba6bf07d43289c6a4b4591ddb75bc3bc5f069c19", + "reference": "ba6bf07d43289c6a4b4591ddb75bc3bc5f069c19", "shasum": "" }, "require": { @@ -6055,7 +6231,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.0.3" + "source": "https://github.com/symfony/routing/tree/v7.0.5" }, "funding": [ { @@ -6071,7 +6247,7 @@ "type": "tidelift" } ], - "time": "2024-01-30T13:55:15+00:00" + "time": "2024-02-27T12:34:35+00:00" }, { "name": "symfony/runtime", @@ -6154,16 +6330,16 @@ }, { "name": "symfony/security-bundle", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "84984586e74a3c194c17d6b33ccca682ead23e05" + "reference": "5d620bd5493d62d8016b2383d8690fade66163c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/84984586e74a3c194c17d6b33ccca682ead23e05", - "reference": "84984586e74a3c194c17d6b33ccca682ead23e05", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/5d620bd5493d62d8016b2383d8690fade66163c1", + "reference": "5d620bd5493d62d8016b2383d8690fade66163c1", "shasum": "" }, "require": { @@ -6245,7 +6421,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v7.0.3" + "source": "https://github.com/symfony/security-bundle/tree/v7.0.5" }, "funding": [ { @@ -6261,7 +6437,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-03-02T12:46:12+00:00" }, { "name": "symfony/security-core", @@ -6417,16 +6593,16 @@ }, { "name": "symfony/security-http", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "d974526dc43525a17bd588e45f86f382edd57331" + "reference": "f3a70a937128f47366821a9f4b5dbfaa0ba9c862" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/d974526dc43525a17bd588e45f86f382edd57331", - "reference": "d974526dc43525a17bd588e45f86f382edd57331", + "url": "https://api.github.com/repos/symfony/security-http/zipball/f3a70a937128f47366821a9f4b5dbfaa0ba9c862", + "reference": "f3a70a937128f47366821a9f4b5dbfaa0ba9c862", "shasum": "" }, "require": { @@ -6484,7 +6660,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v7.0.3" + "source": "https://github.com/symfony/security-http/tree/v7.0.4" }, "funding": [ { @@ -6500,20 +6676,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-26T07:52:39+00:00" }, { "name": "symfony/serializer", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "6e83031c481e50b6f28e72531660341f1f120e6f" + "reference": "c71d61c6c37804e10981960e5f5ebc2c8f0a4fbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/6e83031c481e50b6f28e72531660341f1f120e6f", - "reference": "6e83031c481e50b6f28e72531660341f1f120e6f", + "url": "https://api.github.com/repos/symfony/serializer/zipball/c71d61c6c37804e10981960e5f5ebc2c8f0a4fbb", + "reference": "c71d61c6c37804e10981960e5f5ebc2c8f0a4fbb", "shasum": "" }, "require": { @@ -6579,7 +6755,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.0.3" + "source": "https://github.com/symfony/serializer/tree/v7.0.4" }, "funding": [ { @@ -6595,7 +6771,7 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:34:29+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/service-contracts", @@ -6681,16 +6857,16 @@ }, { "name": "symfony/stimulus-bundle", - "version": "v2.15.0", + "version": "v2.16.0", "source": { "type": "git", "url": "https://github.com/symfony/stimulus-bundle.git", - "reference": "c113ab8e92c6b14659f6be4e9bef5c1f4c4a000e" + "reference": "6add4bdab1b9df4f2b2532a9dcb7b2f26dbba634" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/c113ab8e92c6b14659f6be4e9bef5c1f4c4a000e", - "reference": "c113ab8e92c6b14659f6be4e9bef5c1f4c4a000e", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/6add4bdab1b9df4f2b2532a9dcb7b2f26dbba634", + "reference": "6add4bdab1b9df4f2b2532a9dcb7b2f26dbba634", "shasum": "" }, "require": { @@ -6730,7 +6906,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/stimulus-bundle/tree/v2.15.0" + "source": "https://github.com/symfony/stimulus-bundle/tree/v2.16.0" }, "funding": [ { @@ -6746,7 +6922,7 @@ "type": "tidelift" } ], - "time": "2024-02-14T16:26:57+00:00" + "time": "2024-02-29T16:20:46+00:00" }, { "name": "symfony/stopwatch", @@ -6812,16 +6988,16 @@ }, { "name": "symfony/string", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "524aac4a280b90a4420d8d6a040718d0586505ac" + "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/524aac4a280b90a4420d8d6a040718d0586505ac", - "reference": "524aac4a280b90a4420d8d6a040718d0586505ac", + "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b", + "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b", "shasum": "" }, "require": { @@ -6878,7 +7054,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.3" + "source": "https://github.com/symfony/string/tree/v7.0.4" }, "funding": [ { @@ -6894,20 +7070,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-01T13:17:36+00:00" }, { "name": "symfony/translation", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "7285f25c7dcc74d9ec1232473114274604e50f00" + "reference": "5b75e872f7d135d7abb4613809fadc8d9f3d30a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/7285f25c7dcc74d9ec1232473114274604e50f00", - "reference": "7285f25c7dcc74d9ec1232473114274604e50f00", + "url": "https://api.github.com/repos/symfony/translation/zipball/5b75e872f7d135d7abb4613809fadc8d9f3d30a0", + "reference": "5b75e872f7d135d7abb4613809fadc8d9f3d30a0", "shasum": "" }, "require": { @@ -6972,7 +7148,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.0.3" + "source": "https://github.com/symfony/translation/tree/v7.0.4" }, "funding": [ { @@ -6988,7 +7164,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "symfony/translation-contracts", @@ -7070,16 +7246,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "414ff6930889262a11ec67f351e9810dd8565b0d" + "reference": "d16aa4eb5bdaeb6e7407782431dc70530f3b1df5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/414ff6930889262a11ec67f351e9810dd8565b0d", - "reference": "414ff6930889262a11ec67f351e9810dd8565b0d", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/d16aa4eb5bdaeb6e7407782431dc70530f3b1df5", + "reference": "d16aa4eb5bdaeb6e7407782431dc70530f3b1df5", "shasum": "" }, "require": { @@ -7158,7 +7334,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.0.3" + "source": "https://github.com/symfony/twig-bridge/tree/v7.0.4" }, "funding": [ { @@ -7174,20 +7350,20 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:34:29+00:00" + "time": "2024-02-15T11:33:06+00:00" }, { "name": "symfony/twig-bundle", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "6fbf0cc2b0d0208be4881ff6069665687396b323" + "reference": "acab2368f53491e018bf31ef48b39df55a6812ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/6fbf0cc2b0d0208be4881ff6069665687396b323", - "reference": "6fbf0cc2b0d0208be4881ff6069665687396b323", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/acab2368f53491e018bf31ef48b39df55a6812ef", + "reference": "acab2368f53491e018bf31ef48b39df55a6812ef", "shasum": "" }, "require": { @@ -7242,7 +7418,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v7.0.3" + "source": "https://github.com/symfony/twig-bundle/tree/v7.0.4" }, "funding": [ { @@ -7258,7 +7434,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-15T11:33:06+00:00" }, { "name": "symfony/uid", @@ -7336,7 +7512,7 @@ }, { "name": "symfony/ux-turbo", - "version": "v2.15.0", + "version": "v2.16.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-turbo.git", @@ -7412,7 +7588,7 @@ "turbo-stream" ], "support": { - "source": "https://github.com/symfony/ux-turbo/tree/v2.15.0" + "source": "https://github.com/symfony/ux-turbo/tree/v2.16.0" }, "funding": [ { @@ -7430,18 +7606,102 @@ ], "time": "2024-02-20T16:11:17+00:00" }, + { + "name": "symfony/ux-twig-component", + "version": "v2.16.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-twig-component.git", + "reference": "c789f33dd8800949293dd94bf8e7bf01c39559a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/c789f33dd8800949293dd94bf8e7bf01c39559a2", + "reference": "c789f33dd8800949293dd94bf8e7bf01c39559a2", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "twig/twig": "~3.8.0" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^1.15" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TwigComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Twig components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-twig-component/tree/v2.16.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-02-29T16:20:59+00:00" + }, { "name": "symfony/validator", - "version": "v7.0.3", + "version": "v7.0.5", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "03b0c75d7d3df1ef9a0fd9fb8db1e86f83ffa2bb" + "reference": "6a73d479191a0bbbd9ffa3886af6e6ff6e79fb86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/03b0c75d7d3df1ef9a0fd9fb8db1e86f83ffa2bb", - "reference": "03b0c75d7d3df1ef9a0fd9fb8db1e86f83ffa2bb", + "url": "https://api.github.com/repos/symfony/validator/zipball/6a73d479191a0bbbd9ffa3886af6e6ff6e79fb86", + "reference": "6a73d479191a0bbbd9ffa3886af6e6ff6e79fb86", "shasum": "" }, "require": { @@ -7506,7 +7766,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.0.3" + "source": "https://github.com/symfony/validator/tree/v7.0.5" }, "funding": [ { @@ -7522,20 +7782,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-27T12:53:56+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "a7a061abbf6fe3d4a79032cbc5149a4d65a10234" + "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a7a061abbf6fe3d4a79032cbc5149a4d65a10234", - "reference": "a7a061abbf6fe3d4a79032cbc5149a4d65a10234", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e03ad7c1535e623edbb94c22cc42353e488c6670", + "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670", "shasum": "" }, "require": { @@ -7589,7 +7849,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.0.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.0.4" }, "funding": [ { @@ -7605,20 +7865,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-15T11:33:06+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "1fb79308cb5fc2b44bff6e8af10a5af6812e05b8" + "reference": "dfb0acb6803eb714f05d97dd4c5abe6d5fa9fe41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/1fb79308cb5fc2b44bff6e8af10a5af6812e05b8", - "reference": "1fb79308cb5fc2b44bff6e8af10a5af6812e05b8", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/dfb0acb6803eb714f05d97dd4c5abe6d5fa9fe41", + "reference": "dfb0acb6803eb714f05d97dd4c5abe6d5fa9fe41", "shasum": "" }, "require": { @@ -7663,7 +7923,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.0.3" + "source": "https://github.com/symfony/var-exporter/tree/v7.0.4" }, "funding": [ { @@ -7679,7 +7939,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-26T10:35:24+00:00" }, { "name": "symfony/web-link", @@ -8520,16 +8780,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.1", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69", - "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { @@ -8572,26 +8832,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2024-02-21T19:24:10+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -8632,9 +8893,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -8755,16 +9022,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.0", + "version": "11.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "5e238e4b982cb272bf9faeee6f33af83d465d0e2" + "reference": "7e35a2cbcabac0e6865fd373742ea432a3c34f92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5e238e4b982cb272bf9faeee6f33af83d465d0e2", - "reference": "5e238e4b982cb272bf9faeee6f33af83d465d0e2", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e35a2cbcabac0e6865fd373742ea432a3c34f92", + "reference": "7e35a2cbcabac0e6865fd373742ea432a3c34f92", "shasum": "" }, "require": { @@ -8821,7 +9088,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.0" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.3" }, "funding": [ { @@ -8829,7 +9096,7 @@ "type": "github" } ], - "time": "2024-02-02T06:03:46+00:00" + "time": "2024-03-12T15:35:40+00:00" }, { "name": "phpunit/php-file-iterator", @@ -9078,16 +9345,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.0.3", + "version": "11.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de24e7e7c67fbf437f7b6cd7bc919f2dc6fd89d4" + "reference": "6af32d7938fc366f86e49a5f5ebb314018d1b1fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de24e7e7c67fbf437f7b6cd7bc919f2dc6fd89d4", - "reference": "de24e7e7c67fbf437f7b6cd7bc919f2dc6fd89d4", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6af32d7938fc366f86e49a5f5ebb314018d1b1fb", + "reference": "6af32d7938fc366f86e49a5f5ebb314018d1b1fb", "shasum": "" }, "require": { @@ -9158,7 +9425,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.0.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.0.6" }, "funding": [ { @@ -9174,20 +9441,20 @@ "type": "tidelift" } ], - "time": "2024-02-10T06:31:16+00:00" + "time": "2024-03-12T15:40:01+00:00" }, { "name": "sebastian/cli-parser", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "efd6ce5bb8131fe981e2f879dbd47605fbe0cc6f" + "reference": "00a74d5568694711f0222e54fb281e1d15fdf04a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efd6ce5bb8131fe981e2f879dbd47605fbe0cc6f", - "reference": "efd6ce5bb8131fe981e2f879dbd47605fbe0cc6f", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/00a74d5568694711f0222e54fb281e1d15fdf04a", + "reference": "00a74d5568694711f0222e54fb281e1d15fdf04a", "shasum": "" }, "require": { @@ -9223,7 +9490,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.0" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.1" }, "funding": [ { @@ -9231,7 +9498,7 @@ "type": "github" } ], - "time": "2024-02-02T05:48:04+00:00" + "time": "2024-03-02T07:26:58+00:00" }, { "name": "sebastian/code-unit", @@ -9483,16 +9750,16 @@ }, { "name": "sebastian/diff", - "version": "6.0.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3e3f502419518897a923aa1c64d51f9def2e0aff" + "reference": "ab83243ecc233de5655b76f577711de9f842e712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3e3f502419518897a923aa1c64d51f9def2e0aff", - "reference": "3e3f502419518897a923aa1c64d51f9def2e0aff", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ab83243ecc233de5655b76f577711de9f842e712", + "reference": "ab83243ecc233de5655b76f577711de9f842e712", "shasum": "" }, "require": { @@ -9538,7 +9805,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/6.0.0" + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.1" }, "funding": [ { @@ -9546,7 +9813,7 @@ "type": "github" } ], - "time": "2024-02-02T05:56:35+00:00" + "time": "2024-03-02T07:30:33+00:00" }, { "name": "sebastian/environment", @@ -9614,16 +9881,16 @@ }, { "name": "sebastian/exporter", - "version": "6.0.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d0c0a93fc746b0c066037f1e7d09104129e868ff" + "reference": "f291e5a317c321c0381fa9ecc796fa2d21b186da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d0c0a93fc746b0c066037f1e7d09104129e868ff", - "reference": "d0c0a93fc746b0c066037f1e7d09104129e868ff", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f291e5a317c321c0381fa9ecc796fa2d21b186da", + "reference": "f291e5a317c321c0381fa9ecc796fa2d21b186da", "shasum": "" }, "require": { @@ -9680,7 +9947,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/6.0.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/6.0.1" }, "funding": [ { @@ -9688,20 +9955,20 @@ "type": "github" } ], - "time": "2024-02-02T05:58:52+00:00" + "time": "2024-03-02T07:28:20+00:00" }, { "name": "sebastian/global-state", - "version": "7.0.0", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "590e7cbc6565fa2e26c3df4e629a34bb0bc00c17" + "reference": "c3a307e832f2e69c7ef869e31fc644fde0e7cb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/590e7cbc6565fa2e26c3df4e629a34bb0bc00c17", - "reference": "590e7cbc6565fa2e26c3df4e629a34bb0bc00c17", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c3a307e832f2e69c7ef869e31fc644fde0e7cb3e", + "reference": "c3a307e832f2e69c7ef869e31fc644fde0e7cb3e", "shasum": "" }, "require": { @@ -9742,7 +10009,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.0" + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.1" }, "funding": [ { @@ -9750,7 +10017,7 @@ "type": "github" } ], - "time": "2024-02-02T05:59:33+00:00" + "time": "2024-03-02T07:32:10+00:00" }, { "name": "sebastian/lines-of-code", @@ -10308,16 +10575,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "3330a8f836e7631412c5e07f69b88480d27a20a2" + "reference": "6cb272cbec4dc7a30a853d2931766b03bea92dda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/3330a8f836e7631412c5e07f69b88480d27a20a2", - "reference": "3330a8f836e7631412c5e07f69b88480d27a20a2", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/6cb272cbec4dc7a30a853d2931766b03bea92dda", + "reference": "6cb272cbec4dc7a30a853d2931766b03bea92dda", "shasum": "" }, "require": { @@ -10355,7 +10622,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v7.0.3" + "source": "https://github.com/symfony/dom-crawler/tree/v7.0.4" }, "funding": [ { @@ -10371,20 +10638,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-12T11:15:03+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.55.1", + "version": "v1.56.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "11a9d3125c5b93ab4043f0f2e9927fdc55881c17" + "reference": "bbb7949ae048363df7c8439abeddef8befd155ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/11a9d3125c5b93ab4043f0f2e9927fdc55881c17", - "reference": "11a9d3125c5b93ab4043f0f2e9927fdc55881c17", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/bbb7949ae048363df7c8439abeddef8befd155ce", + "reference": "bbb7949ae048363df7c8439abeddef8befd155ce", "shasum": "" }, "require": { @@ -10447,7 +10714,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.55.1" + "source": "https://github.com/symfony/maker-bundle/tree/v1.56.0" }, "funding": [ { @@ -10463,7 +10730,7 @@ "type": "tidelift" } ], - "time": "2024-02-21T13:41:51+00:00" + "time": "2024-03-04T13:36:45+00:00" }, { "name": "symfony/panther", @@ -10556,16 +10823,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "0a2eeb0d9e68bf01660e3e903f8113508bb46132" + "reference": "54ca13ec990a40411ad978e08d994fca6cdd865f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/0a2eeb0d9e68bf01660e3e903f8113508bb46132", - "reference": "0a2eeb0d9e68bf01660e3e903f8113508bb46132", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/54ca13ec990a40411ad978e08d994fca6cdd865f", + "reference": "54ca13ec990a40411ad978e08d994fca6cdd865f", "shasum": "" }, "require": { @@ -10617,7 +10884,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.3" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.4" }, "funding": [ { @@ -10633,20 +10900,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T15:02:46+00:00" + "time": "2024-02-08T19:22:56+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v7.0.3", + "version": "v7.0.4", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "320dbcaa6e3a72797a614216703df8b187f19265" + "reference": "542daea1345fe181cbfd52db00717174a838ea0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/320dbcaa6e3a72797a614216703df8b187f19265", - "reference": "320dbcaa6e3a72797a614216703df8b187f19265", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/542daea1345fe181cbfd52db00717174a838ea0a", + "reference": "542daea1345fe181cbfd52db00717174a838ea0a", "shasum": "" }, "require": { @@ -10698,7 +10965,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.0.3" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.0.4" }, "funding": [ { @@ -10714,20 +10981,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T15:41:16+00:00" + "time": "2024-02-22T20:27:20+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -10756,7 +11023,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -10764,7 +11031,7 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" }, { "name": "zenstruck/assert", diff --git a/config/bundles.php b/config/bundles.php index 81fd39a..a093148 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -16,4 +16,5 @@ Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], RD\SerializeTypeBundle\RDSerializeTypeBundle::class => ['all' => true], + Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], ]; diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index d42c52d..957aa70 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -8,6 +8,9 @@ doctrine: profiling_collect_backtrace: '%kernel.debug%' use_savepoints: true + types: + datetime_immutable: \Carbon\Doctrine\DateTimeImmutableType + datetime: \Carbon\Doctrine\DateTimeType orm: auto_generate_proxy_classes: true enable_lazy_ghost_objects: true diff --git a/config/packages/twig_component.yaml b/config/packages/twig_component.yaml new file mode 100644 index 0000000..fd17ac6 --- /dev/null +++ b/config/packages/twig_component.yaml @@ -0,0 +1,5 @@ +twig_component: + anonymous_template_directory: 'components/' + defaults: + # Namespace & directory for components + App\Twig\Components\: 'components/' diff --git a/importmap.php b/importmap.php index 23ec256..f272f0d 100644 --- a/importmap.php +++ b/importmap.php @@ -10,8 +10,6 @@ * be used as an "entrypoint" (and passed to the importmap() Twig function). * * The "importmap:require" command can be used to add new entries to this file. - * - * This file has been auto-generated by the importmap commands. */ return [ 'app' => [ @@ -25,7 +23,7 @@ 'version' => '3.2.2', ], '@hotwired/turbo' => [ - 'version' => '8.0.3', + 'version' => '8.0.4', ], 'bootstrap' => [ 'version' => '5.3.3', @@ -38,6 +36,12 @@ 'type' => 'css', ], 'axios' => [ - 'version' => '1.6.7', + 'version' => '1.6.8', + ], + 'luxon' => [ + 'version' => '3.4.4', + ], + 'stimulus-use' => [ + 'version' => '0.52.2', ], ]; diff --git a/migrations/Version20240319093206.php b/migrations/Version20240319093206.php new file mode 100644 index 0000000..147f2d4 --- /dev/null +++ b/migrations/Version20240319093206.php @@ -0,0 +1,36 @@ +addSql('CREATE TABLE time_entry ( + started_at TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL, + accumulated_time INT NOT NULL, + running BOOLEAN NOT NULL, + last_restarted_at TIMESTAMP(6) WITHOUT TIME ZONE DEFAULT NULL, + id UUID NOT NULL, + PRIMARY KEY(id) + )'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP TABLE time_entry'); + } +} diff --git a/src/Controller/MainController.php b/src/Controller/MainController.php index 44a14e4..4647a7c 100644 --- a/src/Controller/MainController.php +++ b/src/Controller/MainController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Repository\NoteRepository; +use App\Repository\TimeEntryRepository; use App\Repository\TodoListRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; @@ -11,11 +12,12 @@ class MainController extends AbstractController { #[Route(name: 'app_main_index')] - public function index(NoteRepository $notes, TodoListRepository $listRepository): Response + public function index(NoteRepository $notes, TodoListRepository $listRepository, TimeEntryRepository $timeEntryRepository): Response { return $this->render('main.html.twig', [ 'notes' => $notes->findAll(), 'todos' => $listRepository->findAll(), + 'timers' => $timeEntryRepository->findBy([], ['startedAt' => 'DESC']), ]); } } diff --git a/src/Controller/TimerController.php b/src/Controller/TimerController.php new file mode 100644 index 0000000..3cbbed8 --- /dev/null +++ b/src/Controller/TimerController.php @@ -0,0 +1,68 @@ + Requirement::UUID], methods: ['POST'])] + public function createTimer(): JsonResponse + { + // @TODO CSRF + + $timeEntry = new TimeEntry(startedAt: new CarbonImmutable()); + + $timeEntry->startTimer(); + + $this->repository->persist($timeEntry, flush: true); + + return $this->json([ + 'message' => 'OK', + 'html' => $this->render('time_entry/_timer-card.html.twig', [ + 'timer' => $timeEntry, + ]), + ]); + } + + #[Route(path: '/start/{id}', name: 'start', requirements: ['id' => Requirement::UUID], methods: ['POST'])] + public function startTimer(TimeEntry $timeEntry): JsonResponse + { + // @TODO CSRF + + $timeEntry->startTimer(); + + $this->repository->flush(); + + return $this->json([ + 'message' => 'OK', + 'restartedAt' => $timeEntry->getLastRestartedAt()->timestamp ?? false, + 'accumulatedSeconds' => $timeEntry->getAccumulatedTime()->totalSeconds, + ]); + } + + #[Route(path: '/pause/{id}', name: 'pause', requirements: ['id' => Requirement::UUID], methods: ['POST'])] + public function pauseTimer(TimeEntry $timeEntry, TimeEntryRepository $repository): JsonResponse + { + $timeEntry->stopTimer(); + + $repository->flush(); + + return $this->json([ + 'message' => 'OK', + 'accumulatedSeconds' => $timeEntry->getAccumulatedTime()->totalSeconds, + ]); + } +} diff --git a/src/DataFixtures/LorumIpsumFixtures.php b/src/DataFixtures/LorumIpsumFixtures.php index 1c848af..ef6d022 100644 --- a/src/DataFixtures/LorumIpsumFixtures.php +++ b/src/DataFixtures/LorumIpsumFixtures.php @@ -4,6 +4,7 @@ use App\Factory\NoteFactory; use App\Factory\TaskFactory; +use App\Factory\TimeEntryFactory; use App\Factory\TodoListFactory; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; @@ -19,5 +20,7 @@ public function load(ObjectManager $manager): void foreach ($todoLists as $todoList) { TaskFactory::createMany(3, ['todoList' => $todoList]); } + + TimeEntryFactory::createMany(3); } } diff --git a/src/Entity/TimeEntry.php b/src/Entity/TimeEntry.php new file mode 100644 index 0000000..228b8d5 --- /dev/null +++ b/src/Entity/TimeEntry.php @@ -0,0 +1,75 @@ +startedAt; + } + + public function getAccumulatedTime(): CarbonInterval + { + return (new CarbonInterval())->addSeconds($this->accumulatedTime)->cascade(); + } + + public function isRunning(): bool + { + return $this->running; + } + + public function getLastRestartedAt(): ?CarbonImmutable + { + return $this->lastRestartedAt; + } + + public function startTimer(): self + { + $this->running = true; + + $this->lastRestartedAt = new CarbonImmutable(); + + return $this; + } + + public function stopTimer(): self + { + if (!$this->running) { + return $this; + } + + $started = $this->lastRestartedAt ?? $this->startedAt; + + $interval = $started->diffAsCarbonInterval(absolute: true); + + $this->accumulatedTime = (int) $interval->cascade()->totalSeconds + $this->accumulatedTime; + + $this->running = false; + + return $this; + } +} diff --git a/src/Factory/TimeEntryFactory.php b/src/Factory/TimeEntryFactory.php new file mode 100644 index 0000000..6bd29e8 --- /dev/null +++ b/src/Factory/TimeEntryFactory.php @@ -0,0 +1,62 @@ + + * + * @method TimeEntry|Proxy create(array|callable $attributes = []) + * @method static TimeEntry|Proxy createOne(array $attributes = []) + * @method static TimeEntry|Proxy find(object|array|mixed $criteria) + * @method static TimeEntry|Proxy findOrCreate(array $attributes) + * @method static TimeEntry|Proxy first(string $sortedField = 'id') + * @method static TimeEntry|Proxy last(string $sortedField = 'id') + * @method static TimeEntry|Proxy random(array $attributes = []) + * @method static TimeEntry|Proxy randomOrCreate(array $attributes = []) + * @method static TimeEntryRepository|RepositoryProxy repository() + * @method static TimeEntry[]|Proxy[] all() + * @method static TimeEntry[]|Proxy[] createMany(int $number, array|callable $attributes = []) + * @method static TimeEntry[]|Proxy[] createSequence(iterable|callable $sequence) + * @method static TimeEntry[]|Proxy[] findBy(array $attributes) + * @method static TimeEntry[]|Proxy[] randomRange(int $min, int $max, array $attributes = []) + * @method static TimeEntry[]|Proxy[] randomSet(int $number, array $attributes = []) + * + * @psalm-method TimeEntry&Proxy create(array|callable $attributes = []) + * @psalm-method static TimeEntry&Proxy createOne(array $attributes = []) + * @psalm-method static TimeEntry&Proxy find(object|array|mixed $criteria) + * @psalm-method static TimeEntry&Proxy findOrCreate(array $attributes) + * @psalm-method static TimeEntry&Proxy first(string $sortedField = 'id') + * @psalm-method static TimeEntry&Proxy last(string $sortedField = 'id') + * @psalm-method static TimeEntry&Proxy random(array $attributes = []) + * @psalm-method static TimeEntry&Proxy randomOrCreate(array $attributes = []) + * @psalm-method static TimeEntryRepository&RepositoryProxy repository() + * @psalm-method static TimeEntry[]&Proxy[] all() + * @psalm-method static TimeEntry[]&Proxy[] createMany(int $number, array|callable $attributes = []) + * @psalm-method static TimeEntry[]&Proxy[] createSequence(iterable|callable $sequence) + * @psalm-method static TimeEntry[]&Proxy[] findBy(array $attributes) + * @psalm-method static TimeEntry[]&Proxy[] randomRange(int $min, int $max, array $attributes = []) + * @psalm-method static TimeEntry[]&Proxy[] randomSet(int $number, array $attributes = []) + */ +final class TimeEntryFactory extends ModelFactory +{ + #[\Override] + protected function getDefaults(): array + { + return [ + 'startedAt' => CarbonImmutable::createFromInterface(self::faker()->dateTime()), + ]; + } + + #[\Override] + protected static function getClass(): string + { + return TimeEntry::class; + } +} diff --git a/src/Repository/TimeEntryRepository.php b/src/Repository/TimeEntryRepository.php new file mode 100644 index 0000000..6a9be6f --- /dev/null +++ b/src/Repository/TimeEntryRepository.php @@ -0,0 +1,22 @@ + + * + * @method TimeEntry|null find($id, $lockMode = null, $lockVersion = null) + * @method TimeEntry|null findOneBy(array $criteria, array $orderBy = null) + * @method TimeEntry[] findAll() + * @method TimeEntry[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class TimeEntryRepository extends AbstractRepository +{ + #[\Override] + protected static function getEntityClassName(): string + { + return TimeEntry::class; + } +} diff --git a/symfony.lock b/symfony.lock index eb27484..754ea8d 100644 --- a/symfony.lock +++ b/symfony.lock @@ -284,6 +284,18 @@ "symfony/ux-turbo": { "version": "v2.14.2" }, + "symfony/ux-twig-component": { + "version": "2.16", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "67814b5f9794798b885cec9d3f48631424449a01" + }, + "files": [ + "config/packages/twig_component.yaml" + ] + }, "symfony/validator": { "version": "7.0", "recipe": { diff --git a/templates/components/Button/Timer/Action.html.twig b/templates/components/Button/Timer/Action.html.twig new file mode 100644 index 0000000..306f936 --- /dev/null +++ b/templates/components/Button/Timer/Action.html.twig @@ -0,0 +1,8 @@ +{% props svg, target, action, color %} + \ No newline at end of file diff --git a/templates/main.html.twig b/templates/main.html.twig index 0a79620..dcaa5b4 100644 --- a/templates/main.html.twig +++ b/templates/main.html.twig @@ -7,7 +7,24 @@ {.lead .text-secondary} {{ text }} {% endmacro %}
-
+
+

Timer + +

+
+ {% for timer in timers %} +
+ {{ include('time_entry/_timer-card.html.twig', {'timer': timer}) }} +
+ {% endfor %} +
+
+

Notes {{ include('svg/plus-circle.html.twig') }} diff --git a/templates/svg/play.html.twig b/templates/svg/play.html.twig new file mode 100644 index 0000000..0adc1c1 --- /dev/null +++ b/templates/svg/play.html.twig @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/templates/svg/stop.html.twig b/templates/svg/stop.html.twig new file mode 100644 index 0000000..9870bf2 --- /dev/null +++ b/templates/svg/stop.html.twig @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/templates/time_entry/_timer-card.html.twig b/templates/time_entry/_timer-card.html.twig new file mode 100644 index 0000000..0083744 --- /dev/null +++ b/templates/time_entry/_timer-card.html.twig @@ -0,0 +1,23 @@ +
+
+
+ {{ timer.accumulatedTime|date('%h:%I:%S') }} + + +
+
+ {{ timer.startedAt|date("H:i", "America/New_York") }} +
+
+ {{ timer.startedAt|date("M jS Y") }} +
+
+
\ No newline at end of file diff --git a/tests/Functional/Controller/TimerControllerTest.php b/tests/Functional/Controller/TimerControllerTest.php new file mode 100644 index 0000000..0f262ca --- /dev/null +++ b/tests/Functional/Controller/TimerControllerTest.php @@ -0,0 +1,71 @@ +request('POST', '/timer/create'); + + /** @var TimeEntryRepository $repository */ + $repository = static::getContainer()->get(TimeEntryRepository::class); + + self::assertCount(1, $repository->findAll()); + } + + public function testStartTimer(): void + { + $client = static::createClient(); + + $timeEntry = TimeEntryFactory::createOne(['running' => false]); + + $client->request('POST', '/timer/start/'.$timeEntry->getId()); + + self::assertResponseIsSuccessful(); + + $responseContent = $client->getResponse()->getContent(); + + self::assertJsonStringEqualsJsonString( + /** @phpstan-ignore-next-line */ + json_encode(['message' => 'OK', 'accumulatedSeconds' => 0, 'restartedAt' => $timeEntry->getLastRestartedAt()->timestamp]), + /** @phpstan-ignore-next-line */ + $responseContent + ); + } + + public function testPauseTimer(): void + { + $client = static::createClient(); + + $startedAt = new CarbonImmutable(); + Carbon::setTestNow($startedAt); + + $timeEntry = TimeEntryFactory::createOne([ + 'startedAt' => $startedAt, + 'running' => true, + ]); + + Carbon::sleep(120); + + $client->request('POST', '/timer/pause/'.$timeEntry->getId()); + + Carbon::setTestNow(); + + self::assertResponseIsSuccessful(); + + $responseContent = $client->getResponse()->getContent(); + + /** @phpstan-ignore-next-line */ + self::assertJsonStringEqualsJsonString(json_encode(['message' => 'OK', 'accumulatedSeconds' => 120]), $responseContent); + self::assertSame(120, (int) $timeEntry->getAccumulatedTime()->totalSeconds); + } +} diff --git a/tests/Unit/Entity/TimeEntryTest.php b/tests/Unit/Entity/TimeEntryTest.php new file mode 100644 index 0000000..a53cb37 --- /dev/null +++ b/tests/Unit/Entity/TimeEntryTest.php @@ -0,0 +1,40 @@ +isRunning()); + self::assertSame(0, (int) $entry->getAccumulatedTime()->totalSeconds); + } + + public function testStopTimer(): void + { + $entry = new TimeEntry(new CarbonImmutable()); + + self::assertSame(0.0, $entry->getAccumulatedTime()->totalSeconds); + + sleep(1); + + $entry->stopTimer(); + + self::assertFalse($entry->isRunning()); + self::assertSame('1 second', $entry->getAccumulatedTime()->forHumans()); + + $entry->startTimer(); + + sleep(2); + + $entry->stopTimer(); + + self::assertSame('3 seconds', $entry->getAccumulatedTime()->forHumans()); + } +}