diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0c4e8e0 Binary files /dev/null and b/.DS_Store differ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..01e641d --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +DATABASE_HOST="placeholder" +DATABASE_PORT="placeholder" +DATABASE_NAME="placeholder" +DATABASE_USERNAME="placeholder" +DATABASE_PASSWORD="placeholder" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1daa64a --- /dev/null +++ b/.gitignore @@ -0,0 +1,173 @@ +# Cache, temp and personal files +.env +.vscode +/.htaccess +*.log + +# Cache +/cache/* +!/cache/.htaccess +!/cache/cachefs/index.php +!/cache/deprecated.txt +!/cache/index.php +!/cache/purifier/index.php +!/cache/push/activity +!/cache/push/index.php +!/cache/push/trends +!/cache/sandbox/index.php +!/cache/smarty/cache/index.php +!/cache/smarty/compile/index.php +!/cache/smarty/index.php +!/cache/tcpdf/index.php + +# Download +/download/* +!/download/.htaccess +!/download/index.php + +# Images +/img/* +!/img/.htaccess +!/img/index.php +!/img/404.gif +!/img/bg_500.png +!/img/bg_loader.png +!/img/favicon.ico +!/img/loader.gif +!/img/loadingAnimation.gif +!/img/logo.jpg +!/img/logo.png +!/img/logo_invoice.jpg +!/img/logo_stores.png +!/img/macFFBgHack.png +!/img/prestashop-avatar.png +!/img/prestashop@2x.png +!/img/preston-login-wink@2x.png +!/img/preston-login@2x.png +!/img/questionmark.png +!/img/genders/index.php +!/img/admin/index.php +!/img/c/index.php +!/img/cms/index.php +!/img/co/index.php +!/img/jquery-ui +!/img/l/index.php +!/img/m/index.php +!/img/os/index.php +!/img/p/index.php +!/img/s/index.php +!/img/scenes +!/img/st/index.php +!/img/su/index.php +!/img/t/index.php +!/img/tmp/index.php + +# Upload +/upload/* +!/upload/.htaccess + +/vendor/* +/docs/phpdoc-sf/ +/composer.lock +*.hot-update.js +*.hot-update.json + + +/admin-dev/autoupgrade/* +!/admin-dev/autoupgrade/index.php +!/admin-dev/autoupgrade/backup/index.php + +/admin-dev/backups/* +!/admin-dev/backups/.htaccess + +/admin-dev/import/* +!/admin-dev/import/.htaccess +!/admin-dev/import/index.php + +/admin-dev/export/* +!/admin-dev/export/.htaccess +!/admin-dev/export/index.php + +# Downloaded RTL files +/admin-dev/themes/default/css/bundle/default_rtl.css +/admin-dev/themes/default/css/bundle/shared_rtl.css +/admin-dev/themes/default/css/font_rtl.css +/admin-dev/themes/default/css/overrides_rtl.css +/admin-dev/themes/default/css/vendor/font-awesome/font-awesome_rtl.css +/admin-dev/themes/default/css/vendor/nv.d3_rtl.css +/admin-dev/themes/default/css/vendor/titatoggle-min_rtl.css +/admin-dev/themes/default/public/theme_rtl.css +/admin-dev/themes/new-theme/css/module/drop_rtl.css +/admin-dev/themes/new-theme/css/right-sidebar_rtl.css + +themes/*/cache/* + +# Config + +config/settings.inc.php +config/settings.old.php +config/xml/* +config/themes/* +!config/xml/themes/default.xml +themes/*/config/settings_*.json +app/config/parameters.old.yml +app/config/config.php + +# Themes, modules and overrides + +modules/* +override/* +themes/*/ +!themes/classic +!themes/_core +!themes/_libraries + +# Vendors and dependencies + +bower_components/ +node_modules/ +composer.phar +php-cs-fixer +.grunt/* + +# Translations and emails templates + +translations/* +mails/* +!mails/themes/ +!mails/_partials/ +themes/default-bootstrap/lang/* +themes/default-bootstrap/modules/*/translations/*.php +themes/default-bootstrap/mails/* +!themes/default-bootstrap/mails/en/ +themes/default-bootstrap/modules/*/mails/* +!themes/default-bootstrap/modules/*/mails/en + +# MISC + +*sitemap.xml +/robots.txt + +# Symfony + +/bin/ +/app/Resources/geoip/GeoLite2-City.mmdb +/app/Resources/translations/* +!/app/Resources/translations/default +/app/config/parameters.yml +/app/config/parameters.php +/build/ +/phpunit.xml +/var/* +!/var/cache +/var/cache/* +!var/cache/.gitkeep +!/var/logs +/var/logs/* +!var/logs/.gitkeep +!/var/sessions +/var/sessions/* +!var/sessions/.gitkeep +!var/SymfonyRequirements.php +/vendor/ +/web/bundles/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6165dfb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +# Utilise l'image officielle MariaDB comme base +FROM mariadb:10.11 + +# Définit le répertoire de travail +WORKDIR /var/lib/mysql + +# Copie les fichiers de configuration personnalisés si nécessaires +# COPY my-custom.cnf /etc/mysql/conf.d/ + +# Définit les variables d'environnement pour MariaDB +ENV MYSQL_ROOT_PASSWORD=root_password +ENV MYSQL_DATABASE=my_database +ENV MYSQL_USER=my_user +ENV MYSQL_PASSWORD=my_password + +# Expose le port par défaut de MariaDB +EXPOSE 3306 + +# Commande par défaut pour démarrer MariaDB +CMD ["mysqld"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..777e147 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# MAW11 - Exercice Looper + +## Subject + +Create a copy of this web application: [Exercice Looper](https://maw-looper.mycpnv.ch/) + +## Deadlines + +- **Intermediate:** 31.10.2024 +- **Final:** 21.12.2024 + +## Requirements + +You must use: + +- HTML5 +- CSS +- PHP +- Object-Oriented Programming (OOP) + +## Installation + +### Local Installation (for Development) + +#### Prerequisites: + +1. Have PHP and a database connection service installed. +2. Verify the installation in a shell: + ```bash + php -v + ``` + Successful verification occurs if the command is recognized. + +#### Procedure: + +1. Clone the repository from GitHub or download it as a ZIP file: + ```bash + git clone + ``` + Example: Clone it into the folder `C:/Users//Documents/Github/`. + +2. Set up the database: + - Run the provided script `create_db.sql` located in the `modelisation` folder to create the necessary database. + - Database connection details are: + ```php + DBConnection::setUp( + 'mysql:host=127.0.0.1;port=3308;dbname=looper;charset=utf8mb4', + 'root', + 'root_password' + ); + ``` + +3. Install dependencies: + ```bash + composer install + ``` + Run this command in the root of the project directory. + +4. Start the development server: + ```bash + php -S localhost:4444 -t public + ``` + +## Progress + +### Completed Features: + +- Exercise creation works. +- Field creation works. +- Fields can be viewed within an exercise. + +### Known Issues: + +- Exercises cannot be viewed. +- Fields cannot be viewed individually. +- Exercises cannot be filled. +- Responses cannot be viewed. +- CSS is broken. +- No best practices like dotenv or similar are followed. +- Code documentation is minimal. \ No newline at end of file diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..67826c0 --- /dev/null +++ b/compose.yml @@ -0,0 +1,19 @@ +version: "3.9" + +services: + mariadb: + image: mariadb:10.11 # Utilise l'image officielle MariaDB + container_name: looper-db + environment: + MYSQL_ROOT_PASSWORD: root_password # Mot de passe root + MYSQL_DATABASE: my_database # Base de données initiale + MYSQL_USER: my_user # Utilisateur + MYSQL_PASSWORD: my_password # Mot de passe utilisateur + volumes: + - db_data:/var/lib/mysql # Persist les données + ports: + - "3308:3306" # Mappe le port 3306 + restart: always + +volumes: + db_data: \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d496036 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "nui/maw11", + "type": "project", + "minimum-stability": "stable", + "require": { + "ext-pdo": "*" + }, + "autoload": { + "psr-4": { + "App\\": "src/", + "Controllers\\": "src/Controllers", + "Router\\": "src/Router", + "Database\\": "src/Database/", + "Models\\": "src/Models/" + } + }, + "require-dev": { + "phpunit/phpunit": "^9" + } + } \ No newline at end of file diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..6c16a37 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1762 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "198f7269e4a8dd66ef9df72dfca4caf3", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:15:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.12.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", + "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.12.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2024-11-08T17:47:46+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.3.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "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.0-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.3.1" + }, + "time": "2024-10-08T18:51:32+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": "9.2.32", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "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": "9.2.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/9.2.32" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:23:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-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/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.22", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-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/9.6.22" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-12-05T13:48:26+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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 calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-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", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:30:58+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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": "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", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:33:00+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:35:11+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+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": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-pdo": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/mcd.md b/mcd.md new file mode 100644 index 0000000..7ac5da2 --- /dev/null +++ b/mcd.md @@ -0,0 +1,29 @@ +```mermaid +erDiagram + Exercise { + int id + string name + tinyint status + } + Field { + int id + string label + string type + } + Fulfillment { + int id + datetime date + int exerciseId + int fieldId + } + Field_has_Fulfillment { + int id + int exerciseId + string value + } + + Exercise ||--o{ Field_has_Fulfillment : has + Exercise ||--|{ Field : has + Exercise ||--|{ Fulfillment : has + Field ||--|{ Fulfillment : has +``` \ No newline at end of file diff --git a/modelisation/ClassUML.drawio b/modelisation/ClassUML.drawio new file mode 100644 index 0000000..0f53104 --- /dev/null +++ b/modelisation/ClassUML.drawio @@ -0,0 +1 @@ +7V1bc9o4FP41zGQf6OALlzxyyW2bbJPSJm1fdhSsgBNjUVskIb9+ZVsGGx0cJ7FEFzTDJCDkm75P0jnn0xE1qz99PgnQbHJBHOzVzIbzXLMGNdM0bNOsRa+Gs0hK2h1eMA5ch1daFQzdF8wLG7x07jo4zFWkhHjUneULR8T38YjmylAQkKd8tTvi5a86Q2MsFAxHyBNLb1yHTpLSjtlelZ9idzxJr2y0DpNvpiitzJ8knCCHPGWKrKOa1Q8Iocm76XMfe1Hjpe1yc7a48c4fWid/X4W/0ffe52//XNeTkx2/5ZDlIwTYp+8+9cvD3fHptX3/Y3Z5fPXUOOne/l3nhzQekTfn7TXo9RMkXOLz56aLtDHDJ3fqIZ996t0Rnw75N6wpeshzxz57P2L3iANW8IgD6jIcuvwLSmasdDRxPeccLcg8epKQotFD+qk3IYH7wk6LPPaVwQrY1wHllDJbuRrD6EhW3GClAQ5Zncu0eYxl0TkKKa8zIp6HZqF7G99wVGWKgrHr9wilZJqeiMx9Bzv80xLv+AMNyMOSQdHxJUHh4EWtgZ8zlOQgnWAyxTRYsCr8W8tof2omB/EuZ9uckk8rAhttDt0kQ17T5n0T8U4zXp59ecGvDFrkj1kzLK9oWo3c9Qy7IV6vBV2vlb8c8hj0PqK4FzVkmKUje5N52FVRTFKYsBe2czU+7l19Hi0mt8Pr44HjDetNgbB15zbDWKtbSGCGAc2Q1cN3dCNVwxkauf74PK4zsFclX3kLREWEHXvnxTSZuI6D/ZhGFFGUMC3izoy4Po2bqNljL9aQ/QaDuMluqM8+G6vP7BVVDyh7BMY45MbUwozGTziichFDJ3Tq8bciNQs7/+vUXOTxfpWHrc00zBGiAH3wjm0BfQFhz42HJ94aBth1X4F/yoCMTpfi/S2iw6BuCJywRE5YAP4eusXeJQndhKGDIKm7xovXoJcFatMsB2rn45iCPboNYNoLMf0+O/hr5/qvLBBbwIgtq2eeT4ZWePnr18nNv2OreTQJOou7umlBMI4xPWMNgfwRZmBaXVZhp4dnWfB2FA68n1/al8O7566Bu0Orc9Ue/fh9UjcON8B7OfiSIsve7iigAlBlMd4IqGGUHHXldVhTtKTIDPsxmo+EHbubWFbfOQ2row5LcArtiFCOPBLi3cVyu3aw0bK3jHgLGo7xMx7NqUZdFuqHCo0scBY2xXBNMgtHgY4ziqdnTjoZR223z/BXP2WzXr/tKbstQIqdMU6jcKzlJmRMfOQdrUrXGm1V55zEXm3k1N5jShc8zIbmlKy7zyig3SgSywocF02J76TFx66XVsO+k1bySeyCsxL+Pdwri8JlIZkHI1wwAKbhZXYXjP8FjcbrRQ1V2MkD7CHqPuajxpWP24bYg6/mmJ9YR1rVRlptcz3Q2gEsuU5T7OJLA2B3A62GITC17tzugQ//XiOjuL9/KMYKUVCaaZl6pjrIWiWsUJQVglVWlNUA43Mh9lgvTm1GFARoUWv3ye19pMTuWseWhi0UfFXbZSFdpOf6IXsE7RBIwx2KyirF3QRxn88cRJfx9ltCPA18tcCD0Vu1PV7UwRnyDhvONfJSkYdivWqRF0N/R884GLkhFsDWTqR8J9Jsr/l0jbbAkKXfl2WIlUbzdtiHFLX9enSAtkfKDE6t0lTc7DqCzJNnj4hjU526NGrqbox0wPDRqFeLOuBZSkMdVCUs0Qqt/46DmjHqcHzz/w76BpRKI7wRzrZoYKjtxIaoJgvo7X3858291GiIkjGIawUBIFAHgVDtpZbjAXtiNA0zYaDdW3q35WEa8hkVz87gGq6a2fKi5olUNLM1jt5qFVkmDwAPUi0PLFHZWedBP1yxITbgUkJoE04KJ4D1RGptOEjz2UwJ5uhTTYnSi03eYwZCi42kUeKfmdG28P3PB/fkpf/z9+GAXDyAuRYRFY5d7DnhwV3072zlzOc0pH0mgwzHHlh6pJYMYLh5FGA2DsR8SOiQUCAu0AaENDKkSX5bIwO4+DTRHgrJoNekyoj5KTQn4fDPpnli7t25njdlT8xmi7l3zD/oOUOJAWEeKrQpx7Z9+WPxxfw6nk2/Gxcn/ZsvfSC3vDuneB7wMEMP+6TWt2rdIzZFsLotNI2gTP6ykiGazqO9CBIb9DZIjc8Bm3OSM5jWJ8P4xP6bYq3h/D5aFhpV63soDNn/7xfn7O9F98YQq1/jIEzSh1kVS+BiHsuniUvxkBEs+vYpQLN8KEzEr6LlinnhB9J9oOXIqRZUeURJxDcNJ51ib4YDoRW1HKlgTeuaOtgyRJYcQqNAGp7aCTUS5Cu0onVPdIoszwr78oeWqYK8kpYMAZgd+6tSVAMqtEgVAlWWRgFkR2REimRWOVjvslqpqJYE0GpWWT0bNmw35ZofYM6E2IVY+Q/L9U9J39k1OsgCGlq+qhRoOJ0xRI94iTQDOEX3r8hL0EElKVQAF7TK4gK8wYRomyXhRU2FDwQONrPjbStclVJBHBXqfEm7poJaKkDbHKidIUCpmi9zd3VcWd6EAO11AEJfEDb4kC8AbQu2BrGC5HcHhZP4+LUU92innFp1Ke5FoGUz3AtFA/Up7rBj3toGULldCvgGBNktChp5/Fb7GKwgfHtY7l27FBRtRqIews7PIPx1eG9OO89fTq9aDfzs3QDSfyzjCbjqgK78gG6z+WrYf1mWG5g7u7RFAUhTYC9YnV0i8rCwi38ouQTkXQW2IHjHQJJzPeMQZONAGvkqkYcSTJQiD2QVxXF0vf5QGuZQFora3i4uK6nH7/99cH1HIy8NeTBRRRb08IIiYF7fE532lRjOZoQLwnll7UVZPbmEI79HQm1FnbRZ0hqrQKkF7xjMJksWf+pUMtkjNJQtAnbpCmJz4C3rRLI/gAWAfAuzoIL1f7CJBsq3G5OG4hFVJw3JdNEbW/fRwTyRjZSIq31m9rymhUxaWAodeNCi19uUfVi+fYfpbzYVOvFgotAuS3aFUlxW7ynqxOr1Hjj7V5TZM9k7Aoha9lmXfV7pvJs5VVr2sZrNcp3Zsgp68/9O94Hpagp01cJPOSYWdP8/QvmB7w+IBWvlRwX0KqUf+P4A0c9ZJgDGqYAa8kohV6n8wOF/QO7T4f/3wrl9OQfYFFKAb8cFABm4ltV1KlAA4PsDf7dVSwBqRmlwFzFZGgB8g6AEpEUAxTwAsvWkqQDwDZYVgwZ6zzDZZOgo1Pph2w3M14gz+pAfPuEgPynoUUGSx65SCIKJAFoHPKNPU0EhFbYu/ligocDVH00FhVRQqQfBVNiU2X8dFWzaNk4bC1LY0Nl2YCC9WNFvGO19aqcE5C1j62aiGAH6M4XhNX1WslL8JjBLK8P80EsST6lLfdFsr/34rdlu50+SPAM/boW4eKq1X0ASTpQ8o3CiquRAG1Cvo+njFIXHq20nQ4FyWsaWL2N31mRlu+zCZSP9VZndlbHTfXyzQse6CaTnvjfOffYfrmXbgJZ9l1lrk0BfsPhGE+BDBNi6om0DijZ/r50dWahvXdS2tQgqAdbS4rYsEdQGw5zLgIYOYMgEH/pBLaUSaLokcz/c2MKVw6+6sZvArN6NPVxTOsu6sa1O3nVo2muTwbvdWPYxIIRmqwdoNrkgTrSHwdF/ \ No newline at end of file diff --git a/modelisation/ClassUML.png b/modelisation/ClassUML.png new file mode 100644 index 0000000..5469311 Binary files /dev/null and b/modelisation/ClassUML.png differ diff --git a/modelisation/MCD.drawio b/modelisation/MCD.drawio new file mode 100644 index 0000000..b1a98b9 --- /dev/null +++ b/modelisation/MCD.drawio @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modelisation/MCD.png b/modelisation/MCD.png new file mode 100644 index 0000000..7baafd5 Binary files /dev/null and b/modelisation/MCD.png differ diff --git a/modelisation/MLD.mwb b/modelisation/MLD.mwb new file mode 100644 index 0000000..3d25309 Binary files /dev/null and b/modelisation/MLD.mwb differ diff --git a/modelisation/MLD.png b/modelisation/MLD.png new file mode 100644 index 0000000..43de252 Binary files /dev/null and b/modelisation/MLD.png differ diff --git a/modelisation/Nazmi-php.code-workspace b/modelisation/Nazmi-php.code-workspace new file mode 100644 index 0000000..794dcc9 --- /dev/null +++ b/modelisation/Nazmi-php.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": ".." + }, + { + "path": "../../MAW1-BPT-SMD" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/modelisation/createDatabase.sql b/modelisation/createDatabase.sql new file mode 100644 index 0000000..5210eca --- /dev/null +++ b/modelisation/createDatabase.sql @@ -0,0 +1,57 @@ +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +DROP DATABASE IF EXISTS `looper`; +CREATE DATABASE IF NOT EXISTS `looper` /*!40100 DEFAULT CHARACTER SET utf8mb3 */; +USE `looper`; + +CREATE TABLE IF NOT EXISTS `exercises` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(45) NOT NULL, + `state` varchar(45) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `title_UNIQUE` (`title`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +CREATE TABLE IF NOT EXISTS `fields` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `label` varchar(45) NOT NULL, + `value_kind` varchar(45) NOT NULL, + `exercises_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `label` (`label`,`exercises_id`) USING BTREE, + KEY `fk_fields_exercises_idx` (`exercises_id`), + CONSTRAINT `fk_fields_exercises` FOREIGN KEY (`exercises_id`) REFERENCES `exercises` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +CREATE TABLE IF NOT EXISTS `fields_has_fulfillments` ( + `fields_id` int(11) NOT NULL, + `fulfillments_id` int(11) NOT NULL, + `value` varchar(255) DEFAULT NULL, + UNIQUE KEY `fields_id` (`fields_id`,`fulfillments_id`), + KEY `fk_fields` (`fields_id`) USING BTREE, + KEY `fk_fulfillments` (`fulfillments_id`), + CONSTRAINT `fk_fields` FOREIGN KEY (`fields_id`) REFERENCES `fields` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT `fk_fulfillments` FOREIGN KEY (`fulfillments_id`) REFERENCES `fulfillments` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +CREATE TABLE IF NOT EXISTS `fulfillments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercises_id` int(11) NOT NULL, + `date` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `fk_fulfillments_exercises` (`exercises_id`), + CONSTRAINT `fk_fulfillments_exercises` FOREIGN KEY (`exercises_id`) REFERENCES `exercises` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/modelisation/sequenceExerciseFields.puml b/modelisation/sequenceExerciseFields.puml new file mode 100644 index 0000000..96d415c --- /dev/null +++ b/modelisation/sequenceExerciseFields.puml @@ -0,0 +1,50 @@ +@startuml +'https://plantuml.com/sequence-diagram + +actor User order 1 +participant Exercise order 2 +participant Field order 2 +participant ExerciseHelper order 4 +participant Query order 5 +participant DBConnection order 6 +actor Database order 7 + +group Create Exercise + User -> Exercise : Create a new exercise + Exercise -> ExerciseHelper : Create() + ExerciseHelper -> Query : insert() + Query -> DBConnection : execute() + DBConnection -> Database : Create the exercise +end + +group Delete Exercise +User -> Exercise : Delete the exercise +Exercise -> ExerciseHelper : Delete() +ExerciseHelper -> Query : delete() +Query -> DBConnection : execute() +DBConnection -> Database : Delete the exercise +end + +group Create Field +User -> Field : Create a new field +Field -> Exercise : CreateField() +Exercise -> Query : insert() +Query -> DBConnection : execute() +DBConnection -> Database : Create the field +end + +group Edit Field +User -> Field : Edit the field +Field -> Exercise : setValueKind(), setLabel() +Exercise --> Query : saveField() +Query -> DBConnection : execute() +DBConnection -> Database : Edit the field +end +group Delete Field +Field -> Exercise : Delete the field +Exercise -> ExerciseHelper : deleteField() +ExerciseHelper -> Query : deleteField() +Query -> DBConnection : execute() +DBConnection -> Database : Delete the field +end +@enduml \ No newline at end of file diff --git a/public/assets/fa-solid-900.woff2 b/public/assets/fa-solid-900.woff2 new file mode 100644 index 0000000..e30fb67 Binary files /dev/null and b/public/assets/fa-solid-900.woff2 differ diff --git a/public/assets/logo.png b/public/assets/logo.png new file mode 100644 index 0000000..fb855c1 Binary files /dev/null and b/public/assets/logo.png differ diff --git a/public/const.php b/public/const.php new file mode 100644 index 0000000..373324c --- /dev/null +++ b/public/const.php @@ -0,0 +1,6 @@ + code { + border-radius: 0; + display: block; + padding: 1rem 1.5rem; + white-space: pre; +} +hr { + border: 0; + border-top: 0.1rem solid #f4f5f6; + margin: 3rem 0; +} +input[type="color"], +input[type="date"], +input[type="datetime"], +input[type="datetime-local"], +input[type="email"], +input[type="month"], +input[type="number"], +input[type="password"], +input[type="search"], +input[type="tel"], +input[type="text"], +input[type="url"], +input[type="week"], +input:not([type]), +textarea, +select { + -webkit-appearance: none; + background-color: transparent; + border: 0.1rem solid #d1d1d1; + border-radius: 0.4rem; + box-shadow: none; + box-sizing: inherit; + height: 3.8rem; + padding: 0.6rem 1rem 0.7rem; + width: 100%; +} +input[type="color"]:focus, +input[type="date"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="email"]:focus, +input[type="month"]:focus, +input[type="number"]:focus, +input[type="password"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="text"]:focus, +input[type="url"]:focus, +input[type="week"]:focus, +input:not([type]):focus, +textarea:focus, +select:focus { + border-color: #9b4dca; + outline: 0; +} +select { + background: url('data:image/svg+xml;utf8,') + center right no-repeat; + padding-right: 3rem; +} +select:focus { + background-image: url('data:image/svg+xml;utf8,'); +} +select[multiple] { + background: none; + height: auto; +} +textarea { + min-height: 6.5rem; +} +label, +legend { + display: block; + font-size: 1.6rem; + font-weight: 700; + margin-bottom: 0.5rem; +} +fieldset { + border-width: 0; + padding: 0; +} +input[type="checkbox"], +input[type="radio"] { + display: inline; +} +.label-inline { + display: inline-block; + font-weight: normal; + margin-left: 0.5rem; +} +.container { + margin: 0 auto; + max-width: 112rem; + padding: 0 2rem; + position: relative; + width: 100%; +} +.row { + display: flex; + flex-direction: column; + padding: 0; + width: 100%; +} +.row.row-no-padding { + padding: 0; +} +.row.row-no-padding > .column { + padding: 0; +} +.row.row-wrap { + flex-wrap: wrap; +} +.row.row-top { + align-items: flex-start; +} +.row.row-bottom { + align-items: flex-end; +} +.row.row-center { + align-items: center; +} +.row.row-stretch { + align-items: stretch; +} +.row.row-baseline { + align-items: baseline; +} +.row .column { + display: block; + flex: 1 1 auto; + margin-left: 0; + max-width: 100%; + width: 100%; +} +.row .column.column-offset-10 { + margin-left: 10%; +} +.row .column.column-offset-20 { + margin-left: 20%; +} +.row .column.column-offset-25 { + margin-left: 25%; +} +.row .column.column-offset-33, +.row .column.column-offset-34 { + margin-left: 33.3333%; +} +.row .column.column-offset-40 { + margin-left: 40%; +} +.row .column.column-offset-50 { + margin-left: 50%; +} +.row .column.column-offset-60 { + margin-left: 60%; +} +.row .column.column-offset-66, +.row .column.column-offset-67 { + margin-left: 66.6666%; +} +.row .column.column-offset-75 { + margin-left: 75%; +} +.row .column.column-offset-80 { + margin-left: 80%; +} +.row .column.column-offset-90 { + margin-left: 90%; +} +.row .column.column-10 { + flex: 0 0 10%; + max-width: 10%; +} +.row .column.column-20 { + flex: 0 0 20%; + max-width: 20%; +} +.row .column.column-25 { + flex: 0 0 25%; + max-width: 25%; +} +.row .column.column-33, +.row .column.column-34 { + flex: 0 0 33.3333%; + max-width: 33.3333%; +} +.row .column.column-40 { + flex: 0 0 40%; + max-width: 40%; +} +.row .column.column-50 { + flex: 0 0 50%; + max-width: 50%; +} +.row .column.column-60 { + flex: 0 0 60%; + max-width: 60%; +} +.row .column.column-66, +.row .column.column-67 { + flex: 0 0 66.6666%; + max-width: 66.6666%; +} +.row .column.column-75 { + flex: 0 0 75%; + max-width: 75%; +} +.row .column.column-80 { + flex: 0 0 80%; + max-width: 80%; +} +.row .column.column-90 { + flex: 0 0 90%; + max-width: 90%; +} +.row .column .column-top { + align-self: flex-start; +} +.row .column .column-bottom { + align-self: flex-end; +} +.row .column .column-center { + align-self: center; +} +@media (min-width: 40rem) { + .row { + flex-direction: row; + margin-left: -1rem; + width: calc(100% + 2rem); + } + .row .column { + margin-bottom: inherit; + padding: 0 1rem; + } +} +a { + color: #9b4dca; + text-decoration: none; +} +a:focus, +a:hover { + color: #606c76; +} +dl, +ol, +ul { + list-style: none; + margin-top: 0; + padding-left: 0; +} +dl dl, +dl ol, +dl ul, +ol dl, +ol ol, +ol ul, +ul dl, +ul ol, +ul ul { + font-size: 90%; + margin: 1.5rem 0 1.5rem 3rem; +} +ol { + list-style: decimal inside; +} +ul { + list-style: circle inside; +} +.button, +button, +dd, +dt, +li { + margin-bottom: 1rem; +} +fieldset, +input, +select, +textarea { + margin-bottom: 1.5rem; +} +blockquote, +dl, +figure, +form, +ol, +p, +pre, +table, +ul { + margin-bottom: 2.5rem; +} +table { + border-spacing: 0; + display: block; + overflow-x: auto; + text-align: left; + width: 100%; +} +td, +th { + border-bottom: 0.1rem solid #e1e1e1; + padding: 1.2rem 1.5rem; +} +td:first-child, +th:first-child { + padding-left: 0; +} +td:last-child, +th:last-child { + padding-right: 0; +} +@media (min-width: 40rem) { + table { + display: table; + overflow-x: initial; + } +} +b, +strong { + font-weight: bold; +} +p { + margin-top: 0; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 300; + letter-spacing: -0.1rem; + margin-bottom: 2rem; + margin-top: 0; +} +h1 { + font-size: 4.6rem; + line-height: 1.2; +} +h2 { + font-size: 3.6rem; + line-height: 1.25; +} +h3 { + font-size: 2.8rem; + line-height: 1.3; +} +h4 { + font-size: 2.2rem; + letter-spacing: -0.08rem; + line-height: 1.35; +} +h5 { + font-size: 1.8rem; + letter-spacing: -0.05rem; + line-height: 1.5; +} +h6 { + font-size: 1.6rem; + letter-spacing: 0; + line-height: 1.4; +} +img { + max-width: 100%; +} +.clearfix:after { + clear: both; + content: " "; + display: table; +} +.float-left { + float: left; +} +.float-right { + float: right; +} + +/*# sourceMappingURL=milligram.min.css.map */ diff --git a/public/img/logo.png b/public/img/logo.png new file mode 100644 index 0000000..fb855c1 Binary files /dev/null and b/public/img/logo.png differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..f5a4d5f --- /dev/null +++ b/public/index.php @@ -0,0 +1,47 @@ +get('home_index', new Route('/', HomeController::class, 'index')); + +$router->get('exercises_index', new Route('/exercises', ExerciseController::class, 'index')); +$router->get('exercises_new', new Route('/exercises/new', ExerciseController::class, 'new')); +$router->get('exercises_answering', new Route('/exercises/answering', ExerciseController::class, 'answering')); +$router->post('exercises_create', new Route('/exercises/new', ExerciseController::class, 'new')); +$router->post('exercises_state', new Route('/exercises/:exercise/state', ExerciseController::class, 'state')); +$router->post('exercises_delete', new Route('/exercises/:exercise', ExerciseController::class, 'delete')); +$router->get('exercises_results', new Route('/exercises/:exercise/results', ExerciseController::class, 'results')); + +$router->get('fields_index', new Route('/exercises/:exercise/fields', FieldsController::class, 'index')); +$router->post('fields_create', new Route('/exercises/:exercise/fields', FieldsController::class, 'index')); +$router->get('fields_edit', new Route('/exercises/:exercise/fields/:field/edit', FieldsController::class, 'edit')); +$router->post('fields_update', new Route('/exercises/:exercise/fields/:field/edit', FieldsController::class, 'edit')); +$router->post('fields_delete', new Route('/exercises/:exercise/fields/:field', FieldsController::class, 'delete')); +$router->get('fields_results', new Route('/exercises/:exercise/results/:field', FieldsController::class, 'results')); + +$router->get('fulfillments_new', new Route('/exercises/:exercise/fulfillments/new', FulfillmentController::class, 'new')); +$router->post('fulfillments_create', new Route('/exercises/:exercise/fulfillments/create', FulfillmentController::class, 'create')); +$router->get('fulfillments_edit', new Route('/exercises/:exercise/fulfillments/:fulfillment/edit', FulfillmentController::class, 'edit')); +$router->post('fulfillments_update', new Route('/exercises/:exercise/fulfillments/:fulfillment/update', FulfillmentController::class, 'update')); +$router->get('fulfillments_results', new Route('/exercises/:exercise/fulfillments/:fulfillment', FulfillmentController::class, 'results')); + +$router->run(); diff --git a/src/Controllers/Controller.php b/src/Controllers/Controller.php new file mode 100644 index 0000000..60e3e4a --- /dev/null +++ b/src/Controllers/Controller.php @@ -0,0 +1,32 @@ +dbConnection = DBConnection::getInstance(); + $this->router = Router::getInstance(); + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + } + + protected function view(string $path, array $params = null): void + { + ob_start(); + require TEMPLATES_DIR . $path . '.php'; + $content = ob_get_clean(); + require TEMPLATES_DIR . 'layout.php'; + } + +} + + diff --git a/src/Controllers/ExerciseController.php b/src/Controllers/ExerciseController.php new file mode 100644 index 0000000..64c9bb9 --- /dev/null +++ b/src/Controllers/ExerciseController.php @@ -0,0 +1,103 @@ +exerciseHelper = new ExerciseHelper(); // Initializes the ExerciseHelper instance + } + + public function index() { + // Logic to show exercise + + $this->view('exercises/index', [ + 'exercises' => $this->exerciseHelper->get(), // Retrieves exercises using ExerciseHelper + 'router' => $this->router, // Passes the router to the view + ]); + } + + public function answering() { + // Logic to show exercise + + $this->view('exercises/answering', [ + 'exercises' => $this->exerciseHelper->get(), // Retrieves exercises using ExerciseHelper + 'router' => $this->router, // Passes the router to the view + ]); + } + + public function new() { + // Logic to show exercise + + $params['router'] = $this->router; // Sets the router parameter + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $exercise = new Exercise(['title' => $_POST['title']]); // Creates a new Exercise instance + if ($exerciseId = $this->exerciseHelper->save($exercise)) { + $this->router->redirect('fields_index', ['exercise' => $exerciseId]); // Redirects to fields index if exercise is saved + } + $params["error"] = "Le titre est déjà utilisé. Veuillez en choisir un autre."; // Sets error message if title is used + } + $this->view('exercises/new', $params); // Renders the new exercise view with parameters + + } + + public function getId(): int { + // Getter logic here + return $this->id; // Returns the ID + } + + public function getTitle(): string { + // Getter logic here + return $this->title; // Returns the title + } + + public function getFields(int $fieldId): array { + // Logic to get fields by exercise ID and field ID + $params = [':exerciseId' => $this->id, ':fieldId' => $fieldId]; // Sets parameters for query + return $this->query->select('fields', Field::class, 'exercise_id = :exerciseId', $params); // Executes the select query to get fields + } + + public function createField(Field $field): void { + // Logic to create field + + $data = ['exercise_id' => $this->id, 'name' => $field->getName(), 'description' => $field->getDescription()]; // Sets data for insertion + $field->setId($this->query->insert('fields', Field::class, $data)); // Inserts new field and sets its ID + + } + + public function deleteField(Field $field): void { + // Logic to delete field + $params = [':fieldId' => $field->getId()]; // Sets parameters for deletion + $this->query->delete('fields', Field::class, 'id = :fieldId', $params); // Executes the delete query + + } + + public function getFulfillments(int $fulfillmentId): array { + // Logic to get fulfillments + } + + public function state(int $exerciseId, string $query) { + parse_str($query, $params); // Parses the query string into parameters + + $exercise = $this->exerciseHelper->get($exerciseId); // Retrieves the exercise using ExerciseHelper + $exercise->setState($params['state']); // Sets the state of the exercise + + $this->exerciseHelper->save($exercise); // Saves the exercise + + $this->view('exercises/index', [ + 'exercises' => $this->exerciseHelper->get(), // Retrieves exercises using ExerciseHelper + 'router' => $this->router, // Passes the router to the view + ]); + } +} diff --git a/src/Controllers/FieldsController.php b/src/Controllers/FieldsController.php new file mode 100644 index 0000000..16369c4 --- /dev/null +++ b/src/Controllers/FieldsController.php @@ -0,0 +1,41 @@ +exerciseHelper = new ExerciseHelper(); // Initializes the ExerciseHelper instance + } + + public function index(int $exerciseId): void + { + $exercise = $this->exerciseHelper->get($exerciseId); // Retrieves the exercise using ExerciseHelper + $params = [ + 'exercise' => $exercise, // Sets the exercise parameter + 'router' => $this->router, // Sets the router parameter + ]; + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $field = new Field([ + 'label' => $_POST['field']['label'], // Sets the label for the field + 'value_kind' => $_POST['field']['value_kind'], // Sets the value kind for the field + ]); + + if ($exercise->createField($field)) { + $this->router->redirect('fields_index', ['exercise' => $exercise->getId()]); // Redirects to fields index if the field is created + } else { + $params["error"] = "Le label déjà utilisé. Veuillez en choisir un autre."; // Sets error message if label is already used + } + } + + $this->view('fields/index', $params); // Renders the fields index view with parameters + } +} diff --git a/src/Controllers/FulfillmentController.php b/src/Controllers/FulfillmentController.php new file mode 100644 index 0000000..3b7c511 --- /dev/null +++ b/src/Controllers/FulfillmentController.php @@ -0,0 +1,46 @@ +router; + $this->view('site/index', compact('router')); + } + +} \ No newline at end of file diff --git a/src/Database/DBConnection.php b/src/Database/DBConnection.php new file mode 100644 index 0000000..b28cce6 --- /dev/null +++ b/src/Database/DBConnection.php @@ -0,0 +1,66 @@ +pdo)) { + $this->open(); + } + return $this->pdo; + } + + private function open(): void { + $this->pdo = new PDO(self::$dns, self::$user, self::$password); + } + + public function close(): void { + // Close connection logic here + self::$dbConnection = null; + } + + public function execute(string $sql, string $class, array $param = null, bool $single = false): object|bool|array + { + $request = $this->getPDO()->prepare($sql); + + $request->execute($param); + + if (str_starts_with($sql, 'SELECT')) { + if ($single) { + return $request->fetchObject($class); + } else { + return $request->fetchAll(PDO::FETCH_CLASS, $class); + } + } else { + return $request->rowCount() > 0; + } + } + + public function getLastItemId(): int { + // Return last inserted ID logic here + return $this->getPDO()->lastInsertId(); + } +} \ No newline at end of file diff --git a/src/Database/Query.php b/src/Database/Query.php new file mode 100644 index 0000000..5fcd193 --- /dev/null +++ b/src/Database/Query.php @@ -0,0 +1,57 @@ +dbConnection = DBConnection::getInstance(); + } + + public function select( + String $table, + String $class, + string $conditions = null, + array $params = null, + bool $single = false + ): array|object { + $sql = "SELECT * FROM {$table}"; + $sql .= $conditions ? " WHERE {$conditions}" : ""; + return $this->dbConnection->execute($sql, $class, $params, $single); + } + + public function insert(string $table, string $class, array $data): int + { + $fieldList = implode(', ', array_keys($data)); + $placeholderList = implode(', ', array_map(fn($key) => ":{$key}", array_keys($data))); + + $this->dbConnection->execute( + "INSERT INTO {$table} ({$fieldList}) VALUES ({$placeholderList})", + $class, + $data + ); + return $this->dbConnection->getLastItemId(); + } + + public function update(string $table, string $class, string $conditions, array $params, array $data): bool + { + $updateList = implode( + ', ', + array_map(fn($key) => "{$key} = :{$key}", array_keys($data)) + ); + $data = array_merge($params, $data); + + return $this->dbConnection->execute( + "UPDATE {$table} SET {$updateList} WHERE {$conditions}", + $class, + $data + ); + } + + public function delete(String $table, String $conditions, String $class, Array $params): bool { + return $this->dbConnection->execute("DELETE FROM {$table} WHERE {$conditions}", $class, $params); + } +} \ No newline at end of file diff --git a/src/Models/Exercise.php b/src/Models/Exercise.php new file mode 100644 index 0000000..154eb80 --- /dev/null +++ b/src/Models/Exercise.php @@ -0,0 +1,111 @@ +query = new Query(); + if (array_key_exists('title', $params)) { + $this->title = $params['title']; + } + } + + + public function getId(): ?int + { + return $this->id ?? null; + } + + + public function getTitle(): string + { + return $this->title; + } + + + public function setTitle(string $title): void + { + $this->title = $title; + } + + + public function getState(): string + { + return $this->state; + } + + + public function setState(string $state): void + { + $this->state = $state; + } + + + public function getFields(int $fieldId = null): array|Field + { + if (is_null($fieldId)) { + return $this->query->select('fields', Field::class, 'exercises_id = :id', [':id' => $this->id]); + } else { + return $this->query->select( + 'fields', + Field::class, + 'id = :field_id AND exercises_id = :exercises_id', + ['field_id' => $fieldId, 'exercises_id' => $this->id], + true + ); + } + } + + + + public function createField(Field $field): int + { + try { + return $this->query->insert('fields', Field::class, [ + 'label' => $field->getLabel(), + 'value_kind' => $field->getValueKind(), + 'exercises_id' => $this->id, + ]); + } catch (PDOException $e) { + error_log($e); + return false; + } + } + + + + public function deleteField(int $fieldId): void + { + foreach ($this->getFulfillments() as $fulfillment) { + $fulfillment->delete(); + } + $this->query->delete('fields', Field::class, 'id = :id', ['id' => $fieldId]); + } + + + public function getFulfillments(int $fulfillment = null): array|Fulfillment + { + if (is_null($fulfillment)) { + return $this->query->select('fulfillments', Fulfillment::class, 'exercises_id = :id', [':id' => $this->id]); + } else { + return $this->query->select( + 'fulfillments', + Fulfillment::class, + 'id = :field_id AND exercises_id = :exercises_id', + ['field_id' => $fulfillment, 'exercises_id' => $this->id], + true + ); + } + } +} \ No newline at end of file diff --git a/src/Models/ExerciseHelper.php b/src/Models/ExerciseHelper.php new file mode 100644 index 0000000..36f6f14 --- /dev/null +++ b/src/Models/ExerciseHelper.php @@ -0,0 +1,90 @@ +query = new Query(); + } + + + public function get(int $exerciseId = null): array|Exercise + { + if (is_null($exerciseId)) { + return $this->query->select('exercises', Exercise::class); + } else { + return $this->query->select('exercises', Exercise::class, 'id = :id', ['id' => $exerciseId], true); + } + } + + public function save(Exercise $exercise): int + { + if (is_null($exercise->getId())) { + return $this->create($exercise); + } else { + return $this->update($exercise); + } + } + + + private function create(Exercise $exercise): int + { + try { + return $this->query->insert( + 'exercises', + Exercise::class, + ['title' => $exercise->getTitle(), 'state' => $exercise->getState()] + ); + } catch (PDOException $e) { + error_log($e); + return false; + } + } + + + private function update(Exercise $exercise): int + { + try { + return $this->query->update( + 'exercises', + Exercise::class, + 'id = :id', + ['id' => $exercise->getId()], + ['title' => $exercise->getTitle(), 'state' => $exercise->getState()] + ); + } catch (PDOException $e) { + error_log($e); + return false; + } + } + + public function delete(int $exerciseId): bool + { + $exercise = $this->get($exerciseId); + $pdo = DBConnection::getInstance()->getPDO(); + try { + $pdo->beginTransaction(); + foreach ($exercise->getFields() as $field) { + $exercise->deleteField($field->getId()); + } + $this->query->delete('exercises', Exercise::class, 'id = :id', ['id' => $exerciseId]); + $pdo->commit(); + return true; + } finally { + // If the transaction has not been committed, roll it back + if ($pdo->inTransaction()) { + $pdo->rollBack(); + return false; + } + } + } +} \ No newline at end of file diff --git a/src/Models/Field.php b/src/Models/Field.php new file mode 100644 index 0000000..5f5d9bd --- /dev/null +++ b/src/Models/Field.php @@ -0,0 +1,84 @@ +query = new Query(); + if (array_key_exists('label', $params)) { + $this->label = $params['label']; + } + if (array_key_exists('value_kind', $params)) { + $this->value_kind = $params['value_kind']; + } + } + public function getId(): int + { + return $this->id; + } + public function setId(int $id): void + { + $this->id = $id; + } + public function getName(): string + { + return $this->name; + } + public function getDescription(): string + { + return $this->description; + } + public function getLabel(): string + { + return $this->label; + } + + public function setLabel(string $label): void + { + $this->label = $label; + } + + public function getValueKind(): string + { + return $this->value_kind; + } + + public function setValueKind(string $value_kind): void + { + $this->value_kind = $value_kind; + } + + public function update(): bool + { + try { + return $this->query->update( + 'fields', + Field::class, + 'id = :id', + ['id' => $this->id], + [ + 'label' => $this->getLabel(), + 'value_kind' => $this->getValueKind(), + ] + ); + } catch (PDOException $e) { + error_log($e); + return false; + } + } +} \ No newline at end of file diff --git a/src/Models/FieldsHasFulfillments.php b/src/Models/FieldsHasFulfillments.php new file mode 100644 index 0000000..41299d8 --- /dev/null +++ b/src/Models/FieldsHasFulfillments.php @@ -0,0 +1,15 @@ +value; + } +} diff --git a/src/Models/Fulfillment.php b/src/Models/Fulfillment.php new file mode 100644 index 0000000..9be9f9a --- /dev/null +++ b/src/Models/Fulfillment.php @@ -0,0 +1,116 @@ +query = new Query(); + if (array_key_exists('date', $params)) { + $this->date = $params['date']; + } + if (array_key_exists('exercise', $params)) { + $this->exercise = $params['exercise']; + } + } + + public function getId(): int + { + return $this->id; + } + + public function getDate(): string + { + return $this->date; + } + + public function save(array $answers = []): int + { + if (!isset($this->id)) { + return $this->create($answers); + } else { + return $this->update($answers); + } + } + + protected function create(array $answers = [[]]): int + { + try { + $fulfillmentsId = $this->query->insert( + 'fulfillments', + Fulfillment::class, + ['date' => $this->date, 'exercises_id' => $this->exercise->getId()] + ); + foreach ($answers as $key => $answer) { + $this->query->insert( + 'fields_has_fulfillments', + Fulfillment::class, + ['fulfillments_id' => $fulfillmentsId, 'fields_id' => $key, 'value' => $answer] + ); + } + return $fulfillmentsId; + } catch (PDOException $e) { + error_log($e); + return false; + } + } + + protected function update(array $answers = [[]]): int + { + try { + foreach ($answers as $fields_id => $answer) { + $this->query->update( + 'fields_has_fulfillments', + Fulfillment::class, + 'fields_id = :fields_id AND fulfillments_id = :fulfillments_id', + [ + 'fields_id' => $fields_id, + 'fulfillments_id' => $this->id, + ], + [ + 'value' => $answer, + ] + ); + } + return true; + } catch (PDOException $e) { + error_log($e); + return false; + } + } + + public function getValue(Field $field): string + { + $fieldsHasFulfillments = $this->query->select( + 'fields_has_fulfillments', + FieldsHasFulfillments::class, + 'fields_id = :fields_id AND fulfillments_id = :fulfillments_id', + [ + ':fields_id' => $field->getId(), + ':fulfillments_id' => $this->id, + ], + true + ); + return $fieldsHasFulfillments->getValue(); + } + + public function delete(): void + { + $this->query->delete( + 'fields_has_fulfillments', + FieldsHasFulfillments::class, + 'fulfillments_id = :fulfillments_id', + ['fulfillments_id' => $this->id] + ); + $this->query->delete('fulfillments', Fulfillment::class, 'id = :id', ['id' => $this->id]); + } +} diff --git a/src/Router/Route.php b/src/Router/Route.php new file mode 100644 index 0000000..007f376 --- /dev/null +++ b/src/Router/Route.php @@ -0,0 +1,78 @@ +path = trim($path, '/'); // Sets the path, trimming any leading/trailing slashes + $this->controller = $controller; // Sets the controller name + $this->method = $method; // Sets the method name + } + + /** + * Gets the path of the route + * + * @return string + */ + public function getPath(): string + { + return $this->path; // Returns the path + } + + /** + * Checks if the given URL matches the route + * + * @param string $url + * + * @return bool + */ + public function matches(string $url): bool + { + $url_components = parse_url($url); // Parses the URL into components + $path = preg_replace('#:([\w]+)#', '([0-9]+)', $this->path); // Replaces placeholders in the path with regex to match numbers + $pathToMatch = '/^\/' . str_replace('/', '\/', $path) . '$/'; // Prepares the regex pattern to match the path + + if (preg_match($pathToMatch, $url_components['path'], $matches)) { // Checks if the URL path matches the pattern + $this->matches = $matches; // Stores the matches + if (isset($url_components['query'])) { + $this->matches[] = $url_components['query']; // Adds the query component to matches if present + } + return true; // Returns true if matches + } else { + return false; // Returns false if no matches + } + } + + /** + * Executes the controller method based on the route + * + * @return void + */ + public function execute(): void + { + $controller = new $this->controller(); // Creates a new instance of the controller + $method = $this->method; // Sets the method to be called + + if (isset($this->matches[2])) { + $controller->$method($this->matches[1], $this->matches[2]); // Calls the method with two parameters if present + } elseif (isset($this->matches[1])) { + $controller->$method($this->matches[1]); // Calls the method with one parameter if present + } else { + $controller->$method(); // Calls the method with no parameters + } + } +} diff --git a/src/Router/Router.php b/src/Router/Router.php new file mode 100644 index 0000000..f03b0e5 --- /dev/null +++ b/src/Router/Router.php @@ -0,0 +1,106 @@ +routes['GET'][$name] = $route; // Adds the route to the GET routes array + } + + /** + * Registers a POST route + * + * @param string $name + * @param Route $route + * + * @return void + */ + public function post(string $name, Route $route): void + { + $this->routes['POST'][$name] = $route; // Adds the route to the POST routes array + } + + /** + * Runs the router to match and execute the appropriate route + * + * @return void + */ + public function run(): void + { + foreach ($this->routes[$_SERVER['REQUEST_METHOD']] as $route) { // Iterates through the routes for the current request method + if ($route->matches($_SERVER['REQUEST_URI'])) { // Checks if the route matches the current URI + $route->execute(); // Executes the matched route + } + } + } + + /** + * Generates a URL for the given route name and parameters + * + * @param string $name + * @param array $params + * @param string $query + * + * @return string + */ + public function generateUrl(string $name, array $params = [], string $query = ''): string + { + foreach ($this->routes as $routes) { + if (isset($routes[$name])) { + $path = '/' . $routes[$name]->getPath(); // Gets the path for the route + + foreach ($params as $key => $param) { + $path = str_replace(':' . $key, $param, $path); // Replaces path parameters with actual values + } + + return $path . ($query ? '?' . $query : ''); // Returns the complete URL with query string if provided + } + } + throw new InvalidUrlException(); // Throws an exception if the route is not found + } + + /** + * Redirects to the given route name with parameters + * + * @param string $name + * @param array $params + * + * @return void + */ + public function redirect(string $name, array $params = []): void + { + $location = $this->generateUrl($name, $params); // Generates the URL for redirection + header("Location: {$location}"); // Sends the HTTP header to redirect + } +} diff --git a/templates/exercises/answering.php b/templates/exercises/answering.php new file mode 100644 index 0000000..ce41202 --- /dev/null +++ b/templates/exercises/answering.php @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/templates/exercises/index.php b/templates/exercises/index.php new file mode 100644 index 0000000..0715c08 --- /dev/null +++ b/templates/exercises/index.php @@ -0,0 +1,125 @@ + + +
+
+

Building

+ + + + + + + + + + getState() == 'building'): ?> + + + + + + + +
Title
getTitle() ?> + getFields()): ?> + + + + + + + + + + +
+
+ +
+

Answering

+ + + + + + + + + + getState() == 'answering'): ?> + + + + + + + +
Title
getTitle() ?> + + + + + + +
+
+ +
+

Closed

+ + + + + + + + + + getState() == 'closed'): ?> + + + + + + + +
Title
getTitle() ?> + + + + + + +
+
+
+ \ No newline at end of file diff --git a/templates/exercises/new.php b/templates/exercises/new.php new file mode 100644 index 0000000..a23300e --- /dev/null +++ b/templates/exercises/new.php @@ -0,0 +1,17 @@ + +

+ +
+
+ + +
+
+
+ +
+
\ No newline at end of file diff --git a/templates/exercises/results.php b/templates/exercises/results.php new file mode 100644 index 0000000..6702a6e --- /dev/null +++ b/templates/exercises/results.php @@ -0,0 +1,60 @@ +generateUrl( + 'exercises_results', + ['exercise' => $params['exercise']->getId(),] + ) . '">' . $params['exercise']->getTitle() . ''; +$headerColor = 'results'; +?> + + + + + + + + + + + + + + + + getValue($field); ?> + + + + + +
Take $params['exercise']->getId(), "field" => $field->getId()] + ) ?>">getLabel() + ?>
+ $fulfillment->getId()] + ) ?>"> + getDate() ?> UTC + + + + + + + + + +
\ No newline at end of file diff --git a/templates/fields/edit.php b/templates/fields/edit.php new file mode 100644 index 0000000..0db3175 --- /dev/null +++ b/templates/fields/edit.php @@ -0,0 +1,57 @@ +getTitle()}"; +?> + +

Editing Field

+ +
+
+ + +
+
+ + +
+
+
+ +
+
\ No newline at end of file diff --git a/templates/fields/index.php b/templates/fields/index.php new file mode 100644 index 0000000..1b10ad1 --- /dev/null +++ b/templates/fields/index.php @@ -0,0 +1,81 @@ +getTitle()}"; +?> + +
+
+

Fields

+ + + + + + + + + + getFields() as $field) : ?> + + + + + + + + +
LabelValue kind
getLabel() ?>getValueKind() ?> + + + + + + +
+ getFields()): ?> + + Complete and be ready for answers + + +
+
+

New Field

+
+
+ + +
+
+ + +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/templates/fields/results.php b/templates/fields/results.php new file mode 100644 index 0000000..ce38861 --- /dev/null +++ b/templates/fields/results.php @@ -0,0 +1,36 @@ +generateUrl( + 'exercises_results', + ['exercise' => $params['exercise']->getId()] + ) . '">' . $params['exercise']->getTitle() . ''; +$headerColor = 'results'; +?> +

getLabel() ?>

+ + + + + + + + + + + + + + + +
TakeContent
+ $params['exercise']->getId(), "fulfillment" => $fulfillment->getId(),] + ) ?>"> + getDate() ?> UTC + + + getValue($params['field']); ?> +
\ No newline at end of file diff --git a/templates/fulfillments/edit.php b/templates/fulfillments/edit.php new file mode 100644 index 0000000..321cf6e --- /dev/null +++ b/templates/fulfillments/edit.php @@ -0,0 +1,41 @@ + + +

Your take

+

Bookmark this page, it's yours. You'll be able to come back later to finish.

+
+ + + getValueKind() == "single_line"): ?> + + + getValueKind() == "single_line_list"): ?> + + + getValueKind() == "multi_line"): ?> + + + + +
+ +
+
\ No newline at end of file diff --git a/templates/fulfillments/new.php b/templates/fulfillments/new.php new file mode 100644 index 0000000..0aa582a --- /dev/null +++ b/templates/fulfillments/new.php @@ -0,0 +1,35 @@ + + +

Your take

+

If you'd like to come back later to finish, simply submit it with blanks

+
+ getFields() as $field) : ?> + + getValueKind() == "single_line") : ?> + + + getValueKind() == "single_line_list") : ?> + + + getValueKind() == "multi_line") : ?> + + + + +
+ +
+
\ No newline at end of file diff --git a/templates/fulfillments/results.php b/templates/fulfillments/results.php new file mode 100644 index 0000000..f403225 --- /dev/null +++ b/templates/fulfillments/results.php @@ -0,0 +1,18 @@ +generateUrl( + 'exercises_results', + ['exercise' => $params['exercise']->getId()] + ) . '">' . $params['exercise']->getTitle() . ''; +$headerColor = 'results'; +?> + +

getDate() ?>

+
+ +
getLabel() ?>
+
getValue($field) ?>
+ +
\ No newline at end of file diff --git a/templates/layout.php b/templates/layout.php new file mode 100644 index 0000000..9bc09a1 --- /dev/null +++ b/templates/layout.php @@ -0,0 +1,42 @@ + + + + + ExerciseLooper + + + + + + + + + + + +
+
+

+

Exercise
Looper

+
+
+ +
+
+ + + +
+
+ + +
+ ExerciseLooper + +
+
+ + \ No newline at end of file diff --git a/templates/layoutold.php b/templates/layoutold.php new file mode 100644 index 0000000..9bc09a1 --- /dev/null +++ b/templates/layoutold.php @@ -0,0 +1,42 @@ + + + + + ExerciseLooper + + + + + + + + + + + +
+
+

+

Exercise
Looper

+
+
+ +
+
+ + + +
+
+ + +
+ ExerciseLooper + +
+
+ + \ No newline at end of file diff --git a/templates/site/index.php b/templates/site/index.php new file mode 100644 index 0000000..9031a16 --- /dev/null +++ b/templates/site/index.php @@ -0,0 +1,17 @@ + +
\ No newline at end of file