diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5d5ae2f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM php:8.3-cli + +WORKDIR /usr/src/app + +RUN apt-get update && apt-get install -y \ + git \ + unzip \ + libzip-dev + +RUN docker-php-ext-install zip + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +COPY composer.json composer.lock ./ +RUN composer install --no-dev --optimize-autoloader + +COPY . . + +CMD ["php", "browser.php"] diff --git a/README.md b/README.md index 65c7632..72c1a0d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # ryobi-crawler +## Project start + +1. Run `migration.php` file to create `database.sqlite` and create tables. +2. Run `php index.php app:scrape` command to scrape all the products from the ryobi website. \ No newline at end of file diff --git a/browser.php b/browser.php index af1bbc8..18ff0ff 100644 --- a/browser.php +++ b/browser.php @@ -35,4 +35,4 @@ if (empty($_GET)) { $template = 'productList.html.twig'; $products = Product::with('price')->orderByDesc('starred')->orderByDesc('created_by')->get(); } -$twig->display($template, ['products' => $products, 'product' => $product, 'search' => $_GET['search']]); +$twig->display($template, ['products' => $products ?? [], 'product' => $product ?? [], 'search' => $_GET['search'] ?? '']); diff --git a/composer.json b/composer.json index 4ef9356..6fadfec 100644 --- a/composer.json +++ b/composer.json @@ -2,9 +2,9 @@ "require": { "guzzlehttp/guzzle": "^7.0", "symfony/var-dumper": "^7.0", - "illuminate/database": "^11.0", + "illuminate/database": "11.26.0.0", "ext-json": "*", - "twig/twig": "^3.0", + "twig/twig": "3.14.0.0", "symfony/console": "^7.0" }, "autoload": { diff --git a/composer.lock b/composer.lock index a931dd7..e9491a3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2c2a4512e1fb86ef1101792390337ad1", + "content-hash": "e9489916095593f696613b706467239b", "packages": [ { "name": "brick/math", @@ -228,22 +228,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.8.1", + "version": "7.9.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.1", - "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -254,9 +254,9 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -334,7 +334,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" }, "funding": [ { @@ -350,20 +350,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:35:24+00:00" + "time": "2024-07-24T11:22:20+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", "shasum": "" }, "require": { @@ -371,7 +371,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -417,7 +417,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.2" + "source": "https://github.com/guzzle/promises/tree/2.0.3" }, "funding": [ { @@ -433,20 +433,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:19:20+00:00" + "time": "2024-07-18T10:29:17+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "shasum": "" }, "require": { @@ -461,8 +461,8 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -533,7 +533,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.2" + "source": "https://github.com/guzzle/psr7/tree/2.7.0" }, "funding": [ { @@ -549,20 +549,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:05:35+00:00" + "time": "2024-07-18T11:15:46+00:00" }, { "name": "illuminate/collections", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "6a5cd843d209a270587d62c40d797ea35e47ed5d" + "reference": "4d333ea19a27230b424b9af56f34cd658b5bbce2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/6a5cd843d209a270587d62c40d797ea35e47ed5d", - "reference": "6a5cd843d209a270587d62c40d797ea35e47ed5d", + "url": "https://api.github.com/repos/illuminate/collections/zipball/4d333ea19a27230b424b9af56f34cd658b5bbce2", + "reference": "4d333ea19a27230b424b9af56f34cd658b5bbce2", "shasum": "" }, "require": { @@ -604,20 +604,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-13T20:54:13+00:00" + "time": "2024-09-27T14:54:48+00:00" }, { "name": "illuminate/conditionable", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", - "reference": "e4c5c9b855c60c7bb16ce92ca9372684448cce47" + "reference": "362dd761b9920367bca1427a902158225e9e3a23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/conditionable/zipball/e4c5c9b855c60c7bb16ce92ca9372684448cce47", - "reference": "e4c5c9b855c60c7bb16ce92ca9372684448cce47", + "url": "https://api.github.com/repos/illuminate/conditionable/zipball/362dd761b9920367bca1427a902158225e9e3a23", + "reference": "362dd761b9920367bca1427a902158225e9e3a23", "shasum": "" }, "require": { @@ -650,20 +650,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-02-07T10:39:14+00:00" + "time": "2024-06-28T20:10:30+00:00" }, { "name": "illuminate/container", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", - "reference": "78cbe88cdc7300efd4cf90244abec2e3c42219bb" + "reference": "bc49d144a20b0d432e1ac812c9e056594b6c6480" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/container/zipball/78cbe88cdc7300efd4cf90244abec2e3c42219bb", - "reference": "78cbe88cdc7300efd4cf90244abec2e3c42219bb", + "url": "https://api.github.com/repos/illuminate/container/zipball/bc49d144a20b0d432e1ac812c9e056594b6c6480", + "reference": "bc49d144a20b0d432e1ac812c9e056594b6c6480", "shasum": "" }, "require": { @@ -701,20 +701,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-09-15T13:17:41+00:00" + "time": "2024-10-08T13:34:53+00:00" }, { "name": "illuminate/contracts", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "fae548ad43f569fc506f40385b2e0dcf1f4eb2c9" + "reference": "56312862af937bd6da8e6dc8bbd88188dfb478f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/fae548ad43f569fc506f40385b2e0dcf1f4eb2c9", - "reference": "fae548ad43f569fc506f40385b2e0dcf1f4eb2c9", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/56312862af937bd6da8e6dc8bbd88188dfb478f8", + "reference": "56312862af937bd6da8e6dc8bbd88188dfb478f8", "shasum": "" }, "require": { @@ -749,20 +749,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-02-23T15:52:10+00:00" + "time": "2024-09-22T15:08:08+00:00" }, { "name": "illuminate/database", - "version": "v11.0.6", + "version": "v11.26.0", "source": { "type": "git", "url": "https://github.com/illuminate/database.git", - "reference": "4ed34edc7d7980971b3657842efe72280903a63d" + "reference": "1373985d7695c5a635036b877bfc4f8d3a932255" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/4ed34edc7d7980971b3657842efe72280903a63d", - "reference": "4ed34edc7d7980971b3657842efe72280903a63d", + "url": "https://api.github.com/repos/illuminate/database/zipball/1373985d7695c5a635036b877bfc4f8d3a932255", + "reference": "1373985d7695c5a635036b877bfc4f8d3a932255", "shasum": "" }, "require": { @@ -782,6 +782,7 @@ "illuminate/events": "Required to use the observers with Eloquent (^11.0).", "illuminate/filesystem": "Required to use the migrations (^11.0).", "illuminate/pagination": "Required to paginate the result set (^11.0).", + "laravel/serializable-closure": "Required to handle circular references in model serialization (^1.3).", "symfony/finder": "Required to use Eloquent model factories (^7.0)." }, "type": "library", @@ -817,20 +818,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-12T18:18:48+00:00" + "time": "2024-09-27T14:53:18+00:00" }, { "name": "illuminate/macroable", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", - "reference": "e1be58f9b2af73f242dc6a9add1f376b3ec89eef" + "reference": "e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/macroable/zipball/e1be58f9b2af73f242dc6a9add1f376b3ec89eef", - "reference": "e1be58f9b2af73f242dc6a9add1f376b3ec89eef", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed", + "reference": "e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed", "shasum": "" }, "require": { @@ -863,20 +864,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-06-08T14:08:27+00:00" + "time": "2024-06-28T20:10:30+00:00" }, { "name": "illuminate/support", - "version": "v11.0.6", + "version": "v11.27.2", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "79c13b3c068db94563f002b6e49dcb5d03fd19a8" + "reference": "a567431e4820363d0bc28bdf14914ab16a2e63ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/79c13b3c068db94563f002b6e49dcb5d03fd19a8", - "reference": "79c13b3c068db94563f002b6e49dcb5d03fd19a8", + "url": "https://api.github.com/repos/illuminate/support/zipball/a567431e4820363d0bc28bdf14914ab16a2e63ef", + "reference": "a567431e4820363d0bc28bdf14914ab16a2e63ef", "shasum": "" }, "require": { @@ -900,6 +901,7 @@ }, "suggest": { "illuminate/filesystem": "Required to use the composer class (^11.0).", + "laravel/serializable-closure": "Required to use the once function (^1.3).", "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", "ramsey/uuid": "Required to use Str::uuid() (^4.7).", "symfony/process": "Required to use the composer class (^7.0).", @@ -915,6 +917,7 @@ }, "autoload": { "files": [ + "functions.php", "helpers.php" ], "psr-4": { @@ -937,20 +940,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-13T15:00:31+00:00" + "time": "2024-10-08T18:54:07+00:00" }, { "name": "nesbot/carbon", - "version": "3.1.1", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2" + "reference": "bbd3eef89af8ba66a3aa7952b5439168fbcc529f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2", - "reference": "34ccf6f6b49c915421c7886c88c0cb77f3ebbfd2", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bbd3eef89af8ba66a3aa7952b5439168fbcc529f", + "reference": "bbd3eef89af8ba66a3aa7952b5439168fbcc529f", "shasum": "" }, "require": { @@ -968,14 +971,14 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.18.0", - "kylekatarnls/multi-tester": "^2.2.0", - "ondrejmirtes/better-reflection": "^6.11.0.0", - "phpmd/phpmd": "^2.13.0", - "phpstan/extension-installer": "^1.3.0", - "phpstan/phpstan": "^1.10.20", - "phpunit/phpunit": "^10.2.2", - "squizlabs/php_codesniffer": "^3.7.2" + "friendsofphp/php-cs-fixer": "^3.57.2", + "kylekatarnls/multi-tester": "^2.5.3", + "ondrejmirtes/better-reflection": "^6.25.0.4", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.11.2", + "phpunit/phpunit": "^10.5.20", + "squizlabs/php_codesniffer": "^3.9.0" }, "bin": [ "bin/carbon" @@ -1043,7 +1046,7 @@ "type": "tidelift" } ], - "time": "2024-03-13T12:42:37+00:00" + "time": "2024-08-19T06:22:39+00:00" }, { "name": "psr/clock", @@ -1200,20 +1203,20 @@ }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -1237,7 +1240,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -1249,9 +1252,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -1403,16 +1406,16 @@ }, { "name": "symfony/clock", - "version": "v7.0.5", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "8b9d08887353d627d5f6c3bf3373b398b49051c2" + "reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/8b9d08887353d627d5f6c3bf3373b398b49051c2", - "reference": "8b9d08887353d627d5f6c3bf3373b398b49051c2", + "url": "https://api.github.com/repos/symfony/clock/zipball/3dfc8b084853586de51dd1441c6242c76a28cbe7", + "reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7", "shasum": "" }, "require": { @@ -1457,7 +1460,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.0.5" + "source": "https://github.com/symfony/clock/tree/v7.1.1" }, "funding": [ { @@ -1473,20 +1476,20 @@ "type": "tidelift" } ], - "time": "2024-03-02T12:46:12+00:00" + "time": "2024-05-31T14:57:53+00:00" }, { "name": "symfony/console", - "version": "v7.0.7", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { @@ -1550,7 +1553,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.7" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -1566,20 +1569,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -1588,7 +1591,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1617,7 +1620,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -1633,24 +1636,24 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1696,7 +1699,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -1712,24 +1715,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1774,7 +1777,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -1790,24 +1793,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1855,7 +1858,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -1871,24 +1874,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1935,7 +1938,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1951,24 +1954,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "name": "symfony/polyfill-php81", + "version": "v1.31.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1982,7 +1985,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Php81\\": "" }, "classmap": [ "Resources/stubs" @@ -1993,10 +1996,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -2006,7 +2005,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -2015,7 +2014,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" }, "funding": [ { @@ -2031,25 +2030,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-php80": "^1.14" + "php": ">=7.2" }, "type": "library", "extra": { @@ -2092,7 +2090,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" }, "funding": [ { @@ -2108,7 +2106,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", @@ -2195,16 +2193,16 @@ }, { "name": "symfony/string", - "version": "v7.0.7", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { @@ -2218,6 +2216,7 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { + "symfony/emoji": "^7.1", "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", @@ -2261,7 +2260,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.7" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -2277,20 +2276,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/translation", - "version": "v7.0.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "5b75e872f7d135d7abb4613809fadc8d9f3d30a0" + "reference": "235535e3f84f3dfbdbde0208ede6ca75c3a489ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/5b75e872f7d135d7abb4613809fadc8d9f3d30a0", - "reference": "5b75e872f7d135d7abb4613809fadc8d9f3d30a0", + "url": "https://api.github.com/repos/symfony/translation/zipball/235535e3f84f3dfbdbde0208ede6ca75c3a489ea", + "reference": "235535e3f84f3dfbdbde0208ede6ca75c3a489ea", "shasum": "" }, "require": { @@ -2355,7 +2354,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.0.4" + "source": "https://github.com/symfony/translation/tree/v7.1.5" }, "funding": [ { @@ -2371,20 +2370,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:20+00:00" + "time": "2024-09-16T06:30:38+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.4.1", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "06450585bf65e978026bda220cdebca3f867fde7" + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", - "reference": "06450585bf65e978026bda220cdebca3f867fde7", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", "shasum": "" }, "require": { @@ -2393,7 +2392,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2433,7 +2432,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" }, "funding": [ { @@ -2449,20 +2448,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.0.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670" + "reference": "e20e03889539fd4e4211e14d2179226c513c010d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e03ad7c1535e623edbb94c22cc42353e488c6670", - "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e20e03889539fd4e4211e14d2179226c513c010d", + "reference": "e20e03889539fd4e4211e14d2179226c513c010d", "shasum": "" }, "require": { @@ -2516,7 +2515,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.0.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.1.5" }, "funding": [ { @@ -2532,34 +2531,41 @@ "type": "tidelift" } ], - "time": "2024-02-15T11:33:06+00:00" + "time": "2024-09-16T10:07:02+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.14.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72", + "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22" + "symfony/polyfill-php81": "^1.29" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -2592,7 +2598,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.14.0" }, "funding": [ { @@ -2604,7 +2610,7 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-09-09T17:55:12+00:00" }, { "name": "voku/portable-ascii", diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e3b0829 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + php-app: + build: . + volumes: + - .:/usr/src/app + command: > + sh -c "composer install && php -S 0.0.0.0:8000 -t /usr/src/app" + ports: + - "9000:8000" \ No newline at end of file diff --git a/index.php b/index.php index 86a1ee7..6d364c9 100644 --- a/index.php +++ b/index.php @@ -2,7 +2,7 @@ include_once 'vendor/autoload.php'; - +use Krzysiej\RyobiCrawler\Command\Migrate; use Krzysiej\RyobiCrawler\Command\ScrapeWebsite; use Symfony\Component\Console\Application; @@ -13,6 +13,7 @@ if (php_sapi_name() !== 'cli') { exit; } -$application = new Application('Ryobi website scraper application', '1.0.0'); +$application = new Application('Ryobi website scraper application', '1.1.0'); $application->add(new ScrapeWebsite()); +$application->add(new Migrate()); $application->run(); diff --git a/src/Command/Migrate.php b/src/Command/Migrate.php new file mode 100644 index 0000000..785fb24 --- /dev/null +++ b/src/Command/Migrate.php @@ -0,0 +1,91 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => __DIR__ . '/../../database.sqlite', + ]); + $capsule->setAsGlobal(); + $capsule->bootEloquent(); + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + $this->createProductsTable(); + $this->createPricesTable(); + $this->createStocksTable(); + + return Command::SUCCESS; + } + + public function createProductsTable(): void + { + if (!Capsule::schema()->hasTable('products')) { + Capsule::schema()->create('products', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + $table->integer('skuID')->unique(); + $table->integer('agilityID'); + $table->integer('availableQuantity'); + $table->integer('stock'); + $table->json('categories'); + $table->string('image'); + $table->string('subTitle'); + $table->string('variantCode'); + $table->string('modelCode'); + $table->string('url'); + $table->boolean('starred')->default(false); + $table->timestamps(); + }); + } + } + + public function createPricesTable(): void + { + if (!Capsule::schema()->hasTable('prices')) { + Capsule::schema()->create('prices', function (Blueprint $table) { + $table->increments('id'); + $table->foreignId('product_id'); + $table->float('price'); + $table->float('productStandardPrice'); + $table->float('lowestProductPrice30Days'); + $table->timestamps(); + }); + } + } + + public function createStocksTable(): void + { + if (!Capsule::schema()->hasTable('stocks')) { + Capsule::schema()->create('stocks', function (Blueprint $table) { + $table->increments('id'); + $table->foreignId('product_id'); + $table->integer('availableQuantity'); + $table->integer('stock'); + $table->boolean('isInStock'); + $table->boolean('previouslyHadStock'); + $table->boolean('isNew'); + $table->boolean('isComingSoon'); + $table->boolean('isOnSale'); + $table->timestamps(); + }); + } + } +} diff --git a/src/Command/ScrapeWebsite.php b/src/Command/ScrapeWebsite.php index 76ed394..e1ede47 100644 --- a/src/Command/ScrapeWebsite.php +++ b/src/Command/ScrapeWebsite.php @@ -5,21 +5,23 @@ declare(strict_types=1); namespace Krzysiej\RyobiCrawler\Command; use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; use Illuminate\Database\Capsule\Manager as Capsule; use Krzysiej\RyobiCrawler\Models\Price; use Krzysiej\RyobiCrawler\Models\Product; +use Krzysiej\RyobiCrawler\Models\Stock; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'app:scrape')] +#[AsCommand(name: 'app:scrape', description: 'Scrape all products from Ryobi website')] class ScrapeWebsite extends Command { private Client $client; - protected function configure() + protected function configure(): void { $capsule = new Capsule; $capsule->addConnection([ @@ -44,6 +46,7 @@ class ScrapeWebsite extends Command $progress->finish(); $output->writeln(''); $output->writeln('DONE'); + return Command::SUCCESS; } @@ -52,22 +55,28 @@ class ScrapeWebsite extends Command $products = []; $page = 0; do { - $res = $this->client->request('POST', 'https://pl.ryobitools.eu/api/product-listing/get-products', [ - 'form_params' => [ - "includePreviousPages" => false, - "pageIndex" => $page, - "pageSize" => 100, - "cultureCode" => "pl-PL", - ] - ]); - $page++; - $responseObject = json_decode($res->getBody()->getContents()); - $products = array_merge($products, $responseObject->products); - } while ((bool)$responseObject->canLoadMore); + try { + $res = $this->client->request('POST', 'https://pl.ryobitools.eu/api/product-listing/get-products', [ + 'form_params' => [ + "includePreviousPages" => false, + "pageIndex" => $page, + "pageSize" => 100, + "cultureCode" => "pl-PL", + ] + ]); + $responseObject = json_decode($res->getBody()->getContents()); + $products = array_merge($products, $responseObject->products); + $page++; + $canLoadMore = $responseObject->canLoadMore; + } catch (GuzzleException $e) { + return $products; + } + } while ($canLoadMore); + return $products; } - private function saveProduct(\stdClass $product) + private function saveProduct(\stdClass $product): void { /** @var Product $productModel */ $productModel = Product::firstOrNew(['skuID' => $product->skuID]); @@ -90,5 +99,17 @@ class ScrapeWebsite extends Command $price->lowestProductPrice30Days = $product->lowestProductPrice30Days; $productModel->price()->save($price); } + $stockExist = $productModel->stock()->whereRaw("strftime('%Y-%m-%d', created_at) = ?", [date('Y-m-d')])->exists(); + if (!$stockExist) { + $stock = new Stock(); + $stock->availableQuantity = $product->availableQuantity; + $stock->stock = $product->stock; + $stock->isInStock = $product->isInStock; + $stock->previouslyHadStock = $product->previouslyHadStock; + $stock->isNew = $product->isNew; + $stock->isComingSoon = $product->isComingSoon; + $stock->isOnSale = $product->isOnSale; + $productModel->stock()->save($stock); + } } -} \ No newline at end of file +} diff --git a/src/Models/Product.php b/src/Models/Product.php index 5ecf358..61f22c9 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -29,6 +29,10 @@ class Product extends Model { return $this->hasMany(Price::class); } + public function stock(): HasMany + { + return $this->hasMany(Stock::class); + } public function toggleStarred(): self { @@ -42,5 +46,4 @@ class Product extends Model get: fn(string $value) => array_reverse(json_decode($value, 1)), ); } - -} \ No newline at end of file +} diff --git a/src/Models/Stock.php b/src/Models/Stock.php new file mode 100644 index 0000000..262f26a --- /dev/null +++ b/src/Models/Stock.php @@ -0,0 +1,25 @@ +belongsTo(Product::class); + } +} diff --git a/src/templates/template.html.twig b/src/templates/template.html.twig index 484a50f..6302287 100644 --- a/src/templates/template.html.twig +++ b/src/templates/template.html.twig @@ -9,11 +9,11 @@ crossorigin="anonymous"/>
-