Application used for pulling products in an async fashion from Shopify API, along with their storage and visual display on the web UI.
Project runs on minimal required PHP version 8.2.
It requires: ext-pdo
, ext-pdo_mysql
and ext-intl
extensions to be installed.
If they are not in the system, install by running sudo apt install php8.2-{pdo,mysql,intl}
.
Also, a redis-server and mysql 8 by default should be installed and running on system (didn't have time to dockerize).
If you are going to use other RDBMS, you should install the appropriate PHP extensions for PDO (e.g., ext-pdo_pgsql
and what not).
- Clone the repository
- Run
cp .env.example .env
to copy environment variables onto.env
file which will be used in the app - Run
composer install
to install all the back-end dependencies. There are no front-end dependencies to install. - Run
mysql -u <database_user> -p < src/Database/init.sql
from project root to migrate database schema. Be sure to use your local DB credentials - Fill out missing environment variable values (to get Shopify access token, custom development store URI and store API version, visit development stores and custom apps in Shopify docs). When creating a custom app, it will automatically seed with products, they'll do fine for our purposes.
Easiest way to start, would be to run php -S 127.0.0.1:8888 -t src/public
in root directory and visit 127.0.0.1:8888
in your browser.
Choose the appropriate port if port 8888
is already listening.
For processing potentially long-running tasks, a queue worker is being used. By default, it uses Redis for storage through predis/predis
Composer package.
To start it, run php start-queue-worker.php
and leave it running.
When there will be a task to process and when it's done, queue worker will let you know in the console where you started the process.
NB: For the sake of this task, this is mandatory in order for products to be refreshed. Otherwise, you can just instantiate RefreshProducts
job and run handle
method to process it synchronously.
For simplicity, routes and "controllers" are handled in one file - Routing/routes.php
, controllers are Closures with ContainerInterface
injected into them that you can use.
In case of needing a new route, register it with $router-><method>('/test', fn () => ...)
. When route is not found, closure defined with $router->abortWith(fn () => ...)
will be called.
Currently, for sake of showcasing, database, views, http requests, queue worker and queue driver are registered in service container.
For example, to create different storage logic for products, you can create an implementation to Database/Contracts/BaseDatabase
interface.
These implementations can be then added in DatabaseDriverFactory
as on of the options it could resolve to. Same with QueueDriverFactory
. It would be better to allow extensibility through some addFactoryDefinition
closure that would add to resolvable drivers, but for now, you have to manually register new drivers.
This app is not production ready. For it to be ready, there should be a lot more try/catch statements in place to handle mishaps, edge-cases should be covered when it comes to unexpected results from DB/elsewhere and above all - a lot more tests to cover functionality and its edge-cases etc.
In order to do all of that, it would take well over the time it already took, therefore I have tried to prioritize certain things.
This should be used as a display of my skill set only.