diff --git a/.github/workflows/php83.yaml b/.github/workflows/php83.yaml
new file mode 100644
index 0000000..af8e437
--- /dev/null
+++ b/.github/workflows/php83.yaml
@@ -0,0 +1,26 @@
+name: Build PHP 8.3
+
+on:
+ push:
+ branches: [ main, dev ]
+ pull_request:
+ branches: [ main, dev ]
+env:
+ OPERATING_SYS: ubuntu-latest
+ PHP_VERSION: 8.3
+jobs:
+
+ test:
+ name: Run Tests
+ uses: WebFiori/workflows/.github/workflows/test-php.yaml@main
+ with:
+ php-version: '8.3'
+ phpunit-config: 'tests/phpunit10.xml'
+
+
+ release-prod:
+ name: Prepare Production Release Branch / Publish Release
+ needs: [test]
+ uses: WebFiori/workflows/.github/workflows/release-php.yaml@main
+ with:
+ branch: 'main'
diff --git a/.gitignore b/.gitignore
index d4d9985..0cf2b95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,8 @@
-/nbproject
-/vendor
+/nbproject
+/vendor
.php_cs.cache
php-cs-fixer-v2.phar
+*.Identifier
+/tests/.phpunit.cache
+/.vscode
+tests/clover.xml
diff --git a/LICENSE b/LICENSE
index f46962f..4973af7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,21 @@
-MIT License
-
-Copyright (c) 2021 WebFiori Framework
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+MIT License
+
+Copyright (c) 2021 WebFiori Framework
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 0dc4875..8af61ab 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,17 @@
-# Vuetify Core
-
-This repo holds a base theme which holds basic structure for building Vuetify based themes.
-
-## Installation
-First of all, you need to have WebFiori framework installed. After that, include the following in your `require` section of your `composer.json` file: `webfiori/vuetifyCore`. Then run the command `php composer "install" "--no-dev"` to install your dependencies.
-
-## Classes
-
-### [`VuetifyThemeCore`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/VuetifyThemeCore.php)
-This is the theme class. It acts as the core of any Vuetify based theme. The developer must extend this class in order to create his own Vuetify based themes.
-
-### [`VuetifyWebPage`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/VuetifyWebPage.php)
-This class extends the class `WebPage`. It has utility methods which helps in creating pages which is based on Vuetify much easier task.
-
-### [`CreateVuetifyThemeCommand`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php)
-A CLI command that can be registered to create Vuetify theme wireframes. This command can be registered in the class `InitCLICommands` of your application.
+# Vuetify Core
+
+This repo holds a base theme which holds basic structure for building Vuetify based themes.
+
+## Installation
+First of all, you need to have WebFiori framework installed. After that, include the following in your `require` section of your `composer.json` file: `webfiori/vuetifyCore`. Then run the command `php composer "install" "--no-dev"` to install your dependencies.
+
+## Classes
+
+### [`VuetifyThemeCore`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/VuetifyThemeCore.php)
+This is the theme class. It acts as the core of any Vuetify based theme. The developer must extend this class in order to create his own Vuetify based themes.
+
+### [`VuetifyWebPage`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/VuetifyWebPage.php)
+This class extends the class `WebPage`. It has utility methods which helps in creating pages which is based on Vuetify much easier task.
+
+### [`CreateVuetifyThemeCommand`](https://github.com/WebFiori/vuetifyCore/blob/main/themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php)
+A CLI command that can be registered to create Vuetify theme wireframes. This command can be registered in the class `InitCLICommands` of your application.
diff --git a/TEST_SUMMARY.md b/TEST_SUMMARY.md
new file mode 100644
index 0000000..58586e0
--- /dev/null
+++ b/TEST_SUMMARY.md
@@ -0,0 +1,62 @@
+# VuetifyCore Test Suite Summary
+
+## Overview
+Implemented comprehensive test cases for the VuetifyCore library following the WebFiori framework testing patterns.
+
+## Test Files Created
+
+### 1. CreateVuetifyThemeCommandTest.php
+- Tests the CLI command for creating Vuetify themes
+- Validates command name, description, and arguments
+- Tests command instantiation and basic properties
+
+### 2. VuetifyThemeClassWriterTest.php
+- Tests the theme class writer with different wireframes:
+ - Base wireframe
+ - Extended Toolbar wireframe
+ - System Bar wireframe
+ - Inbox wireframe
+ - Side Navigation wireframe
+- Validates class name and namespace handling
+
+### 3. SectionWritersTest.php
+- Tests all section writer classes:
+ - HeaderSectionWriter
+ - FooterSectionWriter
+ - SideSectionWriter
+ - HeadSectionWriter
+ - SysBarWriter
+- Validates proper instantiation with VuetifyThemeClassWriter
+
+### 4. VuetifyWebPageTest.php
+- Tests JSON handling functionality
+- Tests Vuetify item structure creation
+- Validates data transformation methods
+
+### 5. VuetifyThemeCoreTest.php
+- Tests core theme functionality
+- Validates version format and constants
+- Tests app ID validation logic
+
+### 6. IntegrationTest.php
+- Tests integration between different components
+- Validates command and writer interaction
+- Tests JSON structure for Vuetify components
+- Tests all wireframe types
+
+## Test Results
+- **Total Tests**: 22
+- **Total Assertions**: 61
+- **Status**: All tests passing ✅
+- **Coverage**: Clover XML report generated
+
+## Fixed Issues
+1. Fixed composer.json syntax errors
+2. Updated PHPUnit configuration for new directory structure
+3. Fixed namespace references after PascalCase refactoring
+4. Added proper autoloading configuration
+5. Corrected API calls to match WebFiori framework patterns
+
+## Test Commands
+- `composer test` - Run all tests
+- `composer test10` - Run tests with PHPUnit 10 configuration
diff --git a/themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php b/Themes/VuetifyCore/Cli/CreateVuetifyThemeCommand.php
similarity index 83%
rename from themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php
rename to Themes/VuetifyCore/Cli/CreateVuetifyThemeCommand.php
index f5bcd0b..78f3199 100644
--- a/themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php
+++ b/Themes/VuetifyCore/Cli/CreateVuetifyThemeCommand.php
@@ -1,79 +1,82 @@
-select('Select theme wireframe:', $wireframes, 0);
- $classInfo = $this->getClassInfo();
- $classInfo['wireframe'] = $wireframe;
- $creator = new VuetifyThemeClassWriter($classInfo);
- $this->println("Creating new vuetify theme based on '$wireframe' wireframe...");
- $creator->writeClass();
- $this->println('Your theme was successfully created.');
-
- return 0;
- }
-
- /**
- * Prompts the user to enter class information such as it is name.
- *
- * This method is useful in case we would like to create a class.
- *
- * @return array The method will return an array that contains 3 indices:
- *
- * name : The name of the class.
- * namespace : The namespace of the class. It will be empty string if no
- * namespace is entered.
- * path : The location at which the class will be created.
- *
- *
- * @since 1.0
- */
- public function getClassInfo() {
- $classExist = true;
-
- do {
- $className = $this->readClassName('Enter a name for the new class:', 'Theme');
- $ns = $this->readNamespace('Enter namespace for the class:', 'themes\\vuetify');
- $classWithNs = $ns.'\\'.$className;
- $classExist = class_exists($classWithNs);
-
- if ($classExist) {
- $this->error('A class in the given namespace which has the given name was found.');
- }
- } while ($classExist);
- $path = ROOT_DIR.DS.trim(trim(str_replace('\\', DS, str_replace('/', DS, $ns)),'/'),'\\');
-
- return [
- 'name' => $className,
- 'namespace' => $ns,
- 'path' => $path
- ];
- }
-}
+select('Select theme wireframe:', $wireframes, 0);
+ $classInfo = $this->getClassInfo();
+ $classInfo['wireframe'] = $wireframe;
+ $creator = new VuetifyThemeClassWriter($classInfo);
+ $this->println("Creating new vuetify theme based on '$wireframe' wireframe...");
+ $creator->writeClass();
+ $this->println('Your theme was successfully created.');
+
+ return 0;
+ }
+
+ /**
+ * Prompts the user to enter class information such as it is name.
+ *
+ * This method is useful in case we would like to create a class.
+ *
+ * @return array The method will return an array that contains 3 indices:
+ *
+ * name : The name of the class.
+ * namespace : The namespace of the class. It will be empty string if no
+ * namespace is entered.
+ * path : The location at which the class will be created.
+ *
+ *
+ * @since 1.0
+ */
+ public function getClassInfo() {
+ $classExist = true;
+
+ do {
+ $className = $this->readClassName('Enter a name for the new class:', 'Theme');
+ $ns = $this->readNamespace('Enter namespace for the class:', 'Themes\\Vuetify');
+ $classWithNs = $ns.'\\'.$className;
+ $classExist = class_exists($classWithNs);
+
+ if ($classExist) {
+ $this->error('A class in the given namespace which has the given name was found.');
+ }
+ } while ($classExist);
+ $path = ROOT_PATH.DS.trim(trim(str_replace('\\', DS, str_replace('/', DS, $ns)),'/'),'\\');
+
+ return [
+ 'name' => $className,
+ 'namespace' => $ns,
+ 'path' => $path
+ ];
+ }
+}
diff --git a/themes/vuetifyCore/cli/FooterSectionWriter.php b/Themes/VuetifyCore/Cli/FooterSectionWriter.php
similarity index 84%
rename from themes/vuetifyCore/cli/FooterSectionWriter.php
rename to Themes/VuetifyCore/Cli/FooterSectionWriter.php
index f954514..05e5832 100644
--- a/themes/vuetifyCore/cli/FooterSectionWriter.php
+++ b/Themes/VuetifyCore/Cli/FooterSectionWriter.php
@@ -1,61 +1,61 @@
-wf;
- }
- public function __construct(VuetifyThemeClassWriter $writer) {
- parent::__construct('FooterSection', $writer->getPath(), $writer->getNamespace());
-
- $this->addUseStatement('webfiori\framework\ui\WebPage');
- $this->addUseStatement('webfiori\\ui\\HTMLNode');
- $this->wf = $writer->getWireframe();
-
-
- }
-
- public function writeClassBody() {
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct',[
- 'page' => 'WebPage'
- ])
- ], 1);
- $wireframe = $this->getWireframe();
- //if ($wireframe == 'Base' || $wireframe == 'Extended Toolbar' || $wireframe == 'System Bar') {
- $this->append('parent::__construct(\'v-footer\');', 2);
- //}
- $this->append('//TODO: Add components to the footer.', 2);
- $this->append('}', 1);
- $this->append('}');
- }
-
- public function writeClassComment() {
- $this->append([
- '/**',
- ' * This class represents footer section of the theme.',
- ' */'
- ]);
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends HTMLNode {');
- }
-
-}
+wf;
+ }
+ public function __construct(VuetifyThemeClassWriter $writer) {
+ parent::__construct('FooterSection', $writer->getPath(), $writer->getNamespace());
+
+ $this->addUseStatement('WebFiori\Framework\Ui\WebPage');
+ $this->addUseStatement('WebFiori\\Ui\\HTMLNode');
+ $this->wf = $writer->getWireframe();
+
+
+ }
+
+ public function writeClassBody() {
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct',[
+ 'page' => 'WebPage'
+ ])
+ ], 1);
+ $wireframe = $this->getWireframe();
+ //if ($wireframe == 'Base' || $wireframe == 'Extended Toolbar' || $wireframe == 'System Bar') {
+ $this->append('parent::__construct(\'v-footer\');', 2);
+ //}
+ $this->append('//TODO: Add components to the footer.', 2);
+ $this->append('}', 1);
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+ $this->append([
+ '/**',
+ ' * This class represents footer section of the theme.',
+ ' */'
+ ]);
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends HTMLNode {');
+ }
+
+}
diff --git a/themes/vuetifyCore/cli/HeadSectionWriter.php b/Themes/VuetifyCore/Cli/HeadSectionWriter.php
similarity index 86%
rename from themes/vuetifyCore/cli/HeadSectionWriter.php
rename to Themes/VuetifyCore/Cli/HeadSectionWriter.php
index b27510b..f88b62b 100644
--- a/themes/vuetifyCore/cli/HeadSectionWriter.php
+++ b/Themes/VuetifyCore/Cli/HeadSectionWriter.php
@@ -1,52 +1,52 @@
-getPath(), $writer->getNamespace());
- $this->addUseStatement('webfiori\framework\ui\WebPage');
- $this->addUseStatement('webfiori\\ui\\HeadNode');
- }
- public function writeClassBody() {
-
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct',[
- 'page' => 'WebPage'
- ])
- ], 1);
- $this->append([
- 'parent::__construct();',
- "\$this->addJs('https://unpkg.com/vue@2.x.x');",
- "\$this->addCSS('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900');",
- "\$this->addCSS('https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css');",
- "\$this->addCSS('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css');",
- "\$this->addJs('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js');",
- "\$this->addJs('https://cdn.jsdelivr.net/gh/usernane/AJAXRequestJs@2.0.3/AJAXRequest.js');",
- '//TODO: Add any extra JS or Css files here in addition to meta tags.',
- ], 2);
- $this->append('}', 1);
- $this->append('}');
- }
-
- public function writeClassComment() {
- $this->append('/**');
- $this->append(' * This class represents head section the theme.');
- $this->append(' */');
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends HeadNode {');
- }
-
-}
+getPath(), $writer->getNamespace());
+ $this->addUseStatement('WebFiori\Framework\Ui\WebPage');
+ $this->addUseStatement('WebFiori\\Ui\\HeadNode');
+ }
+ public function writeClassBody() {
+
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct',[
+ 'page' => 'WebPage'
+ ])
+ ], 1);
+ $this->append([
+ 'parent::__construct();',
+ "\$this->addJs('https://unpkg.com/vue@2.x.x');",
+ "\$this->addCSS('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900');",
+ "\$this->addCSS('https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css');",
+ "\$this->addCSS('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css');",
+ "\$this->addJs('https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js');",
+ "\$this->addJs('https://cdn.jsdelivr.net/gh/usernane/AJAXRequestJs@2.0.3/AJAXRequest.js');",
+ '//TODO: Add any extra JS or Css files here in addition to meta tags.',
+ ], 2);
+ $this->append('}', 1);
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+ $this->append('/**');
+ $this->append(' * This class represents head section the theme.');
+ $this->append(' */');
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends HeadNode {');
+ }
+
+}
diff --git a/themes/vuetifyCore/cli/HeaderSectionWriter.php b/Themes/VuetifyCore/Cli/HeaderSectionWriter.php
similarity index 90%
rename from themes/vuetifyCore/cli/HeaderSectionWriter.php
rename to Themes/VuetifyCore/Cli/HeaderSectionWriter.php
index 04f0235..92fd24e 100644
--- a/themes/vuetifyCore/cli/HeaderSectionWriter.php
+++ b/Themes/VuetifyCore/Cli/HeaderSectionWriter.php
@@ -1,79 +1,79 @@
-wf;
- }
- public function __construct(VuetifyThemeClassWriter $writer) {
- parent::__construct('HeaderSection', $writer->getPath(), $writer->getNamespace());
-
- $this->addUseStatement('webfiori\framework\ui\WebPage');
- $this->addUseStatement('webfiori\\ui\\HTMLNode');
- $this->wf = $writer->getWireframe();
-
- }
-
- public function writeClassBody() {
- $wireframe = $this->getWireframe();
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct',[
- 'page' => 'WebPage'
- ])
- ], 1);
-
- if ($wireframe == 'Side Navigation' || $wireframe == 'Base' || $wireframe == 'System Bar' || $wireframe == 'Inbox') {
- $this->append('parent::__construct(\'v-app-bar\', [', 2);
- $this->append("'app'", 3);
- $this->append(']);', 2);
- $this->append("\$this->addChild('v-app-bar-nav-icon', [", 2);
- $this->append("'@click' => \"drawer = !drawer\",", 3);
- $this->append("'class' => \"d-sm-flex d-md-none\",", 3);
- $this->append("'id' => \"nav-menu-icon\",", 3);
- $this->append("]);", 2);
- $this->append("\$this->addChild('v-toolbar-title')->text(\$page->getWebsiteName());", 2);
- } else if ($wireframe == 'Extended Toolbar') {
- $this->append('parent::__construct(\'v-app-bar\', [', 2);
- $this->append("'app', 'shrink-on-scroll'", 3);
- $this->append(']);', 2);
- $this->append("\$this->addChild('v-app-bar-nav-icon', [", 2);
- $this->append("'@click' => \"drawer = !drawer\",", 3);
- $this->append("'class' => \"d-sm-flex d-md-none\",", 3);
- $this->append("'id' => \"nav-menu-icon\",", 3);
- $this->append("]);", 2);
- $this->append("\$this->addChild('v-toolbar-title')->text(\$page->getWebsiteName());", 2);
- $this->append("\$this->addChild('v-spacer');", 2);
- $this->append("\$this->addChild('v-btn', ['icon'])->addChild('v-icon')->text('mdi-dots-vertical');", 2);
- }
- $this->append('//TODO: Add components to the header.', 2);
- $this->append('}', 1);
- $this->append('}');
- }
-
- public function writeClassComment() {
- $this->append('/**');
- $this->append(' * This class represents header section the theme.');
- $this->append(' */');
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends HTMLNode {');
- }
-
-}
+wf;
+ }
+ public function __construct(VuetifyThemeClassWriter $writer) {
+ parent::__construct('HeaderSection', $writer->getPath(), $writer->getNamespace());
+
+ $this->addUseStatement('WebFiori\Framework\Ui\WebPage');
+ $this->addUseStatement('WebFiori\\Ui\\HTMLNode');
+ $this->wf = $writer->getWireframe();
+
+ }
+
+ public function writeClassBody() {
+ $wireframe = $this->getWireframe();
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct',[
+ 'page' => 'WebPage'
+ ])
+ ], 1);
+
+ if ($wireframe == 'Side Navigation' || $wireframe == 'Base' || $wireframe == 'System Bar' || $wireframe == 'Inbox') {
+ $this->append('parent::__construct(\'v-app-bar\', [', 2);
+ $this->append("'app'", 3);
+ $this->append(']);', 2);
+ $this->append("\$this->addChild('v-app-bar-nav-icon', [", 2);
+ $this->append("'@click' => \"drawer = !drawer\",", 3);
+ $this->append("'class' => \"d-sm-flex d-md-none\",", 3);
+ $this->append("'id' => \"nav-menu-icon\",", 3);
+ $this->append("]);", 2);
+ $this->append("\$this->addChild('v-toolbar-title')->text(\$page->getWebsiteName());", 2);
+ } else if ($wireframe == 'Extended Toolbar') {
+ $this->append('parent::__construct(\'v-app-bar\', [', 2);
+ $this->append("'app', 'shrink-on-scroll'", 3);
+ $this->append(']);', 2);
+ $this->append("\$this->addChild('v-app-bar-nav-icon', [", 2);
+ $this->append("'@click' => \"drawer = !drawer\",", 3);
+ $this->append("'class' => \"d-sm-flex d-md-none\",", 3);
+ $this->append("'id' => \"nav-menu-icon\",", 3);
+ $this->append("]);", 2);
+ $this->append("\$this->addChild('v-toolbar-title')->text(\$page->getWebsiteName());", 2);
+ $this->append("\$this->addChild('v-spacer');", 2);
+ $this->append("\$this->addChild('v-btn', ['icon'])->addChild('v-icon')->text('mdi-dots-vertical');", 2);
+ }
+ $this->append('//TODO: Add components to the header.', 2);
+ $this->append('}', 1);
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+ $this->append('/**');
+ $this->append(' * This class represents header section the theme.');
+ $this->append(' */');
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends HTMLNode {');
+ }
+
+}
diff --git a/themes/vuetifyCore/cli/SideSectionWriter.php b/Themes/VuetifyCore/Cli/SideSectionWriter.php
similarity index 92%
rename from themes/vuetifyCore/cli/SideSectionWriter.php
rename to Themes/VuetifyCore/Cli/SideSectionWriter.php
index e45642e..16ba0cf 100644
--- a/themes/vuetifyCore/cli/SideSectionWriter.php
+++ b/Themes/VuetifyCore/Cli/SideSectionWriter.php
@@ -1,95 +1,95 @@
-getPath(), $writer->getNamespace());
-
- $this->addUseStatement('webfiori\framework\ui\WebPage');
- $this->addUseStatement('webfiori\\ui\\HTMLNode');
- $this->wf = $writer->getWireframe();
- }
- public function getWireframe() : string {
- return $this->wf;
- }
- public function writeClassBody() {
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct',[
- 'page' => 'WebPage'
- ])
- ], 1);
- $wireframe = $this->getWireframe();
-
- if ($wireframe == 'Base'
- || $wireframe == 'Extended Toolbar'
- || $wireframe == 'System Bar') {
- $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
- $this->append("'app', 'v-model' => 'drawer'", 3);
- $this->append(']);', 2);
- } else if ($wireframe == 'Side Navigation') {
- $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
- $this->append("'app', 'mini-variant', 'v-model' => 'drawer',", 3);
- $this->append("'class' => 'pt-4', 'color' => 'grey lighten-3'", 3);
- $this->append(']);', 2);
- $this->append("\$this->addChild('v-avatar', [", 2);
- $this->append("'v-for' => 'n in 6',", 3);
- $this->append("':key' => 'n',", 3);
- $this->append("':color' => \"`grey \\\${n === 1 ? 'darken' : 'lighten'}-1`\",", 3);
- $this->append("':size' => 'n === 1 ? 36 : 20',", 3);
- $this->append("'class' => 'd-block text-center mx-auto mb-9',", 3);
- $this->append("]);", 2);
- } else if ($wireframe == 'Inbox') {
- $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
- $this->append("'app', 'v-model' => 'drawer'", 3);
- $this->append(']);', 2);
- $this->append("\$this->addChild('v-sheet', [", 2);
- $this->append("'color' => 'grey lighten-4',", 3);
- $this->append("'class' => 'pa-4',", 3);
- $this->append("])->addChild('v-avatar', [", 2);
- $this->append("'color' => 'grey darken-1',", 3);
- $this->append("'class' => 'mb-4',", 3);
- $this->append("'size' => '64',", 3);
- $this->append("])->getParent()->addChild('div')->text('my-email@xyz.com');", 2);
- $this->append("\$this->addChild('v-divider');", 2);
- $this->append("\$this->addChild('v-list')", 2);
- $this->append("->addChild('v-list-item', [", 3);
- $this->append("'v-for' => \"[icon, text] in inbox_links\"", 4);
- $this->append("])->addChild('v-list-item-icon')", 3);
- $this->append("->addChild('v-icon')->text('{{ icon }}')", 3);
- $this->append("->getParent()->getParent()->addChild('v-list-item-content')", 3);
- $this->append("->addChild('v-list-item-title')->text('{{ text }}');", 3);
- }
-
-
- $this->append('//TODO: Add components to the footer.', 2);
- $this->append('}', 1);
- $this->append('}');
- }
-
- public function writeClassComment() {
- $this->append('/**');
- $this->append(' * This class represents side section of the theme.');
- $this->append(' */');
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends HTMLNode {');
- }
-
-}
+getPath(), $writer->getNamespace());
+
+ $this->addUseStatement('WebFiori\Framework\Ui\WebPage');
+ $this->addUseStatement('WebFiori\\Ui\\HTMLNode');
+ $this->wf = $writer->getWireframe();
+ }
+ public function getWireframe() : string {
+ return $this->wf;
+ }
+ public function writeClassBody() {
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct',[
+ 'page' => 'WebPage'
+ ])
+ ], 1);
+ $wireframe = $this->getWireframe();
+
+ if ($wireframe == 'Base'
+ || $wireframe == 'Extended Toolbar'
+ || $wireframe == 'System Bar') {
+ $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
+ $this->append("'app', 'v-model' => 'drawer'", 3);
+ $this->append(']);', 2);
+ } else if ($wireframe == 'Side Navigation') {
+ $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
+ $this->append("'app', 'mini-variant', 'v-model' => 'drawer',", 3);
+ $this->append("'class' => 'pt-4', 'color' => 'grey lighten-3'", 3);
+ $this->append(']);', 2);
+ $this->append("\$this->addChild('v-avatar', [", 2);
+ $this->append("'v-for' => 'n in 6',", 3);
+ $this->append("':key' => 'n',", 3);
+ $this->append("':color' => \"`grey \\\${n === 1 ? 'darken' : 'lighten'}-1`\",", 3);
+ $this->append("':size' => 'n === 1 ? 36 : 20',", 3);
+ $this->append("'class' => 'd-block text-center mx-auto mb-9',", 3);
+ $this->append("]);", 2);
+ } else if ($wireframe == 'Inbox') {
+ $this->append('parent::__construct(\'v-navigation-drawer\', [', 2);
+ $this->append("'app', 'v-model' => 'drawer'", 3);
+ $this->append(']);', 2);
+ $this->append("\$this->addChild('v-sheet', [", 2);
+ $this->append("'color' => 'grey lighten-4',", 3);
+ $this->append("'class' => 'pa-4',", 3);
+ $this->append("])->addChild('v-avatar', [", 2);
+ $this->append("'color' => 'grey darken-1',", 3);
+ $this->append("'class' => 'mb-4',", 3);
+ $this->append("'size' => '64',", 3);
+ $this->append("])->getParent()->addChild('div')->text('my-email@xyz.com');", 2);
+ $this->append("\$this->addChild('v-divider');", 2);
+ $this->append("\$this->addChild('v-list')", 2);
+ $this->append("->addChild('v-list-item', [", 3);
+ $this->append("'v-for' => \"[icon, text] in inbox_links\"", 4);
+ $this->append("])->addChild('v-list-item-icon')", 3);
+ $this->append("->addChild('v-icon')->text('{{ icon }}')", 3);
+ $this->append("->getParent()->getParent()->addChild('v-list-item-content')", 3);
+ $this->append("->addChild('v-list-item-title')->text('{{ text }}');", 3);
+ }
+
+
+ $this->append('//TODO: Add components to the footer.', 2);
+ $this->append('}', 1);
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+ $this->append('/**');
+ $this->append(' * This class represents side section of the theme.');
+ $this->append(' */');
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends HTMLNode {');
+ }
+
+}
diff --git a/themes/vuetifyCore/cli/SysBarWriter.php b/Themes/VuetifyCore/Cli/SysBarWriter.php
similarity index 86%
rename from themes/vuetifyCore/cli/SysBarWriter.php
rename to Themes/VuetifyCore/Cli/SysBarWriter.php
index 6eaade2..27e1744 100644
--- a/themes/vuetifyCore/cli/SysBarWriter.php
+++ b/Themes/VuetifyCore/Cli/SysBarWriter.php
@@ -1,60 +1,60 @@
-getPath(), $writer->getNamespace());
-
- $this->addUseStatement('webfiori\framework\ui\WebPage');
- $this->addUseStatement('use webfiori\\ui\\HTMLNode');
- $this->wf = $writer->getWireframe();
- }
- public function getWireframe() : string {
- return $this->wf;
- }
- public function writeClassBody() {
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct',[
- 'page' => 'WebPage'
- ])
- ], 1);
- $wireframe = $this->getWireframe();
-
- $this->append('parent::__construct(\'v-system-bar\', [', 2);
- $this->append("'app'", 3);
- $this->append(']);', 2);
- $this->append("\$this->addChild('v-spacer');", 2);
- $this->append("\$this->addChild('v-icon')->text('mdi-square');", 2);
- $this->append("\$this->addChild('v-icon')->text('mdi-circle');", 2);
- $this->append("\$this->addChild('v-icon')->text('mdi-triangle');", 2);
- $this->append('}', 1);
- $this->append('}');
- }
-
- public function writeClassComment() {
- $this->append('/**');
- $this->append(' * This class represents system bar section of the theme.');
- $this->append(' */');
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends HTMLNode {');
- }
-
-}
+getPath(), $writer->getNamespace());
+
+ $this->addUseStatement('WebFiori\Framework\Ui\WebPage');
+ $this->addUseStatement('use WebFiori\\Ui\\HTMLNode');
+ $this->wf = $writer->getWireframe();
+ }
+ public function getWireframe() : string {
+ return $this->wf;
+ }
+ public function writeClassBody() {
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct',[
+ 'page' => 'WebPage'
+ ])
+ ], 1);
+ $wireframe = $this->getWireframe();
+
+ $this->append('parent::__construct(\'v-system-bar\', [', 2);
+ $this->append("'app'", 3);
+ $this->append(']);', 2);
+ $this->append("\$this->addChild('v-spacer');", 2);
+ $this->append("\$this->addChild('v-icon')->text('mdi-square');", 2);
+ $this->append("\$this->addChild('v-icon')->text('mdi-circle');", 2);
+ $this->append("\$this->addChild('v-icon')->text('mdi-triangle');", 2);
+ $this->append('}', 1);
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+ $this->append('/**');
+ $this->append(' * This class represents system bar section of the theme.');
+ $this->append(' */');
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends HTMLNode {');
+ }
+
+}
diff --git a/themes/vuetifyCore/cli/VuetifyThemeClassWriter.php b/Themes/VuetifyCore/Cli/VuetifyThemeClassWriter.php
similarity index 92%
rename from themes/vuetifyCore/cli/VuetifyThemeClassWriter.php
rename to Themes/VuetifyCore/Cli/VuetifyThemeClassWriter.php
index da80f30..5841da3 100644
--- a/themes/vuetifyCore/cli/VuetifyThemeClassWriter.php
+++ b/Themes/VuetifyCore/Cli/VuetifyThemeClassWriter.php
@@ -1,146 +1,146 @@
-wireframe = $classInfoArr['wireframe'];
- $ns = $this->getNamespace();
-
- $this->addUseStatement('themes\\vuetifyCore\\VuetifyThemeCore;');
- $this->addUseStatement('webfiori\\ui\\HTMLNode;');
- $this->addUseStatement('webfiori\ui\HeadNode');
-
- $this->addUseStatement($ns.'\\AsideSection');
- $this->addUseStatement($ns.'\\FooterSection');
- $this->addUseStatement($ns.'\\HeadSection');
- $this->addUseStatement($ns.'\\HeaderSection');
-
-
- }
- public function getWireframe() {
- return $this->wireframe;
- }
- private function writeAside() {
- $writer = new SideSectionWriter($this);
- $writer->writeClass();
- }
- private function writeFooter() {
- $writer = new FooterSectionWriter($this);
- $writer->writeClass();
- }
- private function writeHead() {
- $writer = new HeadSectionWriter($this);
- $writer->writeClass();
- }
- private function writeHeader() {
- $writer = new HeaderSectionWriter($this);
- $writer->writeClass();
- }
- private function writeSysBar() {
- $writer = new SysBarWriter($this);
- $writer->writeClass();
- }
-
- public function writeClassBody() {
- $this->append([
- "/**",
- " * Creates new instance of the class.",
- " */",
- $this->f('__construct')
- ], 1);
-
- $this->append([
- "parent::__construct('Super Theme');",
- '//TODO: Set the properties of your theme.',
- '//$this->setName(\'Super Theme\');',
- '//$this->setVersion(\'1.0\');',
- '//$this->setAuthor(\'Me\');',
- '//$this->setDescription(\'My Super Cool Theme.\');',
- '//$this->setAuthorUrl(\'https://me.com\');',
- '//$this->setLicenseName(\'MIT\');',
- '//$this->setLicenseUrl(\'https://opensource.org/licenses/MIT\');',
- '//$this->setCssDirName(\'css\');',
- '//$this->setJsDirName(\'js\');',
- '//$this->setImagesDirName(\'images\');'
- ], 2);
-
- if ($this->getWireframe() == 'System Bar' || $this->getWireframe() == 'Inbox') {
- $this->append('$this->setAfterLoaded(function ('.$this->getName().' $theme) {', 2);
- $this->append("\$theme->getPage()->getChildByID('app')->insert(new SystemBarSection(\$theme->getPage()), 0);;", 3);
- $this->append('});', 2);
- $this->writeSysBar();
- }
- $this->append('}', 1);
-
- $this->append([
- '/**',
- " * Returns an object of type 'HTMLNode' that represents aside section of the page. ",
- ' *',
- " * @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no aside",
- ' * section, the method might return null.',
- ' */',
- $this->f('getAsideNode', [], 'HTMLNode')
- ], 1);
- $this->append('return new AsideSection($this->getPage());', 2);
- $this->append('}', 1);
- $this->writeAside();
-
- $this->append([
- '/**',
- " * Returns an object of type 'HTMLNode' that represents footer section of the page.",
- ' *',
- " * @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no footer",
- ' * section, the method might return null.',
- ' */',
- $this->f('getFooterNode', [], 'HTMLNode')
- ], 1);
- $this->append('return new FooterSection($this->getPage());', 2);
- $this->append('}', 1);
- $this->writeFooter();
-
- $this->append([
- '/**',
- " * Returns an object of type HeadNode that represents HTML <head> node.",
- ' *',
- " * @return HeadNode",
- ' */',
- $this->f('getHeadNode', [], 'HeadNode')
- ], 1);
- $this->append('return new HeadSection($this->getPage());', 2);
- $this->append('}', 1);
- $this->writeHead();
-
- $this->append([
- '/**',
- " * Returns an object of type HTMLNode that represents header section of the page.",
- ' *',
- " * @return HTMLNode|null @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no header",
- ' * section, the method might return null.',
- ' */',
- $this->f('getHeaderNode', [], 'HTMLNode')
- ], 1);
- $this->append('return new HeaderSection($this->getPage());', 2);
- $this->append('}', 1);
- $this->writeHeader();
- $this->append('}');
- }
-
- public function writeClassComment() {
-
- }
-
- public function writeClassDeclaration() {
- $this->append("class ".$this->getName().' extends VuetifyThemeCore {');
- }
-
-}
+wireframe = $classInfoArr['wireframe'];
+ $ns = $this->getNamespace();
+
+ $this->addUseStatement('Themes\\VuetifyCore\\VuetifyThemeCore;');
+ $this->addUseStatement('WebFiori\\Ui\\HTMLNode;');
+ $this->addUseStatement('WebFiori\Ui\HeadNode');
+
+ $this->addUseStatement($ns.'\\AsideSection');
+ $this->addUseStatement($ns.'\\FooterSection');
+ $this->addUseStatement($ns.'\\HeadSection');
+ $this->addUseStatement($ns.'\\HeaderSection');
+
+
+ }
+ public function getWireframe() {
+ return $this->wireframe;
+ }
+ private function writeAside() {
+ $writer = new SideSectionWriter($this);
+ $writer->writeClass();
+ }
+ private function writeFooter() {
+ $writer = new FooterSectionWriter($this);
+ $writer->writeClass();
+ }
+ private function writeHead() {
+ $writer = new HeadSectionWriter($this);
+ $writer->writeClass();
+ }
+ private function writeHeader() {
+ $writer = new HeaderSectionWriter($this);
+ $writer->writeClass();
+ }
+ private function writeSysBar() {
+ $writer = new SysBarWriter($this);
+ $writer->writeClass();
+ }
+
+ public function writeClassBody() {
+ $this->append([
+ "/**",
+ " * Creates new instance of the class.",
+ " */",
+ $this->f('__construct')
+ ], 1);
+
+ $this->append([
+ "parent::__construct('Super Theme');",
+ '//TODO: Set the properties of your theme.',
+ '//$this->setName(\'Super Theme\');',
+ '//$this->setVersion(\'1.0\');',
+ '//$this->setAuthor(\'Me\');',
+ '//$this->setDescription(\'My Super Cool Theme.\');',
+ '//$this->setAuthorUrl(\'https://me.com\');',
+ '//$this->setLicenseName(\'MIT\');',
+ '//$this->setLicenseUrl(\'https://opensource.org/licenses/MIT\');',
+ '//$this->setCssDirName(\'css\');',
+ '//$this->setJsDirName(\'js\');',
+ '//$this->setImagesDirName(\'images\');'
+ ], 2);
+
+ if ($this->getWireframe() == 'System Bar' || $this->getWireframe() == 'Inbox') {
+ $this->append('$this->setAfterLoaded(function ('.$this->getName().' $theme) {', 2);
+ $this->append("\$theme->getPage()->getChildByID('app')->insert(new SystemBarSection(\$theme->getPage()), 0);;", 3);
+ $this->append('});', 2);
+ $this->writeSysBar();
+ }
+ $this->append('}', 1);
+
+ $this->append([
+ '/**',
+ " * Returns an object of type 'HTMLNode' that represents aside section of the page. ",
+ ' *',
+ " * @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no aside",
+ ' * section, the method might return null.',
+ ' */',
+ $this->f('getAsideNode', [], 'HTMLNode')
+ ], 1);
+ $this->append('return new AsideSection($this->getPage());', 2);
+ $this->append('}', 1);
+ $this->writeAside();
+
+ $this->append([
+ '/**',
+ " * Returns an object of type 'HTMLNode' that represents footer section of the page.",
+ ' *',
+ " * @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no footer",
+ ' * section, the method might return null.',
+ ' */',
+ $this->f('getFooterNode', [], 'HTMLNode')
+ ], 1);
+ $this->append('return new FooterSection($this->getPage());', 2);
+ $this->append('}', 1);
+ $this->writeFooter();
+
+ $this->append([
+ '/**',
+ " * Returns an object of type HeadNode that represents HTML <head> node.",
+ ' *',
+ " * @return HeadNode",
+ ' */',
+ $this->f('getHeadNode', [], 'HeadNode')
+ ], 1);
+ $this->append('return new HeadSection($this->getPage());', 2);
+ $this->append('}', 1);
+ $this->writeHead();
+
+ $this->append([
+ '/**',
+ " * Returns an object of type HTMLNode that represents header section of the page.",
+ ' *',
+ " * @return HTMLNode|null @return HTMLNode|null An object of type 'HTMLNode'. If the theme has no header",
+ ' * section, the method might return null.',
+ ' */',
+ $this->f('getHeaderNode', [], 'HTMLNode')
+ ], 1);
+ $this->append('return new HeaderSection($this->getPage());', 2);
+ $this->append('}', 1);
+ $this->writeHeader();
+ $this->append('}');
+ }
+
+ public function writeClassComment() {
+
+ }
+
+ public function writeClassDeclaration() {
+ $this->append("class ".$this->getName().' extends VuetifyThemeCore {');
+ }
+
+}
diff --git a/themes/vuetifyCore/CommonHead.php b/Themes/VuetifyCore/CommonHead.php
similarity index 94%
rename from themes/vuetifyCore/CommonHead.php
rename to Themes/VuetifyCore/CommonHead.php
index e749cc8..fb698a6 100644
--- a/themes/vuetifyCore/CommonHead.php
+++ b/Themes/VuetifyCore/CommonHead.php
@@ -1,137 +1,137 @@
-addJs('https://unpkg.com/ajaxrequest-helper@2.1.9/AJAXRequest.js', [
- 'integrity' => "sha256-s9Ds9XxJtxeXIpTz5boTwnVxkYJ6lQ/SlkqNsebuCjQ=",
- 'crossorigin' => "anonymous",
- 'id' => 'ajaxrequest-helper'
- ]);
-
- $this->addLink('icon', App::getConfig()->getBaseURL().'/favicon.ico', [
- 'id' => 'favicon'
- ]);
- $this->addCSS('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900');
- $this->addCSS('https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.4.47/css/materialdesignicons.min.css', [
- 'integrity' => "sha256-A/48q6BeZbFOQDUTnu6JsSvofNC880KsOIZ3Duw6mWI=",
- 'crossorigin' => "anonymous",
- 'id' => 'MaterialDesign-Webfont'
- ]);
-
- if (!(defined('TESTING') && TESTING) && !(defined('STAGING') && STAGING)) {
- $page->addBeforeRender(function (WebPage $p) {
-
- $head = $p->getDocument()->getHeadNode();
- $gtmId = $head->getGTM();
-
- if ($gtmId !== null) {
- $p->removeChild('google-tag-manager');
- $p->removeChild('google-tag-manager-noscript');
- $gtmCode = new JsCode();
- $gtmNonce = hash('sha256', microtime().''. random_bytes(10));
- $gtmCode->setAttributes([
- 'id' => 'google-tag-manager',
- 'nonce' => $gtmNonce
- ]);
- $gtmCode->addCode(""
- . "(function(w, d, s, l, i) {\n"
- . " w[l] = w[l] || [];\n"
- . " w[l].push({\n"
- . " 'gtm.start': new Date().getTime(),\n"
- . " event: 'gtm.js'\n"
- . " });\n"
- . " var f = d.getElementsByTagName(s)[0],\n"
- . " j = d.createElement(s),\n"
- . " dl = l != 'dataLayer' ? '&l=' + l : '';\n"
- . " j.async = true;\n"
- . " j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;\n"
- . " var n = d.querySelector('[nonce]');\n"
- . " n && j.setAttribute('nonce', n.nonce || n.getAttribute('nonce'));\n"
- . " f.parentNode.insertBefore(j, f);"
- . " })(window, document, 'script', 'dataLayer', '$gtmId');\n");
-
-
- $head->addChild($gtmCode);
- $noScriptGtm = new HTMLNode('noscript', [
- 'id' => 'google-tag-manager-noscript'
- ]);
-
- $noScriptGtm->addChild('iframe', [
- 'src' => "https://www.googletagmanager.com/ns.html?id=$gtmId",
- 'height' => "0",
- 'width' => "0",
- 'style' => "display:none;visibility:hidden"
- ]);
- $p->getDocument()->getBody()->insert($noScriptGtm, 0);
-
- }
-
- $searchConsoleID = $head->getGoogleSiteVerification();
-
- if ($searchConsoleID !== null) {
- $head->addMeta('google-site-verification', $searchConsoleID);
- }
-
- },100);
- };
- }
- /**
- * Returns Google Tag Manager container ID.
- *
- * A container is a collection of tags, triggers, variables, and related
- * configurations installed on a given website or mobile app
- *
- * @return string
- */
- public function getGTM() {
- return $this->gtm;
- }
- /**
- * Returns Google search console verification code.
- *
- * @return string
- */
- public function getGoogleSiteVerification() {
- return $this->googleSiteVerification;
- }
- /**
- * Sets Google Tag Manager container ID.
- *
- * This code is used to link a website with Google Tag manager.
- *
- * @param string $code
- */
- public function setGTM(string $code) {
- $this->gtm = $code;
- }
- /**
- * Sets Google search console verification code.
- *
- * This code is used to verify ownership of a domain in Google search console.
- *
- * @param string $code
- */
- public function setGoogleSiteVerification(string $code) {
- $this->googleSiteVerification = $code;
- }
-}
-
+addJs('https://unpkg.com/ajaxrequest-helper@2.1.9/AJAXRequest.js', [
+ 'integrity' => "sha256-s9Ds9XxJtxeXIpTz5boTwnVxkYJ6lQ/SlkqNsebuCjQ=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'ajaxrequest-helper'
+ ]);
+
+ $this->addLink('icon', App::getConfig()->getBaseURL().'/favicon.ico', [
+ 'id' => 'favicon'
+ ]);
+ $this->addCSS('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900');
+ $this->addCSS('https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.4.47/css/materialdesignicons.min.css', [
+ 'integrity' => "sha256-A/48q6BeZbFOQDUTnu6JsSvofNC880KsOIZ3Duw6mWI=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'MaterialDesign-Webfont'
+ ]);
+
+ if (!(defined('TESTING') && TESTING) && !(defined('STAGING') && STAGING)) {
+ $page->addBeforeRender(function (WebPage $p) {
+
+ $head = $p->getDocument()->getHeadNode();
+ $gtmId = $head->getGTM();
+
+ if ($gtmId !== null) {
+ $p->removeChild('google-tag-manager');
+ $p->removeChild('google-tag-manager-noscript');
+ $gtmCode = new JsCode();
+ $gtmNonce = hash('sha256', microtime().''. random_bytes(10));
+ $gtmCode->setAttributes([
+ 'id' => 'google-tag-manager',
+ 'nonce' => $gtmNonce
+ ]);
+ $gtmCode->addCode(""
+ . "(function(w, d, s, l, i) {\n"
+ . " w[l] = w[l] || [];\n"
+ . " w[l].push({\n"
+ . " 'gtm.start': new Date().getTime(),\n"
+ . " event: 'gtm.js'\n"
+ . " });\n"
+ . " var f = d.getElementsByTagName(s)[0],\n"
+ . " j = d.createElement(s),\n"
+ . " dl = l != 'dataLayer' ? '&l=' + l : '';\n"
+ . " j.async = true;\n"
+ . " j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;\n"
+ . " var n = d.querySelector('[nonce]');\n"
+ . " n && j.setAttribute('nonce', n.nonce || n.getAttribute('nonce'));\n"
+ . " f.parentNode.insertBefore(j, f);"
+ . " })(window, document, 'script', 'dataLayer', '$gtmId');\n");
+
+
+ $head->addChild($gtmCode);
+ $noScriptGtm = new HTMLNode('noscript', [
+ 'id' => 'google-tag-manager-noscript'
+ ]);
+
+ $noScriptGtm->addChild('iframe', [
+ 'src' => "https://www.googletagmanager.com/ns.html?id=$gtmId",
+ 'height' => "0",
+ 'width' => "0",
+ 'style' => "display:none;visibility:hidden"
+ ]);
+ $p->getDocument()->getBody()->insert($noScriptGtm, 0);
+
+ }
+
+ $searchConsoleID = $head->getGoogleSiteVerification();
+
+ if ($searchConsoleID !== null) {
+ $head->addMeta('google-site-verification', $searchConsoleID);
+ }
+
+ },100);
+ };
+ }
+ /**
+ * Returns Google Tag Manager container ID.
+ *
+ * A container is a collection of tags, triggers, variables, and related
+ * configurations installed on a given website or mobile app
+ *
+ * @return string
+ */
+ public function getGTM() {
+ return $this->gtm;
+ }
+ /**
+ * Returns Google search console verification code.
+ *
+ * @return string
+ */
+ public function getGoogleSiteVerification() {
+ return $this->googleSiteVerification;
+ }
+ /**
+ * Sets Google Tag Manager container ID.
+ *
+ * This code is used to link a website with Google Tag manager.
+ *
+ * @param string $code
+ */
+ public function setGTM(string $code) {
+ $this->gtm = $code;
+ }
+ /**
+ * Sets Google search console verification code.
+ *
+ * This code is used to verify ownership of a domain in Google search console.
+ *
+ * @param string $code
+ */
+ public function setGoogleSiteVerification(string $code) {
+ $this->googleSiteVerification = $code;
+ }
+}
+
diff --git a/themes/vuetifyCore/VueHeadSectionV2.php b/Themes/VuetifyCore/VueHeadSectionV2.php
similarity index 93%
rename from themes/vuetifyCore/VueHeadSectionV2.php
rename to Themes/VuetifyCore/VueHeadSectionV2.php
index 5ec6ca0..df39082 100644
--- a/themes/vuetifyCore/VueHeadSectionV2.php
+++ b/Themes/VuetifyCore/VueHeadSectionV2.php
@@ -1,48 +1,48 @@
-addJs("https://unpkg.com/vue@$vueVersion/dist/vue.js", [
- 'integrity' => "sha256-NrENO0kgWSpOwmwGTEKemj37RokjX9/JHhc2toHHZ4Y=",
- 'crossorigin' => "anonymous",
- 'id' => 'vue-script',
- 'version' => $vueVersion
- ]);
- } else {
- $this->addJs("https://unpkg.com/vue@$vueVersion/dist/vue.min.js", [
- 'integrity' => "sha256-PB1LDFSejenUqbr7EqtwtqGsdH0HKTuYxbJbZjKZmv0=",
- 'crossorigin' => "anonymous",
- 'id' => 'vue-script',
- 'version' => $vueVersion
- ]);
- }
-
- $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.css", [
- 'integrity' => "sha256-Y2/mvM8cPptVwHOaNUPMi+I636ATzQd9zc4vvqWIv/I=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-css',
- 'version' => $vuetifyVersion
- ]);
- $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.js", [
- 'integrity' => "sha256-CStrrGPWeCKqJCtxBeZ/UebZkA72s/hhfcQrHSYp0fs=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-script',
- 'version' => $vuetifyVersion
- ]);
- }
-}
+addJs("https://unpkg.com/vue@$vueVersion/dist/vue.js", [
+ 'integrity' => "sha256-NrENO0kgWSpOwmwGTEKemj37RokjX9/JHhc2toHHZ4Y=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vue-script',
+ 'version' => $vueVersion
+ ]);
+ } else {
+ $this->addJs("https://unpkg.com/vue@$vueVersion/dist/vue.min.js", [
+ 'integrity' => "sha256-PB1LDFSejenUqbr7EqtwtqGsdH0HKTuYxbJbZjKZmv0=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vue-script',
+ 'version' => $vueVersion
+ ]);
+ }
+
+ $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.css", [
+ 'integrity' => "sha256-Y2/mvM8cPptVwHOaNUPMi+I636ATzQd9zc4vvqWIv/I=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-css',
+ 'version' => $vuetifyVersion
+ ]);
+ $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.js", [
+ 'integrity' => "sha256-CStrrGPWeCKqJCtxBeZ/UebZkA72s/hhfcQrHSYp0fs=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-script',
+ 'version' => $vuetifyVersion
+ ]);
+ }
+}
diff --git a/themes/vuetifyCore/VueHeadSectionV3.php b/Themes/VuetifyCore/VueHeadSectionV3.php
similarity index 94%
rename from themes/vuetifyCore/VueHeadSectionV3.php
rename to Themes/VuetifyCore/VueHeadSectionV3.php
index 0fa9fbe..c40b19f 100644
--- a/themes/vuetifyCore/VueHeadSectionV3.php
+++ b/Themes/VuetifyCore/VueHeadSectionV3.php
@@ -1,61 +1,61 @@
-addJs("https://unpkg.com/vue@$vueVersion/dist/vue.global.js", [
- 'integrity' => "sha256-pMWQ5r9rnIyHnjdyvp6GlqmxIr/veom1EbAa22k8fu0=",
- 'crossorigin' => "anonymous",
- 'id' => 'vue-script',
- 'version' => $vueVersion
- ]);
-
- } else {
- $this->addJs("https://unpkg.com/vue@$vueVersion/dist/vue.global.prod.js", [
- 'integrity' => "sha256-ewTfzPdWQgxTZNeP25A9hU8AQCfVrFVIzJQA5el11nw=",
- 'crossorigin' => "anonymous",
- 'id' => 'vue-script',
- 'version' => $vueVersion
- ]);
- }
- $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.css", [
- 'integrity' => "sha256-Dlnp/rmEf5MhIrKZ5rNvXH1C+gW5S0eczEPPdHtIVDg=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-css',
- 'version' => $vuetifyVersion
- ]);
- $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify-labs.min.css", [
- 'integrity' => "sha256-SfpdqbfoTXHiaZrXGNV3D3IKogXsj99VJ1TYowZ53nw=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-labs-css',
- 'version' => $vuetifyVersion
- ]);
- $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.js", [
- 'integrity' => "sha256-f9d1J5BICD5jgnzKaWeHZL4IXPkjh04tKPQRo8T2awY=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-script',
- 'version' => $vuetifyVersion
- ]);
- $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify-labs.min.js", [
- 'integrity' => "sha256-kDjMygj+Kz7W1UO7mhNwVvKeZy99WuiDyz/CueRp5eI=",
- 'crossorigin' => "anonymous",
- 'id' => 'vuetify-labs-script',
- 'version' => $vuetifyVersion
- ]);
- }
-}
+addJs("https://unpkg.com/vue@$vueVersion/dist/vue.global.js", [
+ 'integrity' => "sha256-pMWQ5r9rnIyHnjdyvp6GlqmxIr/veom1EbAa22k8fu0=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vue-script',
+ 'version' => $vueVersion
+ ]);
+
+ } else {
+ $this->addJs("https://unpkg.com/vue@$vueVersion/dist/vue.global.prod.js", [
+ 'integrity' => "sha256-ewTfzPdWQgxTZNeP25A9hU8AQCfVrFVIzJQA5el11nw=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vue-script',
+ 'version' => $vueVersion
+ ]);
+ }
+ $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.css", [
+ 'integrity' => "sha256-Dlnp/rmEf5MhIrKZ5rNvXH1C+gW5S0eczEPPdHtIVDg=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-css',
+ 'version' => $vuetifyVersion
+ ]);
+ $this->addCSS("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify-labs.min.css", [
+ 'integrity' => "sha256-SfpdqbfoTXHiaZrXGNV3D3IKogXsj99VJ1TYowZ53nw=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-labs-css',
+ 'version' => $vuetifyVersion
+ ]);
+ $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify.min.js", [
+ 'integrity' => "sha256-f9d1J5BICD5jgnzKaWeHZL4IXPkjh04tKPQRo8T2awY=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-script',
+ 'version' => $vuetifyVersion
+ ]);
+ $this->addJs("https://cdnjs.cloudflare.com/ajax/libs/vuetify/$vuetifyVersion/vuetify-labs.min.js", [
+ 'integrity' => "sha256-kDjMygj+Kz7W1UO7mhNwVvKeZy99WuiDyz/CueRp5eI=",
+ 'crossorigin' => "anonymous",
+ 'id' => 'vuetify-labs-script',
+ 'version' => $vuetifyVersion
+ ]);
+ }
+}
diff --git a/themes/vuetifyCore/VuetifyThemeCore.php b/Themes/VuetifyCore/VuetifyThemeCore.php
similarity index 94%
rename from themes/vuetifyCore/VuetifyThemeCore.php
rename to Themes/VuetifyCore/VuetifyThemeCore.php
index a3d45d8..7f312a0 100644
--- a/themes/vuetifyCore/VuetifyThemeCore.php
+++ b/Themes/VuetifyCore/VuetifyThemeCore.php
@@ -1,75 +1,75 @@
-setVersion('1.2.5');
- $this->setAuthor('Ibrahim BinAlshikh');
- $this->setDescription('This theme creates basic page structure for '
- .'building themes which can be based on Vuetify. Vuetify is a '
- .'powerfull material design UI kit which can help in building '
- .'amazing user interface.');
- $this->setAuthorUrl('https://ibrahim-binalshikh.me');
- $this->setLicenseName('MIT');
- $this->setLicenseUrl('https://opensource.org/licenses/MIT');
- $this->setAppID('app');
-
- $this->setAfterLoaded(function (VuetifyThemeCore $theme)
- {
- $page = $theme->getPage();
- $vueEl = new HTMLNode('div', [
- 'id' => $theme->getAppID()
- ]);
- $appEl = $vueEl->addChild('v-app');
- $appEl->addChild($page->removeChild('page-header'));
- $appEl->addChild($page->removeChild('page-body'));
- $appEl->addChild($page->removeChild('page-footer'));
- $page->getDocument()->getBody()->addChild($vueEl);
- $page->getChildByID('main-content-area')->setNodeName('v-main');
- $page->getDocument()->addChild('script', [
- 'id' => 'vue-init',
- 'src' => 'https://cdn.jsdelivr.net/gh/webfiori/vuetifyCore@1.x.x/themes/vuetifyCore/default.js'
- ]);
- });
- }
- /**
- * Returns the ID of the 'div' that will be used as root Vue application.
- *
- * @return string Default return value is 'app'.
- */
- public function getAppID() {
- return $this->appElId;
- }
- /**
- * Sets the ID of the 'div' that will be used as root Vue application.
- *
- * @param string $id A non empty string.
- */
- public function setAppID($id) {
- $trimmed = trim($id);
-
- if (strlen($trimmed) > 0) {
- $this->appElId = $trimmed;
- }
- }
-}
+setVersion('1.2.5');
+ $this->setAuthor('Ibrahim BinAlshikh');
+ $this->setDescription('This theme creates basic page structure for '
+ .'building themes which can be based on Vuetify. Vuetify is a '
+ .'powerfull material design UI kit which can help in building '
+ .'amazing user interface.');
+ $this->setAuthorUrl('https://ibrahim-binalshikh.me');
+ $this->setLicenseName('MIT');
+ $this->setLicenseUrl('https://opensource.org/licenses/MIT');
+ $this->setAppID('app');
+
+ $this->setAfterLoaded(function (VuetifyThemeCore $theme)
+ {
+ $page = $theme->getPage();
+ $vueEl = new HTMLNode('div', [
+ 'id' => $theme->getAppID()
+ ]);
+ $appEl = $vueEl->addChild('v-app');
+ $appEl->addChild($page->removeChild('page-header'));
+ $appEl->addChild($page->removeChild('page-body'));
+ $appEl->addChild($page->removeChild('page-footer'));
+ $page->getDocument()->getBody()->addChild($vueEl);
+ $page->getChildByID('main-content-area')->setNodeName('v-main');
+ $page->getDocument()->addChild('script', [
+ 'id' => 'vue-init',
+ 'src' => 'https://cdn.jsdelivr.net/gh/webfiori/vuetifyCore@1.x.x/themes/vuetifyCore/default.js'
+ ]);
+ });
+ }
+ /**
+ * Returns the ID of the 'div' that will be used as root Vue application.
+ *
+ * @return string Default return value is 'app'.
+ */
+ public function getAppID() {
+ return $this->appElId;
+ }
+ /**
+ * Sets the ID of the 'div' that will be used as root Vue application.
+ *
+ * @param string $id A non empty string.
+ */
+ public function setAppID($id) {
+ $trimmed = trim($id);
+
+ if (strlen($trimmed) > 0) {
+ $this->appElId = $trimmed;
+ }
+ }
+}
diff --git a/themes/vuetifyCore/VuetifyWebPage.php b/Themes/VuetifyCore/VuetifyWebPage.php
similarity index 93%
rename from themes/vuetifyCore/VuetifyWebPage.php
rename to Themes/VuetifyCore/VuetifyWebPage.php
index 938b23b..3b0523d 100644
--- a/themes/vuetifyCore/VuetifyWebPage.php
+++ b/Themes/VuetifyCore/VuetifyWebPage.php
@@ -1,197 +1,191 @@
-addBeforeRender(function (VuetifyWebPage $p)
- {
- $p->addToJson([
- 'dir' => $p->getTranslation()->getWritingDir()
- ]);
- $p->addBeforeRender(function (VuetifyWebPage $p2) {
- $jsCode = new HTMLNode('script', [
- 'id' => 'server-json-data',
- 'nonce' => str_replace('=','',base64_encode(hash('sha256', microtime().'-'. random_bytes(10))))
- ]);
- $jsCode->text('data = '.$p2->getJson(), false);
- $p2->getDocument()->getHeadNode()->addChild($jsCode);
- },100);
- }, 100);
- $this->jsonData = new Json();
- $this->setVueScript($this->getPrimaryVueFilePath());
- }
- /**
- * Adds a set of attributes to the global 'data' JavaScript object.
- *
- * This method will add attributes to the global 'data' JsvaScript object.
- *
- * @param array $arrOfAttrs An associative array. The indices of the array
- * are attributes names and the value of each index is the value that will
- * be passed.
- */
- public function addToJson(array $arrOfAttrs) {
- foreach ($arrOfAttrs as $attrKey => $attrVal) {
- $this->getJson()->add($attrKey, $attrVal);
- }
- }
- /**
- * Adds a mixins JS file to the head tag.
- *
- * @param string $fileName The name of the mixins file such as 'add-user-mixins.js'.
- *
- * @param string|null $path An optional path that points to the location
- * of the file in public folder. If not specified, the method will use same
- * path as the primary vue script.
- */
- public function addMixins(string $fileName, ?string $path = null) {
- if ($path === null) {
- $path = $this->jsFolderPath;
- }
- if ($path === null) {
- return;
- }
- $this->addJS($path.$fileName);
- }
- /**
- * Returns an object of type Json that contains all JSON attributes which
- * will be added to the global 'data' JavaScript object.
- *
- * Initially, the object will contain all common attributes for all pages.
- *
- * @return Json
- */
- public function getJson() {
- return $this->jsonData;
- }
- /**
- * Sets the JavaScript file which will be used to initialize vue.
- *
- * @param string $jsFilePath A string that represents the path of the
- * file such as 'assets/js/init-vue.js'.
- */
- public function setVueScript($jsFilePath) {
- if ($this->jsScriptRender === null) {
- $this->jsScriptRender = $this->addBeforeRender(function (){}, 0);
- }
- $this->jsScriptRender->setCallback(function (WebPage $page, string $jsPath) {
- $base = $page->getBase();
-
- if (!strpos($jsPath, $base) === false) {
- $jsPath = trim($base,"/").'/'.trim($jsPath, "/");
- }
- $page->removeChild('vue-init');
- $page->getDocument()->addChild('script', [
- 'type' => 'text/javascript',
- 'src' => $jsPath.'?jv='.App::getConfig()->getAppVersion(),
- 'id' => 'vue-init'
- ]);
- }, [$jsFilePath]);
- }
- /**
- * Constructs and returns a default path for the primary JavaScript file
- * that has code which is used to initialize vue application.
- *
- * The method will construct the path as follows, first, it will take
- * the name of the class, including namestace and convert it to kebab
- * case and convert all characters to lower case.
- *
- * Note that the method assumes that the class is created inside the folder
- * '[APP_DIR]/pages' of the application. Also, it assumes that the JS file
- * will be inside the folder '[public-folder]/assets/js'.
- *
- *
- * @return string A string such as 'assets/js/my-page.js'.
- */
- public function getPrimaryVueFilePath() {
- $pagesFolder = APP_DIR.'\\'.'pages';
- $clazz = static::class;
- $expl = explode('\\', $clazz);
- $className = $expl[count($expl) - 1];
- $fileName = CaseConverter::toKebabCase($className, 'lower').'.js';
- $trim1 = substr($clazz, strlen($pagesFolder));
- $this->jsFolderPath = 'assets/js'.str_replace('\\', '/', substr($trim1, 0, -1*strlen($className)));
-
- return $this->jsFolderPath.$fileName;
- }
- /**
- * Converts an array of labels to JSON objects which could be used as items
- * for selects or auto-complete components of Vuetify.
- *
- * @param string|array $labelOrArrOfLabels A label location which exist in the language class.
- * Also, this can be an array that holds the labels.
- *
- * @param array $extraAttrs An associative array that holds extra
- * attributes to set for an item. The indices of the array should
- * represent the key and the value is a sub-associative array of
- * values.
- *
- * @return array The method will return an array that holds objects of type
- * Json. Each object will have at least two attributes, 'value'
- * and 'text'. The object may have extra attributes based on what values
- * passed in the array $extraAttrs .
- */
- public function toVItems($labelOrArrOfLabels, array $extraAttrs = []) {
- if (gettype($labelOrArrOfLabels) == 'array') {
- $data = $labelOrArrOfLabels;
- } else {
- $data = $this->get($labelOrArrOfLabels);
- }
- $retVal = [];
-
- if (gettype($data) == 'array') {
- foreach ($data as $key => $lbl) {
- $jsonItem = new Json([
- 'text' => $lbl,
- 'value' => $key,
- 'title' => $lbl,
- 'key' => $key
- ]);
-
- if (isset($extraAttrs[$key]) && gettype($extraAttrs[$key]) == 'array') {
- foreach ($extraAttrs[$key] as $itemKey => $val) {
- $jsonItem->add($itemKey, $val);
- }
- }
- $retVal[] = $jsonItem;
- }
- }
-
- return $retVal;
- }
-}
+addBeforeRender(function (VuetifyWebPage $p)
+ {
+ $p->addToJson([
+ 'dir' => $p->getTranslation()->getWritingDir()
+ ]);
+ $p->addBeforeRender(function (VuetifyWebPage $p2) {
+ $jsCode = new HTMLNode('script', [
+ 'id' => 'server-json-data',
+ 'nonce' => str_replace('=','',base64_encode(hash('sha256', microtime().'-'. random_bytes(10))))
+ ]);
+ $jsCode->text('data = '.$p2->getJson(), false);
+ $p2->getDocument()->getHeadNode()->addChild($jsCode);
+ },100);
+ }, 100);
+ $this->jsonData = new Json();
+ $this->setVueScript($this->getPrimaryVueFilePath());
+ }
+ /**
+ * Adds a set of attributes to the global 'data' JavaScript object.
+ *
+ * This method will add attributes to the global 'data' JsvaScript object.
+ *
+ * @param array $arrOfAttrs An associative array. The indices of the array
+ * are attributes names and the value of each index is the value that will
+ * be passed.
+ */
+ public function addToJson(array $arrOfAttrs) {
+ foreach ($arrOfAttrs as $attrKey => $attrVal) {
+ $this->getJson()->add($attrKey, $attrVal);
+ }
+ }
+ /**
+ * Adds a mixins JS file to the head tag.
+ *
+ * @param string $fileName The name of the mixins file such as 'add-user-mixins.js'.
+ *
+ * @param string|null $path An optional path that points to the location
+ * of the file in public folder. If not specified, the method will use same
+ * path as the primary vue script.
+ */
+ public function addMixins(string $fileName, ?string $path = null) {
+ if ($path === null) {
+ $path = $this->jsFolderPath;
+ }
+ if ($path === null) {
+ return;
+ }
+ $this->addJS($path.$fileName);
+ }
+ /**
+ * Returns an object of type Json that contains all JSON attributes which
+ * will be added to the global 'data' JavaScript object.
+ *
+ * Initially, the object will contain all common attributes for all pages.
+ *
+ * @return Json
+ */
+ public function getJson() {
+ return $this->jsonData;
+ }
+ /**
+ * Sets the JavaScript file which will be used to initialize vue.
+ *
+ * @param string $jsFilePath A string that represents the path of the
+ * file such as 'assets/js/init-vue.js'.
+ */
+ public function setVueScript($jsFilePath) {
+
+ $this->addBeforeRender(function (WebPage $page, string $jsPath)
+ {
+ $base = $page->getBase();
+
+ if (!strpos($jsPath, $base) === false) {
+ $jsPath = trim($base,"/").'/'.trim($jsPath, "/");
+ }
+ $page->removeChild('vue-init');
+ $page->getDocument()->addChild('script', [
+ 'type' => 'text/javascript',
+ 'src' => $jsPath.'?jv='.App::getConfig()->getAppVersion(),
+ 'id' => 'vue-init'
+ ]);
+ }, 0, [$jsFilePath]);
+ }
+ /**
+ * Constructs and returns a default path for the primary JavaScript file
+ * that has code which is used to initialize vue application.
+ *
+ * The method will construct the path as follows, first, it will take
+ * the name of the class, including namestace and convert it to kebab
+ * case and convert all characters to lower case.
+ *
+ * Note that the method assumes that the class is created inside the folder
+ * '[APP_DIR]/pages' of the application. Also, it assumes that the JS file
+ * will be inside the folder '[public-folder]/assets/js'.
+ *
+ *
+ * @return string A string such as 'assets/js/my-page.js'.
+ */
+ public function getPrimaryVueFilePath() {
+ $pagesFolder = APP_DIR.'\\'.'pages';
+ $clazz = static::class;
+ $expl = explode('\\', $clazz);
+ $className = $expl[count($expl) - 1];
+ $fileName = CaseConverter::toKebabCase($className, 'lower').'.js';
+ $trim1 = substr($clazz, strlen($pagesFolder));
+ $this->jsFolderPath = 'assets/js'.str_replace('\\', '/', substr($trim1, 0, -1*strlen($className)));
+
+ return $this->jsFolderPath.$fileName;
+ }
+ /**
+ * Converts an array of labels to JSON objects which could be used as items
+ * for selects or auto-complete components of Vuetify.
+ *
+ * @param string|array $labelOrArrOfLabels A label location which exist in the language class.
+ * Also, this can be an array that holds the labels.
+ *
+ * @param array $extraAttrs An associative array that holds extra
+ * attributes to set for an item. The indices of the array should
+ * represent the key and the value is a sub-associative array of
+ * values.
+ *
+ * @return array The method will return an array that holds objects of type
+ * Json. Each object will have at least two attributes, 'value'
+ * and 'text'. The object may have extra attributes based on what values
+ * passed in the array $extraAttrs .
+ */
+ public function toVItems($labelOrArrOfLabels, array $extraAttrs = []) {
+ if (gettype($labelOrArrOfLabels) == 'array') {
+ $data = $labelOrArrOfLabels;
+ } else {
+ $data = $this->get($labelOrArrOfLabels);
+ }
+ $retVal = [];
+
+ if (gettype($data) == 'array') {
+ foreach ($data as $key => $lbl) {
+ $jsonItem = new Json([
+ 'text' => $lbl,
+ 'value' => $key,
+ 'title' => $lbl,
+ 'key' => $key
+ ]);
+
+ if (isset($extraAttrs[$key]) && gettype($extraAttrs[$key]) == 'array') {
+ foreach ($extraAttrs[$key] as $itemKey => $val) {
+ $jsonItem->add($itemKey, $val);
+ }
+ }
+ $retVal[] = $jsonItem;
+ }
+ }
+
+ return $retVal;
+ }
+}
diff --git a/themes/vuetifyCore/default.js b/Themes/VuetifyCore/default.js
similarity index 100%
rename from themes/vuetifyCore/default.js
rename to Themes/VuetifyCore/default.js
diff --git a/bootstrap.php b/bootstrap.php
deleted file mode 100644
index 35167fd..0000000
--- a/bootstrap.php
+++ /dev/null
@@ -1,101 +0,0 @@
- [
- 'tests',
- 'webfiori',
- 'vendor',
- 'app'
- ],
- 'define-root' => true,
- 'root' => __DIR__,
- 'on-load-failure' => 'do-nothing'
-]);
-fprintf(STDOUT,'Autoloader Initialized.'."\n");
-fprintf(STDOUT,'Class Search Paths:'."\n");
-$dirs = AutoLoader::getFolders();
-
-foreach ($dirs as $dir) {
- fprintf(STDOUT, $dir."\n");
-}
-
-fprintf(STDOUT,"Initializing application...\n");
-App::start();
-fprintf(STDOUT,'Done.'."\n");
-fprintf(STDOUT,'Root Directory: \''.AutoLoader::get()->root().'\'.'."\n");
-define('TESTS_PATH', AutoLoader::get()->root().$DS.TESTS_DIRECTORY);
-
-fprintf(STDOUT, "Registering shutdown function...\n");
-//run code after tests completion.
-register_shutdown_function(function()
-{
- $sessionDb = new webfiori\framework\session\DatabaseSessionStorage();
- $sessionDb->dropTables();
- ConfigController::get()->removeConfigFiles();
-});
-fprintf(STDOUT, "Registering shutdown function completed.\n");
-fprintf(STDOUT,"Starting to run tests...\n");
diff --git a/composer.json b/composer.json
index c1db419..a68968d 100644
--- a/composer.json
+++ b/composer.json
@@ -13,10 +13,16 @@
}
],
"require": {
- "php": ">=8.0"
+ "webfiori/framework":"dev-main"
},
"require-dev": {
- "webfiori/framework":"*"
+ "phpunit/phpunit": "^10",
+ "friendsofphp/php-cs-fixer": "^3.86"
+ },
+ "autoload": {
+ "psr-4": {
+ "Themes\\": "Themes/"
+ }
},
"keywords": [
"framework",
@@ -28,5 +34,10 @@
"Vuetify",
"Vue"
],
- "license": "MIT"
+ "license": "MIT",
+ "scripts":{
+ "test": "vendor/bin/phpunit -c tests/phpunit.xml",
+ "test10": "vendor/bin/phpunit -c tests/phpunit10.xml",
+ "fix-cs": "vendor/bin/php-cs-fixer fix --config=php_cs.php.dist"
+ }
}
diff --git a/composer.lock b/composer.lock
index f4401d2..5529e0b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,30 +4,127 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "02dec0e606332acf15990a29456117eb",
- "packages": [],
- "packages-dev": [
+ "content-hash": "fbb352c9a2bed0bdbc2c0bacf7fccb05",
+ "packages": [
+ {
+ "name": "webfiori/cache",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WebFiori/cache.git",
+ "reference": "5ab55bc0e0b9ba14c3d9870d29cefb94a8b9d59d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WebFiori/cache/zipball/5ab55bc0e0b9ba14c3d9870d29cefb94a8b9d59d",
+ "reference": "5ab55bc0e0b9ba14c3d9870d29cefb94a8b9d59d",
+ "shasum": ""
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Cache\\": "WebFiori/Cache/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple caching engine which is highly customizable.",
+ "keywords": [
+ "cache",
+ "customizable",
+ "file cache"
+ ],
+ "support": {
+ "issues": "https://github.com/WebFiori/cache/issues",
+ "source": "https://github.com/WebFiori/cache/tree/v2.0.0"
+ },
+ "time": "2025-08-25T22:30:26+00:00"
+ },
+ {
+ "name": "webfiori/cli",
+ "version": "v2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WebFiori/cli.git",
+ "reference": "d7772d9ace6ca922dcaef04ae0c2450b90102b3c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WebFiori/cli/zipball/d7772d9ace6ca922dcaef04ae0c2450b90102b3c",
+ "reference": "d7772d9ace6ca922dcaef04ae0c2450b90102b3c",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1",
+ "webfiori/file": "2.0.*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.86",
+ "phpunit/phpunit": "^10.0"
+ },
+ "bin": [
+ "bin/wfc"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Cli\\": "WebFiori/Cli"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ibrahim",
+ "email": "ibrahim@webfiori.com"
+ }
+ ],
+ "description": "Class library to simplify the process of creating command line based applications using PHP.",
+ "keywords": [
+ "cli",
+ "command line",
+ "php",
+ "terminal"
+ ],
+ "support": {
+ "issues": "https://github.com/WebFiori/cli/issues",
+ "source": "https://github.com/WebFiori/cli/tree/v2.0.1"
+ },
+ "time": "2025-10-06T14:09:41+00:00"
+ },
{
"name": "webfiori/collections",
- "version": "v1.0.3",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/collections.git",
- "reference": "ac072ab441c7635d94e60e095402023a59667bff"
+ "reference": "9345cca4dd6cb739fb471db835029f81fab1caa6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/collections/zipball/ac072ab441c7635d94e60e095402023a59667bff",
- "reference": "ac072ab441c7635d94e60e095402023a59667bff",
+ "url": "https://api.github.com/repos/WebFiori/collections/zipball/9345cca4dd6cb739fb471db835029f81fab1caa6",
+ "reference": "9345cca4dd6cb739fb471db835029f81fab1caa6",
"shasum": ""
},
"require": {
- "php": ">=5.6"
+ "php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^5"
+ "phpunit/phpunit": "^10"
},
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Collections\\": "WebFiori/Collections/"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -42,25 +139,40 @@
],
"support": {
"issues": "https://github.com/WebFiori/collections/issues",
- "source": "https://github.com/WebFiori/collections/tree/v1.0.3"
+ "source": "https://github.com/WebFiori/collections/tree/v2.0.0"
},
- "time": "2021-03-28T14:22:48+00:00"
+ "time": "2025-08-21T14:56:08+00:00"
},
{
"name": "webfiori/database",
- "version": "v0.3.9",
+ "version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/database.git",
- "reference": "739c9e482ca1ebda2eb8ba226cf9b561a5351b98"
+ "reference": "d13abfcb63d238a95c4b0c177eaf1eb2e5015415"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/database/zipball/739c9e482ca1ebda2eb8ba226cf9b561a5351b98",
- "reference": "739c9e482ca1ebda2eb8ba226cf9b561a5351b98",
+ "url": "https://api.github.com/repos/WebFiori/database/zipball/d13abfcb63d238a95c4b0c177eaf1eb2e5015415",
+ "reference": "d13abfcb63d238a95c4b0c177eaf1eb2e5015415",
"shasum": ""
},
+ "require": {
+ "ext-mysqli": "*",
+ "ext-sqlsrv": "*",
+ "php": ">=8.1",
+ "webfiori/jsonx": "*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.86",
+ "phpunit/phpunit": "^10"
+ },
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Database\\": "WebFiori/Database"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -75,47 +187,154 @@
],
"support": {
"issues": "https://github.com/WebFiori/database/issues",
- "source": "https://github.com/WebFiori/database/tree/v0.3.9"
+ "source": "https://github.com/WebFiori/database/tree/v1.1.0"
},
- "funding": [
- {
- "url": "https://paypal.me/IbrahimBinAlshikh",
- "type": "custom"
- },
+ "time": "2025-09-29T16:28:23+00:00"
+ },
+ {
+ "name": "webfiori/err",
+ "version": "v2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WebFiori/err.git",
+ "reference": "9ffb01a5fd44fe9a03fcb20b6547c7dddc40989c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WebFiori/err/zipball/9ffb01a5fd44fe9a03fcb20b6547c7dddc40989c",
+ "reference": "9ffb01a5fd44fe9a03fcb20b6547c7dddc40989c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.86",
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Error\\": "WebFiori/Error/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://www.buymeacoffee.com/ibrahimdev",
- "type": "custom"
- },
+ "name": "Ibrahim BinAlshikh",
+ "email": "ibrahim@webfiori.com"
+ }
+ ],
+ "description": "A library for handling PHP errors and exceptions in a better way.",
+ "keywords": [
+ "error",
+ "error handler",
+ "errors",
+ "exception",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/WebFiori/err/issues",
+ "source": "https://github.com/WebFiori/err/tree/v2.0.1"
+ },
+ "time": "2025-10-02T08:56:56+00:00"
+ },
+ {
+ "name": "webfiori/file",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WebFiori/file.git",
+ "reference": "904c9ffa9432d04ac1d536e5a707fd43c84b40e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WebFiori/file/zipball/904c9ffa9432d04ac1d536e5a707fd43c84b40e5",
+ "reference": "904c9ffa9432d04ac1d536e5a707fd43c84b40e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0",
+ "webfiori/jsonx": "4.0.x"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "webfiori/http": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\File\\": "WebFiori/File/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
{
- "url": "https://ko-fi.com/ibrahimdev",
- "type": "ko_fi"
+ "name": "Ibrahim BinAlshikh",
+ "email": "ibrahim@webfiori.com"
}
],
- "time": "2022-01-30T10:52:15+00:00"
+ "description": "Basic class library to read, write and view files using PHP.",
+ "keywords": [
+ "file",
+ "files",
+ "php",
+ "upload",
+ "uploading"
+ ],
+ "support": {
+ "issues": "https://github.com/WebFiori/file/issues",
+ "source": "https://github.com/WebFiori/file/tree/v2.0.0"
+ },
+ "time": "2025-08-06T22:16:05+00:00"
},
{
"name": "webfiori/framework",
- "version": "v2.4.7",
+ "version": "dev-main",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/framework.git",
- "reference": "e5d469150593add45441e08618dd5ff820638f2b"
+ "reference": "22433ff2b3e87a952adc1356bc4776850e80a405"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/framework/zipball/e5d469150593add45441e08618dd5ff820638f2b",
- "reference": "e5d469150593add45441e08618dd5ff820638f2b",
+ "url": "https://api.github.com/repos/WebFiori/framework/zipball/22433ff2b3e87a952adc1356bc4776850e80a405",
+ "reference": "22433ff2b3e87a952adc1356bc4776850e80a405",
"shasum": ""
},
"require": {
- "php": ">=5.6",
- "webfiori/collections": "1.0.3",
- "webfiori/database": "0.3.9",
- "webfiori/http": "3.1.1",
- "webfiori/jsonx": "3.0.0",
- "webfiori/ui": "2.2.3"
+ "ext-fileinfo": "*",
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "ext-openssl": "*",
+ "php": ">=8.1",
+ "webfiori/cache": "v2.0.*",
+ "webfiori/cli": "v2.0.*",
+ "webfiori/collections": "v2.0.*",
+ "webfiori/database": "v1.1.*",
+ "webfiori/err": "v2.0.*",
+ "webfiori/file": "v2.0.*",
+ "webfiori/http": "v4.0.*",
+ "webfiori/jsonx": "v4.0.*",
+ "webfiori/mailer": "v2.1.*",
+ "webfiori/ui": "v4.0.*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
},
+ "default-branch": true,
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Framework\\": "WebFiori/Framework/"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -123,10 +342,13 @@
"authors": [
{
"name": "Ibrahim BinAlshikh",
- "email": "ibrahim@webfiori.com"
+ "email": "ibrahim@webfiori.com",
+ "homepage": "https://ibrahim-binalshikh.me",
+ "role": "Maintainer"
}
],
"description": "WebFiori framework. Made to make the web bloom.",
+ "homepage": "https://webfiori.com",
"keywords": [
"Web APIs",
"api",
@@ -136,8 +358,8 @@
"webfiori"
],
"support": {
- "issues": "https://github.com/WebFiori/framework/issues",
- "source": "https://github.com/WebFiori/framework/tree/v2.4.7"
+ "issues": "https://github.com/webfiori/framework/issues",
+ "source": "https://github.com/webfior/framework"
},
"funding": [
{
@@ -153,30 +375,37 @@
"type": "ko_fi"
}
],
- "time": "2022-01-31T08:42:43+00:00"
+ "time": "2025-10-09T12:35:04+00:00"
},
{
"name": "webfiori/http",
- "version": "v3.1.1",
+ "version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/http.git",
- "reference": "1cee0781ac7c3bfdee1f8385977630dca576dd87"
+ "reference": "b9eb529784cbec7a9c74fdf6a30efe0098f11ca8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/http/zipball/1cee0781ac7c3bfdee1f8385977630dca576dd87",
- "reference": "1cee0781ac7c3bfdee1f8385977630dca576dd87",
+ "url": "https://api.github.com/repos/WebFiori/http/zipball/b9eb529784cbec7a9c74fdf6a30efe0098f11ca8",
+ "reference": "b9eb529784cbec7a9c74fdf6a30efe0098f11ca8",
"shasum": ""
},
"require": {
- "php": ">=5.6",
- "webfiori/jsonx": "*"
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "php": ">=7.0",
+ "webfiori/jsonx": "4.0.x"
},
"require-dev": {
- "phpunit/phpunit": "^5"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Http\\": "WebFiori/Http"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -187,13 +416,14 @@
"api",
"http",
"json",
+ "jsonx",
"library",
"php",
"psr-7"
],
"support": {
"issues": "https://github.com/WebFiori/http/issues",
- "source": "https://github.com/WebFiori/http/tree/v3.1.1"
+ "source": "https://github.com/WebFiori/http/tree/v4.0.0"
},
"funding": [
{
@@ -201,29 +431,34 @@
"type": "custom"
}
],
- "time": "2021-10-25T12:42:25+00:00"
+ "time": "2025-08-06T20:32:03+00:00"
},
{
"name": "webfiori/jsonx",
- "version": "v3.0.0",
+ "version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/json.git",
- "reference": "f5fe3f44a57e785f999d3c951aa57f15d5769619"
+ "reference": "d1605b5025ffec5a48a4b0330208c09631900a03"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/json/zipball/f5fe3f44a57e785f999d3c951aa57f15d5769619",
- "reference": "f5fe3f44a57e785f999d3c951aa57f15d5769619",
+ "url": "https://api.github.com/repos/WebFiori/json/zipball/d1605b5025ffec5a48a4b0330208c09631900a03",
+ "reference": "d1605b5025ffec5a48a4b0330208c09631900a03",
"shasum": ""
},
"require": {
- "php": ">=5.6"
+ "php": ">=8.0"
},
"require-dev": {
- "phpunit/phpunit": "^5"
+ "phpunit/phpunit": "^10.0"
},
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Json\\": "WebFiori/Json"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -231,11 +466,12 @@
"description": "PHP library for creating well-formatted JSON strings.",
"keywords": [
"json",
+ "jsonx",
"php"
],
"support": {
"issues": "https://github.com/WebFiori/json/issues",
- "source": "https://github.com/WebFiori/json/tree/v3.0.0"
+ "source": "https://github.com/WebFiori/json/tree/v4.0.0"
},
"funding": [
{
@@ -243,30 +479,90 @@
"type": "custom"
}
],
- "time": "2021-12-27T14:24:38+00:00"
+ "time": "2025-08-03T15:19:48+00:00"
+ },
+ {
+ "name": "webfiori/mailer",
+ "version": "2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WebFiori/mail.git",
+ "reference": "3aa18195717efcb5a069af47c8620062231a0901"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WebFiori/mail/zipball/3aa18195717efcb5a069af47c8620062231a0901",
+ "reference": "3aa18195717efcb5a069af47c8620062231a0901",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "webfiori/file": "2.0.*",
+ "webfiori/ui": "4.0.*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.86",
+ "phpunit/phpunit": "^10",
+ "webfiori/oauth": "1.0.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Mail\\": "WebFiori/Mail/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ibrahim BinAlshikh",
+ "email": "ibrahim@webfiori.com"
+ }
+ ],
+ "description": "Sockets-based library for sending HTML email messages.",
+ "keywords": [
+ "email",
+ "html",
+ "mail",
+ "php",
+ "sockets"
+ ],
+ "support": {
+ "issues": "https://github.com/WebFiori/mail/issues",
+ "source": "https://github.com/WebFiori/mail/tree/v2.1.0"
+ },
+ "time": "2025-10-07T22:13:09+00:00"
},
{
"name": "webfiori/ui",
- "version": "v2.2.3",
+ "version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/WebFiori/ui.git",
- "reference": "36b75e939d015867768430d51126f443efd9f237"
+ "reference": "95b6bd5860584278577aeb603d4b2f6c576d901a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/WebFiori/ui/zipball/36b75e939d015867768430d51126f443efd9f237",
- "reference": "36b75e939d015867768430d51126f443efd9f237",
+ "url": "https://api.github.com/repos/WebFiori/ui/zipball/95b6bd5860584278577aeb603d4b2f6c576d901a",
+ "reference": "95b6bd5860584278577aeb603d4b2f6c576d901a",
"shasum": ""
},
"require": {
- "php": ">=5.6",
- "webfiori/collections": "1.0.3"
+ "php": ">=8.1",
+ "webfiori/collections": "2.0.x"
},
"require-dev": {
- "phpunit/phpunit": "^5"
+ "friendsofphp/php-cs-fixer": "^3.86",
+ "phpunit/phpunit": "^10"
},
"type": "library",
+ "autoload": {
+ "psr-4": {
+ "WebFiori\\Ui\\": "WebFiori/Ui/"
+ }
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@@ -281,25 +577,4283 @@
],
"support": {
"issues": "https://github.com/WebFiori/ui/issues",
- "source": "https://github.com/WebFiori/ui/tree/v2.2.3"
+ "source": "https://github.com/WebFiori/ui/tree/v4.0.0"
+ },
+ "time": "2025-10-07T21:08:40+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "clue/ndjson-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-ndjson.git",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0",
+ "reference": "392dc165fce93b5bb5c637b67e59619223c931b0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\NDJson\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-ndjson",
+ "keywords": [
+ "NDJSON",
+ "json",
+ "jsonlines",
+ "newline",
+ "reactphp",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-ndjson/issues",
+ "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0"
},
"funding": [
{
- "url": "https://paypal.me/IbrahimBinAlshikh",
+ "url": "https://clue.engineering/support",
"type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
}
],
- "time": "2021-12-07T21:28:53+00:00"
- }
- ],
- "aliases": [],
- "minimum-stability": "stable",
- "stability-flags": {},
- "prefer-stable": false,
- "prefer-lowest": false,
- "platform": {
- "php": ">=8.0"
- },
+ "time": "2022-12-23T10:58:28+00:00"
+ },
+ {
+ "name": "composer/pcre",
+ "version": "3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-12T16:29:46+00:00"
+ },
+ {
+ "name": "composer/semver",
+ "version": "3.4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/semver.git",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.11",
+ "symfony/phpunit-bridge": "^3 || ^7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Semver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "Semver library that offers utilities, version constraint parsing and validation.",
+ "keywords": [
+ "semantic",
+ "semver",
+ "validation",
+ "versioning"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/semver/issues",
+ "source": "https://github.com/composer/semver/tree/3.4.4"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-20T19:15:30+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-06T16:37:16+00:00"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Evenement\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
+ },
+ {
+ "name": "fidry/cpu-core-counter",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theofidry/cpu-core-counter.git",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "fidry/makefile": "^0.2.0",
+ "fidry/php-cs-fixer-config": "^1.1.2",
+ "phpstan/extension-installer": "^1.2.0",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^8.5.31 || ^9.5.26",
+ "webmozarts/strict-phpunit": "^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Fidry\\CpuCoreCounter\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Théo FIDRY",
+ "email": "theo.fidry@gmail.com"
+ }
+ ],
+ "description": "Tiny utility to get the number of CPU cores.",
+ "keywords": [
+ "CPU",
+ "core"
+ ],
+ "support": {
+ "issues": "https://github.com/theofidry/cpu-core-counter/issues",
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theofidry",
+ "type": "github"
+ }
+ ],
+ "time": "2025-08-14T07:29:31+00:00"
+ },
+ {
+ "name": "friendsofphp/php-cs-fixer",
+ "version": "v3.88.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
+ "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99",
+ "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99",
+ "shasum": ""
+ },
+ "require": {
+ "clue/ndjson-react": "^1.3",
+ "composer/semver": "^3.4",
+ "composer/xdebug-handler": "^3.0.5",
+ "ext-filter": "*",
+ "ext-hash": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "fidry/cpu-core-counter": "^1.3",
+ "php": "^7.4 || ^8.0",
+ "react/child-process": "^0.6.6",
+ "react/event-loop": "^1.5",
+ "react/promise": "^3.3",
+ "react/socket": "^1.16",
+ "react/stream": "^1.4",
+ "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
+ "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0",
+ "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0",
+ "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0",
+ "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0",
+ "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0",
+ "symfony/polyfill-mbstring": "^1.33",
+ "symfony/polyfill-php80": "^1.33",
+ "symfony/polyfill-php81": "^1.33",
+ "symfony/polyfill-php84": "^1.33",
+ "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2",
+ "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0"
+ },
+ "require-dev": {
+ "facile-it/paraunit": "^1.3.1 || ^2.7",
+ "infection/infection": "^0.31.0",
+ "justinrainbow/json-schema": "^6.5",
+ "keradus/cli-executor": "^2.2",
+ "mikey179/vfsstream": "^1.6.12",
+ "php-coveralls/php-coveralls": "^2.8",
+ "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
+ "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
+ "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
+ "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2",
+ "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2"
+ },
+ "suggest": {
+ "ext-dom": "For handling output formats in XML",
+ "ext-mbstring": "For handling non-UTF8 characters."
+ },
+ "bin": [
+ "php-cs-fixer"
+ ],
+ "type": "application",
+ "autoload": {
+ "psr-4": {
+ "PhpCsFixer\\": "src/"
+ },
+ "exclude-from-classmap": [
+ "src/Fixer/Internal/*"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Dariusz Rumiński",
+ "email": "dariusz.ruminski@gmail.com"
+ }
+ ],
+ "description": "A tool to automatically fix PHP code style",
+ "keywords": [
+ "Static code analysis",
+ "fixer",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
+ "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/keradus",
+ "type": "github"
+ }
+ ],
+ "time": "2025-09-27T00:24:15+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.13.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-01T08:46:24+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
+ },
+ "time": "2025-08-13T20:13:15+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
+ },
+ "dist": {
+ "type": "zip",
+ "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",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "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.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "10.1.16",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
+ "php": ">=8.1",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "sebastian/code-unit-reverse-lookup": "^3.0.0",
+ "sebastian/complexity": "^3.2.0",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/lines-of-code": "^2.0.2",
+ "sebastian/version": "^4.0.1",
+ "theseer/tokenizer": "^1.2.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.1"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "10.1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "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/10.1.16"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-08-22T04:31:57+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-31T06:24:48+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^10.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:56:09+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-31T14:07:24+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:57:52+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "10.5.58",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca",
+ "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.1",
+ "phpunit/php-code-coverage": "^10.1.16",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-invoker": "^4.0.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "phpunit/php-timer": "^6.0.0",
+ "sebastian/cli-parser": "^2.0.1",
+ "sebastian/code-unit": "^2.0.0",
+ "sebastian/comparator": "^5.0.4",
+ "sebastian/diff": "^5.1.1",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/exporter": "^5.1.4",
+ "sebastian/global-state": "^6.0.2",
+ "sebastian/object-enumerator": "^5.0.0",
+ "sebastian/recursion-context": "^5.0.1",
+ "sebastian/type": "^4.0.0",
+ "sebastian/version": "^4.0.1"
+ },
+ "suggest": {
+ "ext-soap": "To be able to generate mocks based on WSDL files"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "10.5-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-28T12:04:46+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Standard interfaces for event handling.",
+ "keywords": [
+ "events",
+ "psr",
+ "psr-14"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2022-11-30T15:59:55+00:00"
+ },
+ {
+ "name": "react/child-process",
+ "version": "v0.6.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159",
+ "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/socket": "^1.16",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\ChildProcess\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven library for executing child processes with ReactPHP.",
+ "keywords": [
+ "event-driven",
+ "process",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/child-process/issues",
+ "source": "https://github.com/reactphp/child-process/tree/v0.6.6"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-01-01T16:37:48+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.13.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
+ "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.7 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3 || ^2",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.13.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-13T14:18:03+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
+ "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "suggest": {
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-11-13T13:48:05+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "1.12.28 || 1.4.10",
+ "phpunit/phpunit": "^9.6 || ^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v3.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-08-19T18:57:03+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.16.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
+ "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.13",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.6 || ^1.2.1",
+ "react/stream": "^1.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3.3 || ^2",
+ "react/promise-stream": "^1.4",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.16.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-07-26T10:38:09+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-11T12:45:25+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+ "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "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/2.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:12:49+00:00"
+ },
+ {
+ "name": "sebastian/code-unit",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:58:43+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:59:15+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "5.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e",
+ "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/diff": "^5.0",
+ "sebastian/exporter": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-07T05:25:07+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "3.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T08:37:17+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "5.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "symfony/process": "^6.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:15:17+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "6.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
+ "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-23T08:47:14+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "5.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "0735b90f4da94969541dac1da743446e276defa6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6",
+ "reference": "0735b90f4da94969541dac1da743446e276defa6",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-24T06:09:11+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+ "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "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/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-02T07:19:19+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T08:38:20+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:08:32+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:06:18+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a",
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-10T07:50:56+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:10:45+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-07T11:34:05+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v6.4.26",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
+ "reference": "492de6dfd93910d7d7a729c5a04ddcd2b9e99c4f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/string": "^5.4|^6.0|^7.0"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/event-dispatcher": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/process": "<5.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0|^7.0",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/lock": "^5.4|^6.0|^7.0",
+ "symfony/messenger": "^5.4|^6.0|^7.0",
+ "symfony/process": "^5.4|^6.0|^7.0",
+ "symfony/stopwatch": "^5.4|^6.0|^7.0",
+ "symfony/var-dumper": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command-line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v6.4.26"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-26T12:13:46+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.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-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v6.4.25",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "b0cf3162020603587363f0551cd3be43958611ff"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff",
+ "reference": "b0cf3162020603587363f0551cd3be43958611ff",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/event-dispatcher-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "provide": {
+ "psr/event-dispatcher-implementation": "1.0",
+ "symfony/event-dispatcher-implementation": "2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0|^7.0",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/error-handler": "^5.4|^6.0|^7.0",
+ "symfony/expression-language": "^5.4|^6.0|^7.0",
+ "symfony/http-foundation": "^5.4|^6.0|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/stopwatch": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-13T09:41:44+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher-contracts.git",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/event-dispatcher": "^1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to dispatching event",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.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-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
+ "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^5.4|^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-10T08:14:14+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "73089124388c8510efb8d2d1689285d285937b08"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08",
+ "reference": "73089124388c8510efb8d2d1689285d285937b08",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "symfony/filesystem": "^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Finds files and directories via an intuitive fluent interface",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/finder/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-15T12:02:45+00:00"
+ },
+ {
+ "name": "symfony/options-resolver",
+ "version": "v6.4.25",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/options-resolver.git",
+ "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe",
+ "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\OptionsResolver\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an improved replacement for the array_replace PHP function",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "config",
+ "configuration",
+ "options"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/options-resolver/tree/v6.4.25"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-04T17:06:28+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-06-27T09:58:17+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+ "reference": "3833d7255cc303546435cb650316bff708a1c75c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-01-02T08:10:11+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php81",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php81.git",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php81\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php84",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php84.git",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
+ "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php84\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-06-24T13:30:11+00:00"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v6.4.26",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/process.git",
+ "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
+ "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Executes commands in sub-processes",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/process/tree/v6.4.26"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T09:57:09+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.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": "2025-04-25T09:37:31+00:00"
+ },
+ {
+ "name": "symfony/stopwatch",
+ "version": "v6.4.24",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/stopwatch.git",
+ "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898",
+ "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/service-contracts": "^2.5|^3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Stopwatch\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a way to profile code",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/stopwatch/tree/v6.4.24"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-10T08:14:14+00:00"
+ },
+ {
+ "name": "symfony/string",
+ "version": "v6.4.26",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/string.git",
+ "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/string/zipball/5621f039a71a11c87c106c1c598bdcd04a19aeea",
+ "reference": "5621f039a71a11c87c106c1c598bdcd04a19aeea",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": "<2.5"
+ },
+ "require-dev": {
+ "symfony/http-client": "^5.4|^6.0|^7.0",
+ "symfony/intl": "^6.2|^7.0",
+ "symfony/translation-contracts": "^2.5|^3.0",
+ "symfony/var-exporter": "^5.4|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "string",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/string/tree/v6.4.26"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T14:32:46+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "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.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:36:25+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {
+ "webfiori/framework": 20
+ },
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}
diff --git a/php_cs.php.dist b/php_cs.php.dist
index ea7b2cb..927bae0 100644
--- a/php_cs.php.dist
+++ b/php_cs.php.dist
@@ -1,93 +1,93 @@
-exclude('vendor')
- ->exclude('tests')
- ->in(__DIR__)
-;
-
-return PhpCsFixer\Config::create()
- ->setRules([
- 'align_multiline_comment' => [
- 'comment_type' => 'phpdocs_only'
- ],
- 'array_indentation' => [],
- 'array_syntax' => [
- 'syntax' => 'short'
- ],
- 'binary_operator_spaces' => [
- 'default' => 'single_space'
- ],
- 'blank_line_before_statement' => [
- 'statements' => [
- 'if','return','while','for','foreach','do'
- ]
- ],
- 'blank_line_after_opening_tag' => true,
- 'blank_line_after_namespace' => true,
- 'elseif' => false,
- 'explicit_string_variable' => false,
- 'full_opening_tag' => true,
- 'fully_qualified_strict_types' => true,
- 'line_ending' => true,
- 'linebreak_after_opening_tag' => true,
- 'lowercase_cast' => true,
- 'lowercase_keywords' => true,
- 'lowercase_static_reference' => true,
- 'no_alternative_syntax' => true,
- 'no_blank_lines_after_class_opening' => true,
- 'no_blank_lines_after_phpdoc' => true,
- 'no_blank_lines_before_namespace' => true,
- 'no_closing_tag' => true,
- 'no_empty_comment' => true,
- 'no_empty_phpdoc' => true,
- 'no_empty_statement' => true,
- 'no_multiline_whitespace_around_double_arrow' => true,
- 'no_spaces_after_function_name' => true,
- 'no_spaces_inside_parenthesis' => true,
- 'no_unused_imports' => true,
- 'single_import_per_statement' => true,
- 'single_blank_line_at_eof' => true,
- 'no_whitespace_in_blank_line' => true,
- 'not_operator_with_space' => false,
- 'ordered_imports' => [
- 'sort_algorithm' => 'alpha'
- ],
- 'ordered_class_elements' => [
- 'sortAlgorithm' => 'alpha',
- 'order' => [
- 'constant_public',
- 'constant_protected',
- 'constant_private',
- 'property_public',
- 'property_protected',
- 'property_private',
- 'construct',
- 'method_public',
- 'method_private'
- ]
- ],
- 'no_mixed_echo_print' => [
- 'use' => 'echo'
- ],
- 'constant_case' => [
- 'case' => 'lower'
- ],
- 'increment_style' => [
- 'style' => 'post'
- ],
- 'concat_space' => [
- 'spacing' => 'none'
- ],
- 'braces' => [
- 'allow_single_line_closure' => false,
- 'position_after_functions_and_oop_constructs' => 'same',
- 'position_after_anonymous_constructs' => 'next',
- 'position_after_control_structures' => 'same'
- ],
- 'class_definition' => [
- 'single_line' => true
- ]
- ])
- ->setFinder($finder)
-;
+exclude('vendor')
+ ->exclude('tests')
+ ->in(__DIR__)
+;
+
+$config = new PhpCsFixer\Config();
+return $config->setRules([
+ 'align_multiline_comment' => [
+ 'comment_type' => 'phpdocs_only'
+ ],
+ 'array_indentation' => [],
+ 'array_syntax' => [
+ 'syntax' => 'short'
+ ],
+ 'binary_operator_spaces' => [
+ 'default' => 'single_space'
+ ],
+ 'blank_line_before_statement' => [
+ 'statements' => [
+ 'if','return','while','for','foreach','do'
+ ]
+ ],
+ 'blank_line_after_opening_tag' => true,
+ 'blank_line_after_namespace' => true,
+ 'elseif' => false,
+ 'explicit_string_variable' => false,
+ 'full_opening_tag' => true,
+ 'fully_qualified_strict_types' => true,
+ 'line_ending' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'lowercase_cast' => true,
+ 'lowercase_keywords' => true,
+ 'lowercase_static_reference' => true,
+ 'no_alternative_syntax' => true,
+ 'no_blank_lines_after_class_opening' => true,
+ 'no_blank_lines_after_phpdoc' => true,
+ 'no_blank_lines_before_namespace' => true,
+ 'no_closing_tag' => true,
+ 'no_empty_comment' => true,
+ 'no_empty_phpdoc' => true,
+ 'no_empty_statement' => true,
+ 'no_multiline_whitespace_around_double_arrow' => true,
+ 'no_spaces_after_function_name' => true,
+ 'no_spaces_inside_parenthesis' => true,
+ 'no_unused_imports' => true,
+ 'single_import_per_statement' => true,
+ 'single_blank_line_at_eof' => true,
+ 'no_whitespace_in_blank_line' => true,
+ 'not_operator_with_space' => false,
+ 'ordered_imports' => [
+ 'sort_algorithm' => 'alpha'
+ ],
+ 'ordered_class_elements' => [
+ 'sort_algorithm' => 'alpha',
+ 'order' => [
+ 'constant_public',
+ 'constant_protected',
+ 'constant_private',
+ 'property_public',
+ 'property_protected',
+ 'property_private',
+ 'construct',
+ 'method_public',
+ 'method_private'
+ ]
+ ],
+ 'no_mixed_echo_print' => [
+ 'use' => 'echo'
+ ],
+ 'constant_case' => [
+ 'case' => 'lower'
+ ],
+ 'increment_style' => [
+ 'style' => 'post'
+ ],
+ 'concat_space' => [
+ 'spacing' => 'none'
+ ],
+ 'braces' => [
+ 'allow_single_line_closure' => false,
+ 'position_after_functions_and_oop_constructs' => 'same',
+ 'position_after_anonymous_constructs' => 'next',
+ 'position_after_control_structures' => 'same'
+ ],
+ 'class_definition' => [
+ 'single_line' => true
+ ]
+ ])
+ ->setFinder($finder)
+;
diff --git a/phpunit.xml b/phpunit.xml
deleted file mode 100644
index e087130..0000000
--- a/phpunit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
- ./themes/vuetifyCore/cli/CreateVuetifyThemeCommand.php
- ./themes/vuetifyCore/cli/FooterSectionWriter.php
- ./themes/vuetifyCore/cli/HeadSectionWriter.php
- ./themes/vuetifyCore/cli/HeaderSectionWriter.php
- ./themes/vuetifyCore/cli/SideSectionWriter.php
- ./themes/vuetifyCore/cli/SysBarWriter.php
- ./themes/vuetifyCore/cli/VuetifyThemeClassWriter.php
-
-
-
-
-
-
-
- ./tests/themes/vuetifyCore
-
-
-
\ No newline at end of file
diff --git a/release-please-config.json b/release-please-config.json
new file mode 100644
index 0000000..180f5de
--- /dev/null
+++ b/release-please-config.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
+ "include-v-in-tag":true,
+ "tag-separator": "-",
+ "changelog-path": "CHANGELOG.md",
+ "changelog-sections": [
+ { "type": "feat", "section": "Features" },
+ { "type": "feature", "section": "Features" },
+ { "type": "fix", "section": "Bug Fixes" },
+ { "type": "perf", "section": "Performance Improvements" },
+ { "type": "revert", "section": "Reverts" },
+ { "type": "docs", "section": "Documentation" },
+ { "type": "style", "section": "Styles" },
+ { "type": "chore", "section": "Miscellaneous Chores" },
+ { "type": "refactor", "section": "Code Refactoring" },
+ { "type": "test", "section": "Testing" },
+ { "type": "build", "section": "Build System" },
+ { "type": "ci", "section": "Continuous Integration" },
+ { "type": "ui", "section": "User Interface" },
+ { "type": "database", "section": "Database Changes" },
+ { "type": "email", "section": "Email Notifications Changes" }
+ ]
+}
\ No newline at end of file
diff --git a/sonar-project.properties b/sonar-project.properties
index ef74555..92fc662 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -1,11 +1,11 @@
-sonar.projectKey=WebFiori_vuetify_core
-sonar.organization=webfiori
-
-# This is the name and version displayed in the SonarCloud UI.
-sonar.projectName=framework
-#sonar.projectVersion=1.0
-# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
-#sonar.sources=.
-sonar.php.coverage.reportPaths=clover.xml
-# Encoding of the source code. Default is default system encoding
-sonar.sourceEncoding=UTF-8
+sonar.projectKey=WebFiori_vuetify_core
+sonar.organization=webfiori
+
+# This is the name and version displayed in the SonarCloud UI.
+sonar.projectName=framework
+#sonar.projectVersion=1.0
+# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
+#sonar.sources=.
+sonar.php.coverage.reportPaths=clover.xml
+# Encoding of the source code. Default is default system encoding
+sonar.sourceEncoding=UTF-8
diff --git a/tests/Themes/VuetifyCore/CreateVuetifyThemeTest.php b/tests/Themes/VuetifyCore/CreateVuetifyThemeTest.php
new file mode 100644
index 0000000..901a104
--- /dev/null
+++ b/tests/Themes/VuetifyCore/CreateVuetifyThemeTest.php
@@ -0,0 +1,191 @@
+cleanupTestResources($path);
+
+ $output = $this->executeSingleCommand(new CreateVuetifyThemeCommand(), [], [
+ '0',
+ $name,
+ $ns
+ ]);
+ $this->assertEquals([
+ "Select theme wireframe:\n",
+ "0: Base <--\n",
+ "1: Extended Toolbar\n",
+ "2: System Bar\n",
+ "3: Inbox\n",
+ "4: Side Navigation\n",
+ "Enter a name for the new class:\n",
+ "Enter namespace for the class: Enter = 'Themes\Vuetify'\n",
+ "Creating new vuetify theme based on 'Base' wireframe...\n",
+ "Your theme was successfully created.\n"
+ ], $output);
+
+ // Check that all expected files were created
+ $expectedFiles = [
+ $name . '.php',
+ 'AsideSection.php',
+ 'FooterSection.php',
+ 'HeaderSection.php',
+ 'HeadSection.php'
+ ];
+
+ foreach ($expectedFiles as $fileName) {
+ $filePath = $path . DS . $fileName;
+ $this->assertTrue(file_exists($filePath), "File not found: " . $filePath);
+ require_once $filePath;
+ $this->assertTrue(class_exists($ns.'\\'.explode('.', $fileName)[0]), "Class not found: " . $ns.'\\'.explode('.', $fileName)[0]);
+ }
+
+ // Clean up after test
+ $this->cleanupTestResources($path);
+ }
+
+ /**
+ * @test
+ */
+ public function testExtendedToolbar() {
+ $ns = 'TestTheme\\ExtendedToolbar';
+ $name = 'ExtendedToolbarTheme';
+ $path = ROOT_PATH . DS . str_replace('\\', DS, $ns);
+
+ $this->cleanupTestResources($path);
+
+ $output = $this->executeSingleCommand(new CreateVuetifyThemeCommand(), [], [
+ '1',
+ $name,
+ $ns
+ ]);
+
+ $expectedFiles = [$name . '.php', 'AsideSection.php', 'FooterSection.php', 'HeaderSection.php', 'HeadSection.php'];
+
+ foreach ($expectedFiles as $fileName) {
+ $filePath = $path . DS . $fileName;
+ $this->assertTrue(file_exists($filePath), "File not found: " . $filePath);
+ require_once $filePath;
+ $this->assertTrue(class_exists($ns.'\\'.explode('.', $fileName)[0]), "Class not found: " . $ns.'\\'.explode('.', $fileName)[0]);
+ }
+
+ $this->cleanupTestResources($path);
+ }
+
+ /**
+ * @test
+ */
+ public function testSystemBar() {
+ $ns = 'TestTheme\\SystemBar';
+ $name = 'SystemBarTheme';
+ $path = ROOT_PATH . DS . str_replace('\\', DS, $ns);
+
+ $this->cleanupTestResources($path);
+
+ $output = $this->executeSingleCommand(new CreateVuetifyThemeCommand(), [], [
+ '2',
+ $name,
+ $ns
+ ]);
+
+ $expectedFiles = [$name . '.php', 'AsideSection.php', 'FooterSection.php', 'HeaderSection.php', 'HeadSection.php'];
+
+ foreach ($expectedFiles as $fileName) {
+ $filePath = $path . DS . $fileName;
+ $this->assertTrue(file_exists($filePath), "File not found: " . $filePath);
+ require_once $filePath;
+ $this->assertTrue(class_exists($ns.'\\'.explode('.', $fileName)[0]), "Class not found: " . $ns.'\\'.explode('.', $fileName)[0]);
+ }
+
+ $this->cleanupTestResources($path);
+ }
+
+ /**
+ * @test
+ */
+ public function testInbox() {
+ $ns = 'TestTheme\\Inbox';
+ $name = 'InboxTheme';
+ $path = ROOT_PATH . DS . str_replace('\\', DS, $ns);
+
+ $this->cleanupTestResources($path);
+
+ $output = $this->executeSingleCommand(new CreateVuetifyThemeCommand(), [], [
+ '3',
+ $name,
+ $ns
+ ]);
+
+ $expectedFiles = [$name . '.php', 'AsideSection.php', 'FooterSection.php', 'HeaderSection.php', 'HeadSection.php'];
+
+ foreach ($expectedFiles as $fileName) {
+ $filePath = $path . DS . $fileName;
+ $this->assertTrue(file_exists($filePath), "File not found: " . $filePath);
+ require_once $filePath;
+ $this->assertTrue(class_exists($ns.'\\'.explode('.', $fileName)[0]), "Class not found: " . $ns.'\\'.explode('.', $fileName)[0]);
+ }
+
+ $this->cleanupTestResources($path);
+ }
+
+ /**
+ * @test
+ */
+ public function testSideNavigation() {
+ $ns = 'TestTheme\\SideNavigation';
+ $name = 'SideNavigationTheme';
+ $path = ROOT_PATH . DS . str_replace('\\', DS, $ns);
+
+ $this->cleanupTestResources($path);
+
+ $output = $this->executeSingleCommand(new CreateVuetifyThemeCommand(), [], [
+ '4',
+ $name,
+ $ns
+ ]);
+
+ $expectedFiles = [$name . '.php', 'AsideSection.php', 'FooterSection.php', 'HeaderSection.php', 'HeadSection.php'];
+
+ foreach ($expectedFiles as $fileName) {
+ $filePath = $path . DS . $fileName;
+ $this->assertTrue(file_exists($filePath), "File not found: " . $filePath);
+ require_once $filePath;
+ $this->assertTrue(class_exists($ns.'\\'.explode('.', $fileName)[0]), "Class not found: " . $ns.'\\'.explode('.', $fileName)[0]);
+ }
+
+ $this->cleanupTestResources($path);
+ }
+
+ /**
+ * Deletes all resources created by a test in the specified path
+ *
+ * @param string $path The path to clean up
+ */
+ public function cleanupTestResources($path) {
+ if (is_dir($path)) {
+ $files = glob($path . DS . '*');
+ foreach ($files as $file) {
+ if (is_file($file)) {
+ unlink($file);
+ }
+ }
+ rmdir($path);
+ }
+
+ // Also remove parent directory if empty
+ $parentPath = dirname($path);
+ if (is_dir($parentPath) && count(glob($parentPath . DS . '*')) === 0) {
+ rmdir($parentPath);
+ }
+ }
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..d852d98
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ./Themes/VuetifyCore
+
+
+
+
+ ../Themes/VuetifyCore
+
+
+
diff --git a/tests/phpunit10.xml b/tests/phpunit10.xml
new file mode 100644
index 0000000..a374473
--- /dev/null
+++ b/tests/phpunit10.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ./Themes/VuetifyCore
+
+
+
+
+ ./Themes/VuetifyCore
+
+
+
diff --git a/tests/themes/vuetifyCore/CreateVuetifyThemeTest.php b/tests/themes/vuetifyCore/CreateVuetifyThemeTest.php
deleted file mode 100644
index fec5b9f..0000000
--- a/tests/themes/vuetifyCore/CreateVuetifyThemeTest.php
+++ /dev/null
@@ -1,13 +0,0 @@
-assertTrue(true);
- }
-}
\ No newline at end of file