Compare commits
5
Commits
37462e4646
...
4cb3971940
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cb3971940 | ||
|
|
dcd0b5f064 | ||
|
|
28afb11ac4 | ||
|
|
3f1cf11cd7 | ||
|
|
80b8926a0e |
@@ -6,7 +6,9 @@ Powered by:
|
||||
- PHP Symfony.
|
||||
- Easyadmin.
|
||||
|
||||
## Commands:
|
||||
## Get started:
|
||||
|
||||
### Dev commands
|
||||
|
||||
Build containers:
|
||||
```bash
|
||||
@@ -33,7 +35,7 @@ XDEBUG_LOG=/dev/stdout
|
||||
```
|
||||
|
||||
|
||||
### Prod:
|
||||
### Production commands:
|
||||
|
||||
When deploying to a production environment a production build should be used.
|
||||
Then, deployment can be done as containers or using docker-compose.
|
||||
@@ -47,7 +49,7 @@ docker build -t somniarooms:prod --target frankenphp_prod .
|
||||
|
||||
**Deploy prod image**
|
||||
|
||||
You may use a env file to configure the SomniaRoom container:
|
||||
You may use a env file to configure the SomniaRoom container (`.env.prod.local`):
|
||||
|
||||
```shell
|
||||
SERVER_NAME=localhost
|
||||
@@ -83,6 +85,12 @@ If you want your app and DB to comunicate using it's hostname (like on this exam
|
||||
docker network create somniarooms-network
|
||||
```
|
||||
|
||||
Check [deploy docs](docs/deploy.md) for complete examples on how to deploy SomniaRooms (backend+frontend) using Docker and Docker-compose.
|
||||
|
||||
<warning>
|
||||
Examples shown on deploy docs may be out-of-date. Make sure all readme recommendations are applied before use on production.
|
||||
</warning>
|
||||
|
||||
|
||||
## Running the app!
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"easycorp/easyadmin-bundle": "^4.10",
|
||||
"nelmio/api-doc-bundle": "^4.30",
|
||||
"nelmio/cors-bundle": "^2.4",
|
||||
"php-ds/php-ds": "^1.5",
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpstan/phpdoc-parser": "^1.28",
|
||||
"runtime/frankenphp-symfony": "^0.2.0",
|
||||
|
||||
Generated
+56
-1
@@ -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": "974cb22b15d6dc64bd6dac49da5d671d",
|
||||
"content-hash": "03b299c4c2e514090c879c8f71219e56",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/semver",
|
||||
@@ -1686,6 +1686,61 @@
|
||||
},
|
||||
"time": "2023-11-30T16:41:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-ds/php-ds",
|
||||
"version": "v1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-ds/polyfill.git",
|
||||
"reference": "7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-ds/polyfill/zipball/7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4",
|
||||
"reference": "7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ds": "1.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-ds/tests": "^1.5"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ds": "to improve performance and reduce memory usage"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rudi Theunissen",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"data structures",
|
||||
"ds",
|
||||
"php",
|
||||
"polyfill"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-ds/polyfill/issues",
|
||||
"source": "https://github.com/php-ds/polyfill/tree/v1.5.0"
|
||||
},
|
||||
"time": "2023-12-19T16:52:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
|
||||
@@ -24,5 +24,9 @@ services:
|
||||
arguments:
|
||||
$targetDirectory: 'images/'
|
||||
|
||||
App\Service\ExampleDataService:
|
||||
arguments:
|
||||
$sampleDirectory: '../samples/'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
||||
+182
-36
@@ -1,54 +1,200 @@
|
||||
<!-- omit in toc -->
|
||||
# SomniaRooms - App Configuration Variables.
|
||||
|
||||
- [Config Sections](#config-sections)
|
||||
- [Config implementation status](#config-implementation-status)
|
||||
- [Company Information](#company-information)
|
||||
- [Front-end Config](#front-end-config)
|
||||
- [Var `NightAmountForContactDialog`](#var-nightamountforcontactdialog)
|
||||
- [Var `GuestNumberForContactDialog`](#var-guestnumberforcontactdialog)
|
||||
- [Var `ContactDialogShowBehaviour`](#var-contactdialogshowbehaviour)
|
||||
- [Var `ShowNonAvailableRooms`](#var-shownonavailablerooms)
|
||||
- [Var `SomniaAttributionNotice`](#var-somniaattributionnotice)
|
||||
- [Var `PhotoAspectRatio`](#var-photoaspectratio)
|
||||
- [Price Management](#price-management)
|
||||
- [Var `TotalPriceMethod`.](#var-totalpricemethod)
|
||||
- [Var `FareSelectionMethod`](#var-fareselectionmethod)
|
||||
- [API Config.](#api-config)
|
||||
- [Var `MaxAllowedNightAmount`](#var-maxallowednightamount)
|
||||
- [Var `MaxAllowedGuestNumber`](#var-maxallowedguestnumber)
|
||||
|
||||
---
|
||||
|
||||
This document contains a list of all config variables of SomniaRooms. Variables are stored in DB (table _`config_variable`_) and can be configured from admin panel.
|
||||
|
||||
Variables are divided in sections. Some sections are ony accesible from SomniaRoom, but others can be retrieved by anyone using config endpoint (_`/config`_).
|
||||
|
||||
## List of sections:
|
||||
## Config Sections
|
||||
|
||||
WIP
|
||||
| Section | SectionName | Description | Availability |
|
||||
| :------------------------------------------ | :-------------- | :--------------------------------------------- | :----------: |
|
||||
| [Company Information](#company-information) | COMPANY | Configure company information | Public |
|
||||
| [Front-end config](#front-end-config) | FRONTEND_CONFIG | Configure front-end behaviour | Public |
|
||||
| [Price API Management](#price-management) | API_PRICES | Configure how prices are calculated for a stay | Private |
|
||||
| [API Config](#api-config) | API_CONFIG | Configure API | Private |
|
||||
|
||||
TODO -> Add default table with basic information to all sections.
|
||||
|
||||
### **Company**
|
||||
Variables in this section contains information about the Hotel.
|
||||
### Config implementation status
|
||||
|
||||
- SectionName -> company
|
||||
- Availability -> public
|
||||
- Nº variables -> X
|
||||
Not all variables are fully implemented, some are experimental or have options that are.
|
||||
Current status for a variable and it's options:
|
||||
- New!: :sparkles:
|
||||
- Fully available: :heavy_check_mark:
|
||||
- Partially available: :construction:
|
||||
- Experimental: :bulb:
|
||||
- Not yet: :x:
|
||||
|
||||
**Variable list:**
|
||||
|
||||
- Name - Name of hotel.
|
||||
## Company Information
|
||||
Variables in this section contains information about the Company. Those are used to identify the business and to customize frontend.
|
||||
|
||||
| Variable | Type | Description | Constraints | Default Value | Status |
|
||||
| :------------- | :----- | :-------------------- | :----------------------------------------------------------- | :------------ | :------------: |
|
||||
| CompanyName | string | Company name | - | SomniaRooms | :construction: |
|
||||
| CompanyWebsite | string | Company website URL | Valid URL to company website. | somnia.dev | :construction: |
|
||||
| CompanyLogo | string | Company Logo URL | Valid URL to company logo. Somnia Backend system can be used | "" | :construction: |
|
||||
| CompanyAddress | string | Company Address | - | "" | :construction: |
|
||||
| CompanyEmail | string | Company email address | - | "" | :construction: |
|
||||
| CompanyPhone | string | Company phone number | - | "" | :construction: |
|
||||
|
||||
|
||||
## Front-end Config
|
||||
This variable set the behaviour of front-end app.
|
||||
|
||||
| Variable | Type | Description | Constraints | Default Value | Status |
|
||||
| :-------------------------- | :------ | :------------------------------------------------- | :---------------------------------------------- | :------------ | :------------: |
|
||||
| NightAmountForContactDialog | int | Set the amount of nights to show a contact dialog. | See [details](#var-nightamountforcontactdialog) | 10 | :construction: |
|
||||
| GuestNumberForContactDialog | int | Set the guest number to show a contact dialog. | See [details](#var-guestnumberforcontactdialog) | 6 | :construction: |
|
||||
| ContactDialogShowBehaviour | options | Set how the contact dialog is shown | See [details](#var-contactdialogshowbehaviour) | show | :construction: |
|
||||
| ShowNonAvailableRooms | bool | Show rooms without availability on search | See [details](#var-shownonavailablerooms) | true | :construction: |
|
||||
| SomniaAttributionNotice | options | How SomniaRooms notice is shown. | See [details](#var-somniaattributionnotice) | full | :construction: |
|
||||
| PhotoAspectRatio | string | Set the aspect ratio for photos | See [details](#var-photoaspectratio) | 4:3 | :construction: |
|
||||
|
||||
### Var `NightAmountForContactDialog`
|
||||
Set the amount of nights to show a contact dialog. This dialog contains company contact information and may be used to get a custom price for long stays.
|
||||
|
||||
The contact dialog will be shown when night amount is equal or greater than configured amount.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :---- | :-------------------------------------------------------- | :----: |
|
||||
| Disabled | -1 | Disable this funcionality. Contact dialog won't be shown. | :x: |
|
||||
| Always | 0 | Contact dialog is always shown. | :x: |
|
||||
| Custom Amount | - | Set the minimun number of nights to show the dialog. | :x: |
|
||||
|
||||
|
||||
### Var `GuestNumberForContactDialog`
|
||||
Set the guest number to show a contact dialog. This dialog contains company contact information and may be used to get a custom price for groups.
|
||||
|
||||
The contact dialog will be shown when guest number is equal or greater than configured amount.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :---- | :-------------------------------------------------------- | :----: |
|
||||
| Disabled | -1 | Disable this funcionality. Contact dialog won't be shown. | :x: |
|
||||
| Always | 0 | Contact dialog is always shown. | :x: |
|
||||
| Custom Amount | - | Set the minimun guest number to show the dialog. | :x: |
|
||||
|
||||
|
||||
### Var `ContactDialogShowBehaviour`
|
||||
How the contact dialog is shown to the user (when conditions are meet).
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :----- | :---- | :------------------------------- | :----: |
|
||||
| Show | SHOW | Show dialog on screen | :x: |
|
||||
| Alert | ALERT | Show an alert to open the dialog | :x: |
|
||||
|
||||
|
||||
### Var `ShowNonAvailableRooms`
|
||||
Show rooms without availability on search.
|
||||
Non-available rooms will be shown at the end of the list.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :----- | :---- | :-------------------------------------------------------- | :----: |
|
||||
| Show | true | All rooms will appear on search. Even non-available ones. | :x: |
|
||||
| Hide | false | Only show available rooms. | :x: |
|
||||
|
||||
### Var `SomniaAttributionNotice`
|
||||
Configure how SomniaRooms attribution note is display.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :----- | :---- | :------------------------------------ | :----: |
|
||||
| Full | FULL | Show the full message. Thanks :heart: | :x: |
|
||||
| Small | SMALL | Show a small notice :+1: | :x: |
|
||||
| Hide | HIDE | SomniaRooms notice won't be shown. | :x: |
|
||||
|
||||
|
||||
### Var `PhotoAspectRatio`
|
||||
Aspect ratio for front-end photos.
|
||||
|
||||
This setting is currently used for room photos. You may set any valid aspect-ratio you want.
|
||||
It's recommended that all photos have the same aspect-ratio to avoid scaling.
|
||||
|
||||
|
||||
## Price Management
|
||||
How SomniaRooms API services calculates prices for bookings.
|
||||
|
||||
| Variable | Type | Description | Constraints | Default Value | Status |
|
||||
| :------------------ | :----- | :---------------------------------------------------- | :-------------------------------------- | :------------ | :----: |
|
||||
| TotalPriceMethod | option | How total price is calculated for a stay | See [details](#var-totalpricemethod) | SUM | :x: |
|
||||
| FareSelectionMethod | option | What fare to select when multiple fares are available | See [details](#var-fareselectionmethod) | HIGHER | :x: |
|
||||
|
||||
|
||||
### Var `TotalPriceMethod`.
|
||||
Establish the method used to calculate the total price for a stay.
|
||||
|
||||
The total price for a stay will be calculated from the price of the days that make the stay. A operation must be selected to get total price from daily prices.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :------ | :----------------------------------------------------------------- | :----: |
|
||||
| Lower Price | LOWER | The lower price will be apply for each day. | :x: |
|
||||
| High Price | HIGHER | The highest price will be apply for each day. | :x: |
|
||||
| Total Sum | SUM | Total price will be the sum of the price for each day. | :x: |
|
||||
| Average Price | AVERAGE | The average for all days will be calculated and apply to each day. | :x: |
|
||||
|
||||
|
||||
### Var `FareSelectionMethod`
|
||||
How to select the fare for a room when there are multiple fares applicable.
|
||||
|
||||
A faretable may contain multiple fares for a room and guest number given some conditions. If multiple conditions match for a date and therefore there are more than 1 applicable fare, one must be used. This method sets what to do in those cases.
|
||||
Note: RoomPrices have more priority than fares. So if a RoomPrice is available, it will always be the prefered option.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :------ | :---------------------------------------------------------------- | :----: |
|
||||
| Lower Price | LOWER | Lower price available will be used. | :x: |
|
||||
| High Price | HIGHER | Higher available price will be used. | :x: |
|
||||
| Average price | AVERAGE | Selected price will be the aritmetic average of available prices. | :x: |
|
||||
|
||||
|
||||
## API Config.
|
||||
Configuration for some API endpoints.
|
||||
|
||||
| Variable | Type | Description | Constraints | Default Value | Status |
|
||||
| :-------------------- | :--- | :----------------------------------- | :---------------------------------------- | :------------ | :------------: |
|
||||
| MaxAllowedNightAmount | int | Max night amount that can be booked. | See [details](#var-maxallowednightamount) | 20 | :construction: |
|
||||
| MaxAllowedGuestNumber | int | Max guest number that can be booked. | See [details](#var-maxallowedguestnumber) | 20 | :construction: |
|
||||
|
||||
|
||||
|
||||
### **Price Management**
|
||||
Configure how backend services calculates prices for bookings.
|
||||
### Var `MaxAllowedNightAmount`
|
||||
Max number of nights that can be booked using the app. For longer stays the company should be contacted.
|
||||
|
||||
- SectionName -> price_mng
|
||||
- Availability -> internal
|
||||
- Nº variables -> X
|
||||
|
||||
**Variable list:**
|
||||
|
||||
WIP
|
||||
|
||||
#### FinalPriceCalculation.
|
||||
Establece cómo se deben tratar los precios de cada día para generar el precio final de la estancia.
|
||||
|
||||
Algunos algoritmos para estos serán:
|
||||
- Precio más alto.
|
||||
- Precio más bajo.
|
||||
- Suma de precios. --> Por defecto.
|
||||
- Media de precios.
|
||||
|
||||
#### MultipleRoomFareValid
|
||||
Estrategia de selección de tarifa en caso de que haya varias válidas (mientras no exista un sistema de prioridad de tarifas...)
|
||||
|
||||
Posibles algoritmos:
|
||||
- Precio más alto.
|
||||
- Precio más bajo.
|
||||
- Media.
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :---- | :---------------------------------------------------------- | :----: |
|
||||
| Disabled | 0 | Disable this funcionality. No limit on booking will be set. | :x: |
|
||||
| Custom Amount | - | Set the max number of nights allowed to book. | :x: |
|
||||
|
||||
### Var `MaxAllowedGuestNumber`
|
||||
Max guest number that can be booked using the app. For bigger groups the company should be contacted.
|
||||
|
||||
**Options:**
|
||||
| Option | Value | Usage | Status |
|
||||
| :------------ | :---- | :---------------------------------------------------------- | :----: |
|
||||
| Disabled | 0 | Disable this funcionality. No limit on booking will be set. | :x: |
|
||||
| Custom Amount | - | Set the max guest number allowed to book. | :x: |
|
||||
@@ -1,5 +1,13 @@
|
||||
<!-- omit in toc -->
|
||||
# SomniaRooms - How to deploy.
|
||||
|
||||
- [Docker compose examples.](#docker-compose-examples)
|
||||
- [Deploy back-end and front-end on different servers (different ip address).](#deploy-back-end-and-front-end-on-different-servers-different-ip-address)
|
||||
- [Deploy on the same server.](#deploy-on-the-same-server)
|
||||
- [What's next?](#whats-next)
|
||||
|
||||
---
|
||||
|
||||
SomniaRooms is designed to be easy to deploy and use.
|
||||
|
||||
Production images for Docker Containers are available from Gitea Registry.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"name": "Double Bed",
|
||||
"iconUrl": "icon-bed-double"
|
||||
},
|
||||
{
|
||||
"name": "Single Bed",
|
||||
"iconUrl": "icon-bed-single"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,41 @@
|
||||
[
|
||||
{
|
||||
"name": "Double room (double bed)",
|
||||
"description": "Room with double bed and shared bathroom",
|
||||
"maxGuestNum": 2,
|
||||
"orderHomePage": null,
|
||||
"roomCategoryPhotos": [
|
||||
{
|
||||
"path": "https://images.unsplash.com/photo-1559841644-08984562005a",
|
||||
"altText": "Room",
|
||||
"photoOrder": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Double w/ bath (double bed)",
|
||||
"description": "Room with double bed and private bathroom",
|
||||
"maxGuestNum": 2,
|
||||
"orderHomePage": null,
|
||||
"roomCategoryPhotos": [
|
||||
{
|
||||
"path": "https://images.unsplash.com/photo-1559841644-08984562005a",
|
||||
"altText": "Room",
|
||||
"photoOrder": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Double w/ bath (single bed)",
|
||||
"description": "Room with 2 single beds and private bathroom",
|
||||
"maxGuestNum": 2,
|
||||
"orderHomePage": null,
|
||||
"roomCategoryPhotos": [
|
||||
{
|
||||
"path": "https://images.unsplash.com/photo-1559841644-08984562005a",
|
||||
"altText": "Room",
|
||||
"photoOrder": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"amount": 1,
|
||||
"roomCategory": 0,
|
||||
"bedType": 0
|
||||
},
|
||||
{
|
||||
"amount": 1,
|
||||
"roomCategory": 2,
|
||||
"bedType": 1
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Consts;
|
||||
|
||||
use App\Entity\ConfigVariable;
|
||||
use App\Enum\ConfigVariableSectionEnum;
|
||||
|
||||
//Variable List Constants
|
||||
// --> This constants contains all defined Config Variables. For each one a array is stored as [varKey => [varSection, varDefaultValue]].
|
||||
class ConfigVariableConsts
|
||||
{
|
||||
public const CONFIG_COMPANY_NAME = ["CompanyName" => [ConfigVariableSectionEnum::Company, "SomniaRooms"]];
|
||||
public const CONFIG_COMPANY_WEBSITE = ["CompanyWebsite" => [ConfigVariableSectionEnum::Company, "somnia.dev"]];
|
||||
public const CONFIG_COMPANY_LOGO = ["CompanyLogo" => [ConfigVariableSectionEnum::Company, ""]];
|
||||
public const CONFIG_COMPANY_ADDRESS = ["CompanyAddress" => [ConfigVariableSectionEnum::Company, ""]];
|
||||
public const CONFIG_COMPANY_EMAIL = ["CompanyEmail" => [ConfigVariableSectionEnum::Company, ""]];
|
||||
public const CONFIG_COMPANY_PHONE = ["CompanyPhone" => [ConfigVariableSectionEnum::Company, ""]];
|
||||
|
||||
public const CONFIG_FRONTEND_NIGHTSFORCONTACT = ["NightAmountForContactDialog" => [ConfigVariableSectionEnum::Frontend, "10"]];
|
||||
public const CONFIG_FRONTEND_GUESTSFORCONTACT = ["GuestNumberForContactDialog" => [ConfigVariableSectionEnum::Frontend, "6"]];
|
||||
public const CONFIG_FRONTEND_CONTACTDIALOGBEHAVIOUR = ["ContactDialogShowBehaviour" => [ConfigVariableSectionEnum::Frontend, "show"]];
|
||||
public const CONFIG_FRONTEND_SHOWNONAVAILABLEROOMS = ["ShowNonAvailableRooms" => [ConfigVariableSectionEnum::Frontend, true]];
|
||||
public const CONFIG_FRONTEND_SOMNIAATTRIBUTION = ["SomniaAttributionNotice" => [ConfigVariableSectionEnum::Frontend, "full"]];
|
||||
public const CONFIG_FRONTEND_PHOTOASPECTRATIO = ["PhotoAspectRatio" => [ConfigVariableSectionEnum::Frontend, "4:3"]];
|
||||
|
||||
public const CONFIG_PRICES_PRICEMETHOD = ["TotalPriceMethod" => [ConfigVariableSectionEnum::API_PRICES, "SUM"]];
|
||||
public const CONFIG_PRICES_FAREMETHOD = ["FareSelectionMethod" => [ConfigVariableSectionEnum::API_PRICES, "HIGHER"]];
|
||||
|
||||
public const CONFIG_API_NAXNIGHTS = ["MaxAllowedNightAmount" => [ConfigVariableSectionEnum::API_CONFIG, "20"]];
|
||||
public const CONFIG_API_NAXGUESTS = ["MaxAllowedGuestNumber" => [ConfigVariableSectionEnum::API_CONFIG, "20"]];
|
||||
|
||||
public const CONFIG_INTERNAL_SETUP = ["SETUP_STATUS" => [ConfigVariableSectionEnum::Internal, "1"]];
|
||||
|
||||
public static function getKeyFromConstant(array $constant): string
|
||||
{
|
||||
return array_key_first($constant);
|
||||
}
|
||||
|
||||
public static function GetAllDefinedConfigVariablesList(): array
|
||||
{
|
||||
return array_merge(
|
||||
ConfigVariableConsts::CONFIG_COMPANY_NAME,
|
||||
ConfigVariableConsts::CONFIG_COMPANY_WEBSITE,
|
||||
ConfigVariableConsts::CONFIG_COMPANY_LOGO,
|
||||
ConfigVariableConsts::CONFIG_COMPANY_ADDRESS,
|
||||
ConfigVariableConsts::CONFIG_COMPANY_EMAIL,
|
||||
ConfigVariableConsts::CONFIG_COMPANY_PHONE,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_NIGHTSFORCONTACT,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_GUESTSFORCONTACT,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_CONTACTDIALOGBEHAVIOUR,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_SHOWNONAVAILABLEROOMS,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_SOMNIAATTRIBUTION,
|
||||
ConfigVariableConsts::CONFIG_FRONTEND_PHOTOASPECTRATIO,
|
||||
ConfigVariableConsts::CONFIG_PRICES_PRICEMETHOD,
|
||||
ConfigVariableConsts::CONFIG_PRICES_FAREMETHOD,
|
||||
ConfigVariableConsts::CONFIG_API_NAXNIGHTS,
|
||||
ConfigVariableConsts::CONFIG_API_NAXGUESTS,
|
||||
ConfigVariableConsts::CONFIG_INTERNAL_SETUP,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\ConfigVariable;
|
||||
use App\Enum\ConfigSectionType;
|
||||
use App\Enum\ConfigVariableSectionEnum;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
|
||||
@@ -21,10 +22,15 @@ class ConfigVariableCrudController extends AbstractCrudController
|
||||
return $crud;
|
||||
}
|
||||
|
||||
public function configureActions(Actions $actions): Actions
|
||||
{
|
||||
return $actions->disable("new", "delete");;
|
||||
}
|
||||
|
||||
public function configureFields(string $pageName): iterable
|
||||
{
|
||||
yield ChoiceField::new ('section')->setChoices(ConfigSectionType::cases());
|
||||
yield TextField::new ('key');
|
||||
yield TextField::new ('value');
|
||||
yield ChoiceField::new('section')->setChoices(ConfigVariableSectionEnum::cases());
|
||||
yield TextField::new('key');
|
||||
yield TextField::new('value');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Consts\ConfigVariableConsts;
|
||||
use App\DTO\AppSetupConfig;
|
||||
use App\DTO\ExampleDataConfig;
|
||||
use App\Entity\ConfigVariable;
|
||||
@@ -9,9 +10,9 @@ use App\Form\AppSetupFormType;
|
||||
use App\Form\ExampleDataFormType;
|
||||
use App\Repository\RoomCategoryRepository;
|
||||
use App\Service\AppSetupService;
|
||||
use App\Service\ConfigVariableService;
|
||||
use App\Service\ExampleDataService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -25,13 +26,13 @@ class AppSetupController extends AbstractController
|
||||
LoggerInterface $logger,
|
||||
AppSetupService $setupService,
|
||||
Request $request,
|
||||
EntityManagerInterface $entityManager
|
||||
ConfigVariableService $configVars
|
||||
): Response {
|
||||
|
||||
$configRepo = $entityManager->getRepository(ConfigVariable::class);
|
||||
$setupStatus = $configRepo->findBy(["key" => "SETUP_STATUS"]);
|
||||
$setupVar_key = ConfigVariableConsts::getKeyFromConstant(ConfigVariableConsts::CONFIG_INTERNAL_SETUP);
|
||||
$setupStatus = $configVars->getVariable($setupVar_key);
|
||||
|
||||
if ($setupStatus != null && $setupStatus[0] != null && $setupStatus[0]->getValue() == 1) {
|
||||
if ($setupStatus != null && $setupStatus->getValue()) {
|
||||
$logger->warning("SomniaRooms was already setup");
|
||||
|
||||
return $this->GoToResultPage(
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ConfigVariableRepository;
|
||||
use App\Enum\ConfigSectionType;
|
||||
use App\Enum\ConfigVariableSectionEnum;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: ConfigVariableRepository::class)]
|
||||
class ConfigVariable
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue("NONE")]
|
||||
#[ORM\GeneratedValue(strategy: "NONE")]
|
||||
#[ORM\Column(length: 32, unique: true, nullable: false)]
|
||||
private string $key = "";
|
||||
|
||||
#[ORM\Column(length: 255, nullable: false)]
|
||||
private ?string $value = null;
|
||||
|
||||
#[ORM\Column(type: 'string', enumType: ConfigSectionType::class, nullable: false)]
|
||||
private ConfigSectionType $section = ConfigSectionType::General;
|
||||
#[ORM\Column(type: 'string', enumType: ConfigVariableSectionEnum::class, nullable: false)]
|
||||
private ConfigVariableSectionEnum $section = ConfigVariableSectionEnum::Internal;
|
||||
|
||||
|
||||
public function getKey(): string
|
||||
@@ -45,12 +45,12 @@ class ConfigVariable
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSection(): ConfigSectionType
|
||||
public function getSection(): ConfigVariableSectionEnum
|
||||
{
|
||||
return $this->section;
|
||||
}
|
||||
|
||||
public function setSection(ConfigSectionType $section): static
|
||||
public function setSection(ConfigVariableSectionEnum $section): static
|
||||
{
|
||||
$this->section = $section;
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
enum ConfigSectionType: string {
|
||||
case General = 'GENERAL';
|
||||
case Internal = 'INTERNAL';
|
||||
case Company = 'COMPANY';
|
||||
case Backend = 'BACK';
|
||||
case Frontend = 'FRONT';
|
||||
case Test = 'TEST';
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
enum ConfigVariableSectionEnum: string
|
||||
{
|
||||
case Company = 'COMPANY';
|
||||
case Frontend = 'FRONTEND_CONFIG';
|
||||
case API_PRICES = 'API_PRICES';
|
||||
case API_CONFIG = 'API_CONFIG';
|
||||
case Internal = 'INTERNAL';
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace App\Repository;
|
||||
use App\Entity\ConfigVariable;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Ds\Set;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<ConfigVariable>
|
||||
@@ -51,14 +52,24 @@ class ConfigVariableRepository extends ServiceEntityRepository
|
||||
* @param string Variable Key
|
||||
* @return ConfigVariable|null Config Variable.
|
||||
*/
|
||||
public function findVariableByKey($varKey)
|
||||
public function findVariableByKey($varKey): ConfigVariable|null
|
||||
{
|
||||
return $this->createQueryBuilder('c')
|
||||
$rs = $this->createQueryBuilder('c')
|
||||
->select('c.key, c.value, c.section')
|
||||
->andWhere('c.key = :val')
|
||||
->setParameter('val', $varKey)
|
||||
->setMaxResults(1)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
->getResult();
|
||||
// FIXME!!!
|
||||
if (!$rs) {
|
||||
return null;
|
||||
}
|
||||
$var = new ConfigVariable();
|
||||
$var->setKey($rs[0]["key"]);
|
||||
$var->setValue($rs[0]["value"]);
|
||||
$var->setSection($rs[0]["section"]);
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,4 +84,18 @@ class ConfigVariableRepository extends ServiceEntityRepository
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all DB config variables names on a Set.
|
||||
* @return Set Returns a Set with all variable names.
|
||||
*/
|
||||
public function getVariableSet(): Set
|
||||
{
|
||||
$varList = $this->findAll();
|
||||
$keyList = array_map(function ($var) {
|
||||
return $var->getKey();
|
||||
}, $varList);
|
||||
|
||||
return new Set($keyList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Consts\ConfigVariableConsts;
|
||||
use App\DTO\AppSetupConfig;
|
||||
use App\Entity\ConfigVariable;
|
||||
use App\Entity\User;
|
||||
use App\Enum\ConfigSectionType;
|
||||
use App\Enum\ConfigVariableSectionEnum;
|
||||
use App\Enum\UserRoleEnum;
|
||||
use App\Repository\ConfigVariableRepository;
|
||||
|
||||
@@ -23,7 +24,7 @@ class AppSetupService
|
||||
public function __construct(
|
||||
private LoggerInterface $logger,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private ConfigVariableRepository $repoVariables,
|
||||
private ConfigVariableService $configVars,
|
||||
private UserPasswordHasherInterface $passwordHasher,
|
||||
private Security $security
|
||||
) {}
|
||||
@@ -37,15 +38,18 @@ class AppSetupService
|
||||
//Create system variables.
|
||||
$this->logger->info("SomniaRooms Setup - Creating system variables...");
|
||||
|
||||
$var_setup = $this->repoVariables->find("SETUP_STATUS");
|
||||
if (!$var_setup) {
|
||||
$var_setup = new ConfigVariable();
|
||||
$var_setup->setKey("SETUP_STATUS");
|
||||
}
|
||||
$var_setup->setValue("1");
|
||||
$var_setup->setSection(ConfigSectionType::Internal);
|
||||
$this->entityManager->persist($var_setup);
|
||||
//Not neccesary anymore. CONFIG_INTERNAL_SETUP will be initialized with all vars.
|
||||
// $var_setup_key = ConfigVariableConsts::getKeyFromConstant(ConfigVariableConsts::CONFIG_INTERNAL_SETUP);
|
||||
// $var_setup = $this->configVars->getVariable($var_setup_key);
|
||||
// if (!$var_setup) {
|
||||
// $var_setup = new ConfigVariable();
|
||||
// $var_setup->setKey($var_setup_key);
|
||||
// $this->entityManager->persist($var_setup);
|
||||
// }
|
||||
// $var_setup->setValue("1");
|
||||
// $var_setup->setSection(ConfigVariableSectionEnum::Internal);
|
||||
|
||||
$this->configVars->InitVariablesOnSetup();
|
||||
|
||||
//Create user Admin.
|
||||
$this->logger->info("SomniaRooms Setup - Adding super-admin user...");
|
||||
@@ -53,8 +57,6 @@ class AppSetupService
|
||||
$user->setRoles([UserRoleEnum::ROLE_USER->value, UserRoleEnum::ROLE_ADMIN->value, UserRoleEnum::ROLE_SUPERADMIN->value]);
|
||||
$plaintextPassword = $configData->getAdminPass();
|
||||
|
||||
|
||||
|
||||
// hash the password (based on the security.yaml config for the $user class)
|
||||
$hashedPassword = $this->passwordHasher->hashPassword(
|
||||
$user,
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Consts\ConfigVariableConsts;
|
||||
use App\Entity\ConfigVariable;
|
||||
use App\Enum\ConfigVariableSectionEnum;
|
||||
use App\Repository\ConfigVariableRepository;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Service to manage config variables.
|
||||
@@ -14,33 +18,52 @@ class ConfigVariableService
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private ConfigVariableRepository $repoVariables
|
||||
) {}
|
||||
private EntityManagerInterface $entityManager,
|
||||
private ConfigVariableRepository $repoVariables,
|
||||
private LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
public function getVariable(string $key) {
|
||||
$var = $this->repoVariables->findVariableByKey($key);
|
||||
public function getVariable(string $key): ConfigVariable|null
|
||||
{
|
||||
return $this->repoVariables->findVariableByKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and init all variables.
|
||||
* To be used during Setup process.
|
||||
*/
|
||||
public function InitVariablesOnSetup(): void {
|
||||
public function InitVariablesOnSetup(): void
|
||||
{
|
||||
//Get a list of variables to check if those already exists.
|
||||
//$this->entityManager->beginTransaction();
|
||||
$varListDb = $this->repoVariables->getVariableSet();
|
||||
$varListPHP = ConfigVariableConsts::GetAllDefinedConfigVariablesList();
|
||||
|
||||
$entityManager = $this->repoVariables->getEntityManager();
|
||||
$entityManager->beginTransaction();
|
||||
foreach ($varListPHP as $varKey => $varValue) {
|
||||
if ($varListDb->contains($varKey)) {
|
||||
$this->logger->info("Var $varKey already created. Skipped!", [$varKey, $varValue]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->AddConfigVariable($varKey, $varValue[1], $varValue[0]);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
}
|
||||
catch (\Throwable $th) {
|
||||
$entityManager->rollback();
|
||||
} catch (\Throwable $th) {
|
||||
$this->entityManager->rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
private function AddConfigVariable(string $key, string $value, string $section): void {
|
||||
public function AddConfigVariable(string $key, string $value, ConfigVariableSectionEnum $section): void
|
||||
{
|
||||
$var = new ConfigVariable();
|
||||
$var->setKey($key);
|
||||
$var->setValue($value);
|
||||
$var->setSection($section);
|
||||
|
||||
$this->entityManager->persist($var);
|
||||
|
||||
$this->logger->info("Variable added to DB", ["key" => $key, "value" => $value, "section" => $section]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,36 +4,67 @@ namespace App\Service;
|
||||
|
||||
use App\DTO\AppSetupConfig;
|
||||
use App\DTO\ExampleDataConfig;
|
||||
use App\Entity\BedType;
|
||||
use App\Entity\ConfigVariable;
|
||||
use App\Entity\FareTable;
|
||||
use App\Entity\RoomCategory;
|
||||
use App\Entity\RoomCategoryBedType;
|
||||
use App\Entity\RoomFare;
|
||||
use App\Entity\User;
|
||||
use App\Enum\ConfigSectionType;
|
||||
use App\Enum\UserRoleEnum;
|
||||
use App\Repository\ConfigVariableRepository;
|
||||
use App\Repository\FareTableRepository;
|
||||
use App\Repository\RoomAvailabilityRepository;
|
||||
use App\Repository\RoomCategoryRepository;
|
||||
use App\Repository\RoomFareRepository;
|
||||
use App\Serializer\Normalizer\EntityByIdDenormalizer;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
||||
|
||||
/**
|
||||
* Service for setup proccess.
|
||||
*/
|
||||
class ExampleDataService
|
||||
{
|
||||
private Serializer $sampleSerializer;
|
||||
private FileLocator $fileLocator;
|
||||
|
||||
public function __construct(
|
||||
private string $sampleDirectory,
|
||||
private LoggerInterface $logger,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private RoomCategoryRepository $roomCategoryRepository,
|
||||
private RoomAvailabilityRepository $roomAvailabilityRepository,
|
||||
private FareTableRepository $fareTableRepository,
|
||||
private RoomFareRepository $roomFareRepository,
|
||||
) {}
|
||||
private RoomFareRepository $roomFareRepository
|
||||
) {
|
||||
|
||||
$this->sampleSerializer = new Serializer(
|
||||
array(
|
||||
new ObjectNormalizer(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PhpDocExtractor()
|
||||
),
|
||||
new ArrayDenormalizer(),
|
||||
),
|
||||
array('json' => new JsonEncoder())
|
||||
);
|
||||
$this->fileLocator = new FileLocator($this->sampleDirectory);
|
||||
}
|
||||
|
||||
public function AddExampleData(ExampleDataConfig $config): string
|
||||
{
|
||||
@@ -65,12 +96,53 @@ class ExampleDataService
|
||||
return "OK";
|
||||
}
|
||||
|
||||
private function GenerateRoomCategories(): bool
|
||||
public function GenerateRoomCategories(): bool
|
||||
{
|
||||
//TODOME.
|
||||
//Add Example BedTypes.
|
||||
$bedTypeList = $this->DeserializeSampleFile("SampleBedTypes.json", BedType::class . '[]');
|
||||
$this->PersistEntityArray($bedTypeList);
|
||||
|
||||
//Add Example RoomCategories
|
||||
$roomCategoryList = $this->DeserializeSampleFile("SampleRoomCategories.json", RoomCategory::class . '[]');
|
||||
$this->PersistEntityArray($roomCategoryList);
|
||||
|
||||
//Add Example RoomCategoryBedTypes
|
||||
$sampleRcBtData = $this->GetFileData("SampleRoomCategoryBedTypes.json");
|
||||
$sampleRcBtContent = json_decode($sampleRcBtData);
|
||||
foreach ($sampleRcBtContent as $contentElement) {
|
||||
$bedType = null;
|
||||
if (count($bedTypeList) > $contentElement->bedType) {
|
||||
$bedType = $bedTypeList[$contentElement->bedType];
|
||||
}
|
||||
|
||||
$roomCategory = null;
|
||||
if (count($roomCategoryList) > $contentElement->roomCategory) {
|
||||
$roomCategory = $roomCategoryList[$contentElement->roomCategory];
|
||||
}
|
||||
|
||||
if (!$roomCategory || !$bedType) {
|
||||
$this->logger->error(
|
||||
"Invalid RoomCategoryBedType: RoomCategory or BedType not found!",
|
||||
["json" => $contentElement, "bedtype" => $bedType, "roomcategory" => $roomCategory]
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = new RoomCategoryBedType();
|
||||
$item->setAmount($contentElement->amount);
|
||||
$item->setBedType($bedType);
|
||||
$item->setRoomCategory($roomCategory);
|
||||
|
||||
$this->entityManager->persist($item);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Generate Ramdom Data
|
||||
|
||||
private function GenerateAvailability(ExampleDataConfig $config): bool
|
||||
{
|
||||
$roomCategoryList = $this->roomCategoryRepository->findAll();
|
||||
@@ -126,4 +198,51 @@ class ExampleDataService
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Load Sample Data
|
||||
|
||||
//TODO
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
|
||||
private function DeserializeSampleFile(string $fileName, string $class)
|
||||
{
|
||||
$data = $this->GetFileData($fileName);
|
||||
if (!$data) return;
|
||||
|
||||
$itemList = $this->sampleSerializer->deserialize($data, $class, "json");
|
||||
|
||||
return $itemList;
|
||||
}
|
||||
|
||||
private function GetFileData(string $fileName): string|null
|
||||
{
|
||||
$file = $this->fileLocator->locate($fileName, null);
|
||||
$data = file_get_contents($file);
|
||||
if (!$data) {
|
||||
$this->logger->error(
|
||||
"ExampleDataService - DeserializeSampleFile - Unable to get file contents.",
|
||||
["file" => $fileName, "fileData" => $data]
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function PersistEntityArray(array $itemList): void
|
||||
{
|
||||
foreach ($itemList as $item) {
|
||||
try {
|
||||
$this->entityManager->persist($item);
|
||||
} catch (\Throwable $th) {
|
||||
$this->logger->error("Item can't be persisted", ["item" => $item, "exception" => $th]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user