GShop modules
Introduction
This application is based on the skeleton application using the Laminas MVC layer and module systems, on top of Rest and Rpc rhubbit core modules
Required library
Media setting
Install ffmpeg to manage video thumb auto generate process
$ sudo apt-get install ffmpeg
Install dependency
Install dependency modules with:
$ composer install
Download required npm package with
$ npm install
Generate spec
OpenApi spec / redoc
Generate your web services documentation in
/public/doc/api.html from open api spec with:
$ npm run "Bundle HTML spec"
Module spec / pandoc
Download package following instruction at https://pandoc.org/installing.html
Generate your modules documentation in
/public/doc/modules.html from all module
*.md files with:
$ npm run "Modules spec"
Config params
This is the global application config params list.
Set this parameters in
local.php|global.php under
/config/autoload folder to define application
behaviours:
return [
//...
'log' => true,
'version' => 'x.y.z',
'logpath' => '/var/www/your-app-folder/log',
'log_level' => [
'cli' => \Monolog\Level::Debug,
'listener' => \Monolog\Level::Debug,
'web' => \Monolog\Level::Debug,
],
'clipath' => '/var/www/your-app-folder/vendor/bin/laminas',
//...
];
| Parameter | Description |
|---|---|
log |
If set to TRUE application log are enabled, otherwise
every app log will be ignored |
version |
Application version number express with semver syntax |
logpath |
folder where log will be saved |
log_level |
log criteria in use foreach of the supported area |
log_level.cli |
command line interface log level saved in
[logpath]/cli.log file |
log_level.listener |
listener log level saved in [logpath]/listener.log
file |
log_level.web |
web log level saved in [logpath]/web.log file |
clipath |
command line interface base path, used when application try to
exec(/*cli-command*/) |
ChannelManager
Description of setting to add in your application
local.php / global.php file to configure
ChannelManager module
List of channel
Add the channel key to your application’s
configuration file and assign it aa array of configuration blocks, one
for each supported channel.
return [
// ...
'channel' => [
[
'bundle' => 'my.channel.name',
'queue_bundle' => 'test.queue',
'content_provider' => \Your\Helper\ContentProvider::class,
'type' => 'shopify', //or wordpress, farfetch, ...
'api_config' => [
// parameters required to configure channel by type
],
],
// other channel ...
],
// ...
];
Each supported channel configuration block must include the following attributes
| Attribute | Description |
|---|---|
bundle |
unique identifying name of the channel (there cannot be two channels with the same name) |
queue_bundle |
unique identifying queue bundle name of valid queue initialized
via queue:init [options] command exposed by
QueueManager module |
content_provider |
name of subclass implementing
ChannelManager\Sdk\Interface\IContentProvider
interface |
type |
one of the supported channel type, accepted values are:
shopify, wordpress, farfetch …
(at this moment only shopify was implemented) |
api_config |
custom parameters needed to configure each channel type (more information in the next sections) |
Channel API config
In this section you will find the different supported channel
type API configuration params
Shopify
Add the following parameters to configure shopify
channel
return [
// ...
'channel' => [
[
// ... rest of channel config
'type' => 'shopify',
'api_config' => [
'url' => 'https://site-name.myshopify.com/admin/api/2025-04/graphql.json',
'headers' => [
'Accept-Language' => 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7',
'X-Shopify-Access-Token' => 'your_access_token'
],
'TaxonomyCategoryId' => 'gid://shopify/TaxonomyCategory/xxx-1234',
'LocationId' => 'gid://shopify/Location/12345',
'PublicationId' => 'gid://shopify/Publication/12345',
],
],
// other channel ...
],
// ...
];
Each shopify channel configuration block
must include the following attributes
| Attribute | Description |
|---|---|
url |
The URL of shopify GraphQL API got from shopify backend |
headers |
key / values pair of custom headers to add on every shopify
GraphQL request - Accept-Language: required as
workaround of shopify bug to set standard response message
language- X-Shopify-Access-Token: token got from
shopify backend to authenticate every GraphQL
requestPS: You can add any other custom headers to the two mandatory ones above. |
TaxonomyCategoryId |
gid of a shopify category object set
in every synced product mutation request |
LocationId |
gid of a shopify location object set
in every synced product mutation request |
PublicationId |
gid of a shopify publication object
set in every synced product mutation request |
CLI command
List of all command line interface exposed by ChannelManager module
SYNC
$ cm:sync [options]
Start to sync entity with id in input on channel selected by its bundle name.
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-c, --channel=CHANNEL # The bundle name of the channel where the entity will be synced
-t, --type=TYPE # The type of channel where the entity will be synced (eg. shopify|wordpress|farfetch|...
-i, --id=ID # The unique application identifier of the entity to sync
-x, --eid=EID # The unique external channel identifier of the entity to sync (used only if --method=delete
-e, --entity=ENTITY # The the entity type to sync (product|media)
-m, --method=METHOD # The operation to execute when sync (create|update|delete)
-l, --log-filename=LOG-FILENAME # Custom queue log filename
-f, --force[=FORCE] # Force update skipping last sync date check
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-V, --version # Display this application version
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose # Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
# get application product with id 5 and create product on shopify channel with bundle name my.channel
$ ./vendor/bin/laminas cm:sync -n -y -vvv -c my.channel -t shopify -m create -e product -i 5
# get application product with id 5 and update product on shopify channel with bundle name my.channel
$ ./vendor/bin/laminas cm:sync -n -y -vvv -c my.channel -t shopify -m update -e product -i 5
# get application product with id 5 and delete product on shopify channel with bundle name my.channel
$ ./vendor/bin/laminas cm:sync -n -y -vvv -c my.channel -t shopify -m delete -e product -i 5
# useful when main media is deleted working directly with externalId
$ ./vendor/bin/laminas cm:sync -n -y -vvv -c my.channel -t shopify -m delete -e media -x "gid://shopify/Media/1234567890"
These commands will typically be generated by the system
autonomously and executed by queuing them in a queue managed by the
QueueManager module.
Database
This module implement standard Database interface based on Propel ORM
Config params
This is the module application config params list.
Set this parameters in
local.php|global.php under
/config/autoload folder to define application
behaviours:
return [
//...
'database' => [
'enable_log' => true,
'logfilepath' => '/var/www/your-app-folder/log/database.log',
'connections' => [
'YourDB' => [
'dsn' => 'mysql:host=localhost;dbname=YourDB;charset=utf8',
'host' => 'localhost',
'usr' => 'db-user',
'pwd' => 'xxxxxxxxx',
'dbname' => 'YourDB',
],
],
],
//...
];
| Parameter | Description |
|---|---|
enable_log |
If set to TRUE every query executed via propel ORM
will be saved in [logfilepath] file |
logfilepath |
absolute file path where log will be saved |
connections |
list of supported db connection |
connections.[dbname] |
connection params array of a specific db |
connections.[dbname].dns |
dns connection param of a specific db |
connections.[dbname].host |
host connection param of a specific db |
connections.[dbname].usr |
username connection param of a specific db |
connections.[dbname].pwd |
password connection param of a specific db |
connections.[dbname].dbname |
database name of a specific db |
Initialize DB
1 - Move from <project_folder> to database
module folder:
$ cd module/Database
2 - run the following command to generate file in
/generated-conf, /generated-sql,
/generated-classes folders:
$ ../../vendor/propel/propel/bin/propel config:convert
$ ../../vendor/propel/propel/bin/propel sql:build
$ ../../vendor/propel/propel/bin/propel model:build
3 - update autoload including /generated-classes
reference with:
$ composer update
Diff / Migrate
1 - Move from <project_folder> to database
module folder:
$ cd module/Database
2 - run the following commands to generate migration:
$ ../../vendor/propel/propel/bin/propel diff
$ ../../vendor/propel/propel/bin/propel migrate
$ ../../vendor/propel/propel/bin/propel model:build
3 - update autoload including /generated-classes
reference with:
$ composer update
Queue manager
A queue manager service instance will listen queue messages sent on specific queue identified by instance param ad execute cli command received in message event body.
Configure server
Install module
The queue management service could be based on a cloud hosted RabbitMQ server that require amqp module.
Install php8.2-amqp module on server
$ sudo apt install php-amqp
$ sudo apt install php8.2-amqp
Then add this extension to PHP with
extension = 'amqp.so' in
/etc/php/8.2/apache2/php.ini
Register service
To initialize this service you need to copy predefined
rhubbit.queue@.service template in your
systemd folder
$ sudo cp /YourProject/module/QueueManager/bin/rhubbit.queue@.service /etc/systemd/system/rhubbit.queue@.service
and replacing your application root folder path in service
ExecStart editing configuration line path before
/vendor/... part
# ...
[Service]
Type=simple
ExecStart=/var/www/your_project/vendor/bin/laminas queue:manager -vvv -n -y -b %I
# ...
then reload systemd daemon files and enable your service template
$ sudo systemctl daemon-reload
$ sudo systemctl enable rhubbit.queue@.service
Instantiate service
Now your can instantiate monitor and start/stop your service
passing valid queue bundle name as instance param
after @
$ sudo service rhubbit.queue@<queue.bundle>.service start # start service
$ sudo service rhubbit.queue@<queue.bundle>.service status # monitor service status
$ sudo service rhubbit.queue@<queue.bundle>.service stop # stop service
Instance param <queue.bundle> must be the valid
bundle name of database registered Text / RabbitMQ queue.
1 - Register queue
To register a valid queue in application database execute a command like this
$ ./vendor/bin/laminas queue:init -y -e -b test.queue -u file:///var/www/your-project/queue/cli -t "topic1|topic2"
Now you can use test.queue bundle name as service
instance param.
2 - Check service
Now if you check the application service list with
systemctl | grep rhubbit.queue@ you should see something
like this
$ systemctl | grep rhubbit.queue@
rhubbit.queue@test.queue.service loaded active running Rhubbit - queue manager ON test.queue
and if you check your service status with
sudo service rhubbit.queue@test.queue.service status you
should see something like this
$ sudo systemctl status scm_wp_queue.service
● rhubbit.queue@test.queue.service - Rhubbit - queue manager ON test.queue
Loaded: loaded (/etc/systemd/system/rhubbit.queue@.service; disabled; vendor preset: enabled)
Active: active (running) since Tue 2025-07-15 17:38:40 CEST; 24min ago
Main PID: 36527 (php)
Tasks: 1 (limit: 2324)
Memory: 23.6M
CGroup: /system.slice/system-rhubbit.queue.slice/rhubbit.queue@test.queue.service
└─36527 php /var/www/your-project/vendor/bin/laminas queue:manager -vvv -n -y -b test.queue
3 - Queue log
The queue-manager log file could be customized adding
-l parameter in ExecStart command
defined in /bin/rhubbit.queue@.service or system will
automatically use file path set in application logpath
attribute set in global.php config file
# ...
[Service]
Type=simple
ExecStart=/var/www/your-project/vendor/bin/laminas queue:manager -l /your/custom/queue.log -vvv -n -y -b %I
# ...
Service utils
Common command to manage systemd services:
- check all services
systemctl - check all application
systemctl | grep rhubbit(every service name should start withrhubbitprefix) - stop service
systemctl stop YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME stop - start service
systemctl start YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME start - restart service
systemctl restart YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME restart - enable service
systemctl enable YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME enable - disable service
systemctl disable YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME disable - check service status
systemctl status YOUR-SERVICE-NAME.serviceorservice YOUR-SERVICE-NAME status - check id service is enabled
systemctl is-enabled YOUR-SERVICE-NAME.service - reload serviced after some change
systemctl daemon-reload(new service added, .service file update, …) - check service crash log
journalctl -u YOUR-SERVICE-NAME.service
CLI command
List of all command line interface exposed by
QueueMananger module.
INIT
$ queue:init [options]
Initialize or override queue config with input parameter.
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-b, --bundle=BUNDLE # Queue bundle unique name identifier
-u, --uri=URI # Queue uri connection param
-t, --topics=TOPICS # Valid list of queue topics pipeline separated (es. topic1|topic2|...
-l, --log-filename=LOG-FILENAME # Custom queue log filename
-e, --enabled # Enable initialized queue
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose # Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
$ ./vendor/bin/laminas queue:init -y -e -b test.queue -u file:///var/www/gshop-api/queue/cli -t "test1|test2" # init queue with all params
$ ./vendor/bin/laminas queue:init -y -b test.queue # disable queue
$ ./vendor/bin/laminas queue:init -y -e -b test.queue # enable queue
MANAGER
$ queue:manager [options]
Initialize queue monitoring process with these criteria: - if
uri and ‘topics’ are passed ignore ‘bundle’ start
monitoring queue with ‘uri’ on every ‘topics’ - if bundle
is passed extract queue connection params from DB start monitoring
every topic of that queue defined in topics attribute, and set log
name with bundle and filename with related attribute overriding
log-filename input
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-l, --log-filename=LOG-FILENAME # Override log filename (default value cli.log)
-b, --bundle=BUNDLE # Queue bundle unique name used to get connection param from DB
-u, --uri=URI # Queue uri connection param
-t, --topics=TOPICS # Pipeline-separated list of topics to monitor on the queue
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-V, --version # Display this application version
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose # Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
$ ./vendor/bin/laminas queue:manager -vvv -n -y -b test.queue -t "topic1|topic2" # listen topic1 and topic2 on test.queue getting setting from application settings
$ ./vendor/bin/laminas queue:manager -vvv -n -y -b test.queue # listen every topic on test.queue getting setting from application settings
$ ./vendor/bin/laminas queue:manager -vvv -n -y -u file:///queue/path/cli -t "topic1|topic2" # listen topic1 and topic2 on queue with uri file:///queue/path/cli
$ ./vendor/bin/laminas queue:manager -vvv -n -y -u file:///queue/path/cli # listen every topic on queue with specified uri file:///queue/path/cli
PURGE
$ queue:purge [options]
Remove all queue_event filtered via bundle,
uuid, interval and status.
Ignore by default messages with status success trying to
remove these only if explicitly set via related attribute
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-l, --log-filename=LOG-FILENAME # Override log filename (default value cli.log)
-b, --bundle=BUNDLE # Queue bundle unique name used to identify message in queue_event
-u, --uuid=UUID # Queue message uuid to resync
-s, --status=STATUS # Pipeline separated list of valid queue message status to resync
-i, --interval=INTERVAL # Hours elapsed since the message was sent
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-V, --version # Display this application version
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose # Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
$ ./vendor/bin/laminas queue:purge -n -y -vvv -b test.queue -s "pending|in_progress|success" # purge message from test.queue with status pending, in_progress or success
$ ./vendor/bin/laminas queue:purge -n -y -vvv -b test.queue -s "pending" # purge message from test.queue with status pending
$ ./vendor/bin/laminas queue:purge -n -y -vvv -b test.queue -u e9ab214e-9e0e-4460-b4a3-80492c457b0c # purge message from test.queue with specified uuid
$ ./vendor/bin/laminas queue:purge -n -y -vvv -b test.queue -i 24 # purge all message from test.queue enqueued 24 hours ago
RESYNC
$ queue:resync [options]
Resync all queue_event filtered via
bundle, uuid, interval and
status retrying to enqueue all matching messages. If
status filter is not set ignore only messages with status
success trying to resync these only if explicitly
set.
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-l, --log-filename=LOG-FILENAME # Override log filename (default value cli.log)
-b, --bundle=BUNDLE # Queue bundle unique name used to identify message in queue_event
-u, --uuid=UUID # Queue message uuid to resync
-s, --status=STATUS # Pipeline separated list of valid queue message status to resync
-i, --interval=INTERVAL # Hours elapsed since the message was sent
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-V, --version # Display this application version
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
$ ./vendor/bin/laminas queue:resync -n -y -vvv -b test.queue -s "pending|in_progress|success" # resync message from test.queue with status pending, in_progress or success
$ ./vendor/bin/laminas queue:resync -n -y -vvv -b test.queue -s "pending" # resync message from test.queue with status pending
$ ./vendor/bin/laminas queue:resync -n -y -vvv -b test.queue -u e9ab214e-9e0e-4460-b4a3-80492c457b0c # resync message from test.queue with specified uuid
$ ./vendor/bin/laminas queue:resync -n -y -vvv -b test.queue -i 24 # resync all message from test.queue enqueued 24 hours ago
SEND
$ queue:send [options]
Send message with cmd and data content on
selected queue / topic: - if uri is passed ignore
bundle otherwise use bundle to get queue uri
from DB then combining with topic enqueue message on
queue with sent params - if bundle is passed extract
queue override ‘log-filename’ and log setting with data got from
DB
Options:
-y, --yes # Choose yes to confirm automatically (add -y|--yes to confirm)
-l, --log-filename=LOG-FILENAME # Override log filename (default value cli.log)
-b, --bundle=BUNDLE # Queue bundle unique name used to get connection param from DB
-u, --uri=URI # Queue uri connection param
-t, --topic=TOPIC # Queue topic connection param
-c, --cmd=CMD # Command to send in message on queue uri / topic
-d, --data=DATA # JSON with command parameter to send in message on queue uri / topic
-i, --info=INFO # Short message description
-h, --help # Display help for the given command. When no command is given display help for the list command
-q, --quiet # Do not output any message
-V, --version # Display this application version
-n, --no-interaction # Do not ask any interactive question
-v|vv|vvv, --verbose # Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Examples:
$ ./vendor/bin/laminas queue:send -n -y -b test.queue -t test1 -c "custom-command" -d '{"a": true, "bb": false, "xyz": 12, "n": {"test": 666}}' # send custom cli command on test.queue in topic test1 with JSON parameters
$ ./vendor/bin/laminas queue:send -n -y -b test.queue -t test1 -c "ls" -d '{"a": true, "l": true}' # send standard cli command (a simple ls) on test.queue in topic test1 with JSON parameters
$ ./vendor/bin/laminas queue:send -n -y -b test.queue -t test1 -c "ls -la" -i "command short description" # send standard cli command (a simple ls -la) on test.queue in topic test1 with short description
RestIdentity
This module implement standard Database interface based on Propel ORM
Config params
This is the module application config params list.
Set this parameters in
local.php|global.php under
/config/autoload folder to define application
behaviours:
return [
//...
'client' => [
'base_url' => 'https://www.your-app-frontend.com',
'confirm_url' => 'https://www.your-app-frontend.com/confirm'
],
//...
'security' => [
'bundle' => 'api.project_name',
'secret' => 'xxxxxxxxxxxx',
'ttl' => 1800,
'refresh_ttl' => '+5 day',
'confirm_ttl' => '+1 hour',
'default_role_id' => 3,
'admin_role_id' => [1, 2],
'enable_client_log' => true,
'cc_user_invitation_to' => 'admin@domain.com',
],
//...
];
| Parameter | Description |
|---|---|
client |
main client configuration if required |
client.base_url |
homepage url of the main client |
client.confirm_url |
confirm account page url of the main client |
security.bundle |
unique application bundle used to ensure JWT token by project |
security.secret |
secret key to enforce JWT token security |
security.ttl |
JWT token time to live in seconds |
security.refresh_ttl |
refresh token time to live in a format accepted by
strtotime() |
security.confirm_ttl |
identity confirmation code time to live in a format accepted by
strtotime() |
security.default_role_id |
default role id assigned to new users |
security.admin_role_id |
list of role id enabled as admin |
security.enable_client_log |
flag used to enable DeviceLogController used to
support client to log error on server with the aim to support
production client error debug |
security.cc_user_invitation_to |
add this setting optional to send a cc copy of each user invitation email to the specified address |
RestMedia
Module built to implementent standard RESTFul API and controller interface to manage runtime uploaded application media
Required library
Install ffmpeg to manage video frame extracting process
$ sudo apt-get install ffmpeg
Config params
This is the module application config params list.
Set this parameters in
local.php|global.php under
/config/autoload folder to define application
behaviours:
return [
//...
'media' => [
'placeholder' => '/var/www/your-app-folder/public/img/img-placeholder.png',
'cdn' => [
'baseurl' => 'https://www.your-cdn.com',
'basepath'=> '../your-app-cdn/public',
'absolutepath'=> '/var/www/your-app-cdn/public',
],
'entity' => [
// list of entity managed by RestMedia module
]
]
//...
];
| Parameter | Description |
|---|---|
placeholder |
absolute path of placeholder file used if a media can’t be found |
cdn |
local application CDN config params |
cdn.baseurl |
public baseurl of the local CDN used from RestMedia module to create media public link |
cdn.basepath |
relative base path of the local CDN used from RestMedia module to locate uploaded media folder |
cdn.absolutepath |
absolute base path of the local CDN used from RestMedia module to locate uploaded media folder |
entity |
list of entity with related media managed by RestMedia module
stored in local CDN with path like
/{entity_type}/{eid}/media/... |
Entity config
Foreach entity with related media managed by
RestMedia you have to define the module behavior via
a config params array put under reserved key identifying the entity
name, key labeled EntityType in the following example (in
real project could be User, Product,
MediaGallery, …)
return [
//...
'media' => [
//...
'entity' => [ // list of entity managed by RestMedia module
'EntityName' => [ // entity name
'max_file_size' => '4MB',
'mime_types' => \RestMedia\Filter\MediaFilter::getStandardImageTypeAccepted(), // list of supported mime type for entity
'resize' => [
'thumb' => [
'mode' => \RestMedia\Model\MediaModel::CROP_MODE,
'width' => 150,
'height' => 150,
],
//...
],
'video_screenshot_second' => 0, //video seconds to generate thumb
'video_screenshot_extension' => "png",
'video_screenshot' => [
'thumb' => [
'mode' => \RestMedia\Model\MediaModel::CROP_MODE,
'width' => 150,
'height' => 150,
],
//...
],
],
// ...
]
]
//...
];
| Parameter | Description |
|---|---|
max_file_size |
max upload file size accepted |
mime_types |
list of mime types accepted: you can set an explicit static list
or use one of the \RestMedia\Filter\MediaFilter helper
methods with common mime types list |
resize |
list of resize criteria automatically applied to every uploaded
image (in the example there is only thumb criteria but you can add all
match criteria you want). Resized media will stored in folder with criteria name (in the example /{entityname}/{eid}/media/thumb |
resize.[criteria] |
your custom resize criteria name, thumb in the example |
resize.[criteria].mode |
resize mode, accepted values are:
CROP/SCALE/RESIZE |
resize.[criteria].width |
the resized image width |
resize.[criteria].height |
the resized image height |
video_screenshot_second |
param used with uploaded videos to define the instant to get screenshot |
video_screenshot_extension |
param used with uploaded videos to define screenshot image file extension (png, jpg, …) |
video_screenshot |
param used with uploaded videos to define screenshot image resize criteria (you can add all match criteria you want) |
video_screenshot.[criteria] |
your custom resize criteria name, thumb in the
example, this config object use the generic resize criteria (see
resize.[criteria]) |
How to use
RestMedia is a module based on Rest and RestIdentity modules and can be used in two different ways:
- via
/media_gallery/[:id]and/media_gallery/[:id]/media/[:mid]standard RESTFul interface - extending
MediaControllerwith a custom subclass and relate application routing
RESTFul interface
Using standard RESTFul interface you will have access to classic
media gallery system. In the case you have to only define
MediaGallery entity config following specification in
this document, then you will have access to:
/media_gallery/[:id]RESTFul interface to manage runtime a simpleMediaGalleryentity used as container of the uploaded medium/media_gallery/[:id]/media/[:mid]RESTFul interface to upload and manage media uploaded inside the MediaGallery identified by:id
You can create multiple media gallery inside your application and,
if you like it, related entity from different modules to it via
:id unique identifier.
Extend MediaController
Extending MediaController, a subclass of
AdvancedRestfulController exposed by Rest
module, you can create your custom media gallery
controller to fully manage business logic behind your uploading
criteria.
Create your MediaGallery subclass is simple, you only need a controller like this:
class ProductMediaController extends MediaController
{
private $ownerId = 0;
private $entityId = 0;
public function onDispatch(MvcEvent $e)
{
$this->ownerId = //set your media owner id
$this->entityId = //set the id of main entity relate to the media
return parent::onDispatch($e);
}
/*********************************************
* MediaController subclass abstract methods *
*********************************************/
// return the media owner user id
public function getOwnerId(): ?int
{
return $this->ownerId;
}
// return the name of the entity type related to the media
public function getEntityType(): string
{
return ProductEntity::ENTITY_NAME;
}
// return the unique id of the entity type related to the media
public function getEntityId(): int
{
return $this->entityId;
}
/*********************************************************
* MediaController subclass optional override of methods *
*********************************************************/
// Optionally set a subclass of MediaModel as model used by
// MediaController to implements advanced customization
public function getMediaModel(): ?MediaModel
{
return new CustomMediaModel(...)
}
}
Then you need to init register your controller following generic Rest module criteria and defining custom related routes like this:
return [
'router' => [
'routes' => [
//...
'/api/v1/product/{id}/media' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/product/:pid/media[/]',
'constraints' => [
'pid' => '[1-9]\d*'
],
'defaults' => [
'controller' => 'RestProduct\Controller\ProductMedia'
]
],
],
'/api/v1/product/{id}/media/{id}' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/product/:pid/media/:id[/]',
'constraints' => [
'pid' => '[1-9]\d*',
'id' => '[1-9]\d*'
],
'defaults' => [
'controller' => 'RestProduct\Controller\ProductMedia'
]
],
],
],
],
'controllers' => [
'invokables' => [
'RestProduct\Controller\ProductMedia' => Controller\ProductMediaController::class,
//...
],
],
//...
];
Rest
This module contains standard advanced controller to support RESTFul API development based and validated on open api spec.
Required library
Install module APCU Cache:
$ sudo apt install php-apcu $ sudo apt install php8.2-apcuConfigure APC in
php.ini:$ vim /etc/php/8.2/apache2/php.iniWith APC Default configuration:
extension=apcu.so apc.enabled=1 apc.shm_size=1024M apc.max_file_size=10M apc.num_files_hint=20000 apc.user_entries_hint=20000 apc.ttl=7200 apc.user_ttl=7200 apc.gc_ttl=3600 apc.include_once_override=0 apc.enable_cli=1Then reload apache
sudo service apache2 restartDownload apcu monitoring page in your web root or dedicate virtual host web root
$ cd /your/project/root/public $ wget https://raw.githubusercontent.com/krakjoe/apcu/master/apc.phpthen set username and password in
apc.phpReset
oas_specentry from apc cache after every open api spec update$ curl http://your.domain.xxx/spec-clear.php
Config params
This is the module application config params list.
Set this parameters in
local.php|global.php under
/config/autoload folder to define application
behaviours:
return [
//...
'debug' => true,
'oldest_supported_version' => 'x.y.z',
'spec' => '/var/www/your-app-folder/service-spec/generated-spec/spec.yaml',
//...
];
| Parameter | Description |
|---|---|
debug |
If set to TRUE when application trigger
error/exception JSON response will include full stacktrace |
oldest_supported_version |
oldest supported version number express with
semver syntax, if client request older API version
via Accept-Version header will be triggered an
406 - Not acceptable response error exception |
spec |
folder where spec yaml file will be saved |
Module configuration
All the subclasses of AdvancedRestfulController, if
configured, will automatically trigger standard events propagated
throughout the application by Laminas and listenable by every
application modules via dedicate listeners attached to
onBootstrapt event of the module.
To enable your modules and related controllers to trigger and listen RestEvent you have to:
extend your
Moduleclass withAbstractRestfulModuleclass Module extends AbstractRestfulModule ...implement
getBundlesmethod of the superclass returning an array key/values with:key: a unique bundle name identifying your module, eg.
com.rhubbit.rest.aclvalues: a list of controller enabled to trigger this kind of events
'com.rhubbit.rest.acl' => [ Controller\DeviceController::class, Controller\IdentityController::class, Controller\IdentityConfirmationController::class ]
set the event context name in the
onDispatchmethod of the related controller (typically using the related Entity name)public function onDispatch(MvcEvent $e) { $this->setEventContext(ProductEntity::ENTITY_NAME); return parent::onDispatch($e); }
Event structure
Every event automatically triggered by
AdvancedRestfulController contains: -
bundle: unique event name composed by module bundle
and context (entity name) related to the controller, eg.
com.rhubbit.rest.acl/identity - event:
the specific event name, eg. create.pre,
update.post, … - target: reference to
the object instance triggering the event - params: an
array with all the parameters attached by the controller to the
event
Standard events
Every AdvancedRestfulController, if added in the array
returned by getBundles, will automatically trigger the
event matching action managed:
| HTTP | Event | params |
|---|---|---|
GET |
get.pre |
the same input of the controller get method |
GET |
get.post |
the same output that controller get method will
return (the Entity) |
GET |
get.error |
the same error that controller get method will
return |
GET |
getList.pre |
the same input of the controller getList method |
GET |
getList.post |
the same output that controller getList method will
return (the Entity) |
GET |
getList.error |
the same error that controller getList method will
return |
POST |
create.pre |
the same input of the controller create method |
POST |
create.post |
the same output that controller create method will
return (the Entity) |
POST |
create.error |
the same error that controller create method will
return |
PUT |
update.pre |
the same input of the controller update method |
PUT |
update.post |
the same output that controller update method will
return (the Entity) |
PUT |
update.error |
the same error that controller update method will
return |
DELETE |
delete.pre |
the same input of the controller delete method |
DELETE |
delete.post |
a BaseEntity object with the same input of the
controller delete method (Entity at this time was
deleted) |
DELETE |
delete.error |
the same error that controller delete method will
return |
Event lister
To create a new RestEvent listener you have to:
create a class and implements
ListenerAggregateInterfaceadd this class to the factories list managed by the module in the
service_managerblock of the controllermodule.config.phpfilephp 'service_manager' => [ ... 'factories' => [ ... Listener\ProductSyncListener::class => SyncListenerFactory::class, ... ], ],implement the
attachmethod of theListenerAggregateInterface// public function attach(EventManagerInterface $events, $priority = - 100) { $sharedManager = $events->getSharedManager(); $this->listeners[] = $sharedManager->attach('api.shopcm/product', 'create.pre', array( $this, 'onProductCreating' ), $priority); $this->listeners[] = $sharedManager->attach('api.shopcm/product', 'create.post', array( $this, 'onProductCreated' ), $priority); //... }define callback method related to every attached event, e.g.
onProductCreatingeonProductCreated…attach this listener in the
onBootstrapmodule event callback//register single event listener $eventManager = $app->getEventManager(); $app->getServiceManager() ->get(Listener\ProductSyncListener::class) ->attach($eventManager);
RPC
Rpc module, built on top of Rest module, implements standard
json-rpc 2.0 request: https://www.jsonrpc.org/specification.
This module inherits authentication and
authorization criteria from Rest module adding not
standard Api-Key and Authorization header to
json-rpc protocol
Create JSON RPC Controller
Following these steps you are able to implement your custum Json RPC Controller.
Create a subclass of
AbstractRpcControllerclass RestCalculatorController extends AbstractRpcController { // your code here ... }Implement your procedure handler following spec in JSON-RPC PHP Server spec here: https://github.com/matasarei/json-rpc
Implement abstract method
getRpcServer()ofAbstractRpcControllerin your subclassclass RestCalculatorController extends AbstractRpcController { public function getRpcServer(): Server { $server = new Server(); $procedureHandler = $server->getProcedureHandler(); $procedureHandler->withObject(new Calculator()); $procedureHandler->withObject(new Test()); return $server; } }Add controller to your
module.config.php file:return [ // ... 'router' => [ 'routes' => [ '/api/v1/rpc/calculator' => [ 'type' => Segment::class, 'options' => [ 'route' => '/api/v1/rpc/calculator[/]', 'defaults' => [ 'controller' => 'Rpc\Controller\RestCalculator' ] ], ], ], ], 'controllers' => [ 'invokables' => [ 'Rpc\Controller\RestCalculator' => Controller\Example\RestCalculatorController::class, ], ], // ... ]Add your rpc routes to your
spec-root.yaml:# ... '/api/v1/rpc/calculator': $ref: '../module/Rpc/spec/Example/ExampleRpcSpec.yaml#/~1api~1v1~1rpc~1calculator' # ...Add standard
JsonRpcErrorSchema,JsonRpcErrorSchemaandJsonRpcErrorSchemato yourspec-root.yamlgot from module/specfolder:# ... JsonRpcRequest: $ref: '../module/Rpc/spec/JsonRpcRequestSchema.yaml' JsonRpcResponse: $ref: '../module/Rpc/spec/JsonRpcResponseSchema.yaml' JsonRpcError: $ref: '../module/Rpc/spec/JsonRpcErrorSchema.yaml' # ...Define your custom method request schema:
Extending standard
JsonRpcRequestallOf: - $ref: '../../../../../../service-spec/spec-root.yaml#/components/schemas/JsonRpcRequest' - type: object title: add properties: method: type: string description: This method execute x + y. default: add example: add params: type: object description: add method params properties: x: type: integer example: 20 y: type: integer example: 35adding it to your
spec-root.yaml# ... CalculatorRpcAddRequest: $ref: '../module/Rpc/spec/Example/Calculator/Method/AddRequestSchema.yaml' # ...
Define your custom method response schema:
extending standard
JsonRpcResponseallOf: - $ref: '../../../../../../service-spec/spec-root.yaml#/components/schemas/JsonRpcResponse' - type: object title: add properties: result: type: integer example: 55adding it to your
spec-root.yaml# ... CalculatorRpcAddResponse: $ref: '../module/Rpc/spec/Example/Calculator/Method/AddResponseSchema.yaml' # ...
Finally, add you rpc route to ACL