20. Deployment of the client/server application on a hosting service
Here we outline the deployment of the client/server application we developed on a OVH [https://www.ovh.com/fr/] server. Deployment on other hosting providers should not be very different. We simply want to show that our application lends itself well to this deployment.
20.1. Server Deployment
The target OVH hosting is a basic hosting plan:
- a PHP 7.3 environment;
- a SGBD MySQL;
- no [Redis] server;
The third point requires us to modify version 14 on our tax calculation server.

We need to modify:
- the configuration files [1];
- the [AdminDataController] and [CalculerImpotController] controllers to account for the fact that there is no [Redis] server;
The [config.json] file changes as follows:
{
"databaseFilename": "Config/database.json",
"corsAllowed": false,
"redisAvailable":false,
"rootDirectory": "/.../www/apps/impot/serveur-php7",
"relativeDependencies": [
"/Entities/BaseEntity.php",
...
"/Controllers/AdminDataController.php"
],
"absoluteDependencies": [
"/.../vendor/autoload.php",
"/.../vendor/predis/predis/autoload.php"
],
"users": [
{
"login": "admin",
"passwd": "admin"
}
],
...
}
Comments
- line 4: a Boolean variable [redisAvailable] is introduced to indicate whether or not we have access to a server [Redis];
- lines 5, 13, 14: the absolute paths will change;
The [database.json] file changes as follows:
{
"dsn": "mysql:host=...;dbname=...",
"id": "...",
"pwd": "...",
"tableTranches": "dbimpots_tbtranches",
"colLimites": "limites",
"colCoeffR": "coeffr",
"colCoeffN": "coeffn",
"tableConstantes": "dbimpots_tbconstantes",
"colPlafondQfDemiPart": "plafondQfDemiPart",
...
}
Comments
- lines 2-4: the database name and its owner's credentials will change;
The [AdminDataController] controller changes as follows:
<?php
namespace Application;
// symfony dependencies
use \Symfony\Component\HttpFoundation\Response;
use \Symfony\Component\HttpFoundation\Request;
use \Symfony\Component\HttpFoundation\Session\Session;
// layer alias [dao]
use \Application\ServerDaoWithSession as ServerDaoWithRedis;
class AdminDataController implements InterfaceController {
// $config is the application configuration
// request processing
// session and can modify it
// $infos is additional information specific to each controller
// renders a [$statusCode, $état, $content, $headers] array
public function execute(
array $config,
Request $request,
Session $session,
array $infos = NULL): array {
// you must have a single parameter GET
$method = strtolower($request->getMethod());
...
// we can work
// Redis
if ($config["redisAvailable"]) {
\Predis\Autoloader::register();
...
} else {
try {
// retrieve tax data from the database
$dao = new ServerDaoWithRedis($config["databaseFilename"], NULL);
// taxAdminData
$taxAdminData = $dao->getTaxAdminData();
} catch (\Throwable $ex) {
// it didn't go well
// return result with error to main controller
$état = 1051;
return [Response::HTTP_INTERNAL_SERVER_ERROR, $état,
["réponse" => utf8_encode($ex->getMessage())], []];
}
}
// return result to main controller
$état = 1000;
return [Response::HTTP_OK, $état, ["réponse" => $taxAdminData], []];
}
}
Comments
- line 31: we now check whether or not we have a [Redis] server;
- lines 32–34: if so, the preceding code is included in its entirety;
- lines 35–46: otherwise, the tax authority data is retrieved from the database;
The [CalculerImpotController] controller, which also requires data from the tax administration, is updated in the same way.
Done. Deployment on the OVH server consisted of performing FTP. The following was downloaded to OVH:
- version and [vuejs-14-without-redis];
- the [vendor] folder, which contains all dependencies for the [vuejs-14-without-redis] server;
Once the FTP transfer was complete, we generated the tables required by the server using the following SQL script:
-- phpMyAdmin SQL Dump
-- version 4.8.5
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Oct 12, 2019 at 07:45 AM
-- Server version: 5.7.24
-- PHP Version: 7.2.11
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Table structure for table `dbimpots_tbconstantes`
--
CREATE TABLE `dbimpots_tbconstantes` (
`id` int(11) NOT NULL,
`plafondQfDemiPart` decimal(10,2) NOT NULL,
`plafondRevenusCelibatairePourReduction` decimal(10,2) NOT NULL,
`plafondRevenusCouplePourReduction` decimal(10,2) NOT NULL,
`valeurReducDemiPart` decimal(10,2) NOT NULL,
`plafondDecoteCelibataire` decimal(10,2) NOT NULL,
`plafondDecoteCouple` decimal(10,2) NOT NULL,
`plafondImpotCelibatairePourDecote` decimal(10,2) NOT NULL,
`plafondImpotCouplePourDecote` decimal(10,2) NOT NULL,
`abattementDixPourcentMax` decimal(10,2) NOT NULL,
`abattementDixPourcentMin` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `dbimpots_tbconstantes`
--
INSERT INTO `dbimpots_tbconstantes` (`id`, `plafondQfDemiPart`, `plafondRevenusCelibatairePourReduction`, `plafondRevenusCouplePourReduction`, `valeurReducDemiPart`, `plafondDecoteCelibataire`, `plafondDecoteCouple`, `plafondImpotCelibatairePourDecote`, `plafondImpotCouplePourDecote`, `abattementDixPourcentMax`, `abattementDixPourcentMin`) VALUES
(8, '1551.00', '21037.00', '42074.00', '3797.00', '1196.00', '1970.00', '1595.00', '2627.00', '12502.00', '437.00');
-- --------------------------------------------------------
--
-- Table structure for table `dbimpots_tbtranches`
--
CREATE TABLE `dbimpots_tbtranches` (
`id` int(11) NOT NULL,
`limites` decimal(10,2) NOT NULL,
`coeffR` decimal(10,2) NOT NULL,
`coeffN` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `dbimpots_tbtranches`
--
INSERT INTO `dbimpots_tbtranches` (`id`, `limites`, `coeffR`, `coeffN`) VALUES
(36, '9964.00', '0.00', '0.00'),
(37, '27519.00', '0.14', '1394.96'),
(38, '73779.00', '0.30', '5798.00'),
(39, '156244.00', '0.41', '13913.69'),
(40, '0.00', '0.45', '20163.45');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `dbimpots_tbconstantes`
--
ALTER TABLE `dbimpots_tbconstantes`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `dbimpots_tbtranches`
--
ALTER TABLE `dbimpots_tbtranches`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `dbimpots_tbconstantes`
--
ALTER TABLE `dbimpots_tbconstantes`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
--
-- AUTO_INCREMENT for table `dbimpots_tbtranches`
--
ALTER TABLE `dbimpots_tbtranches`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=41;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Once all of this was done, the [config.json, database.json] files were adapted to their new environment.
20.2. Deployment of the [Vue.js] client
It was decided to deploy the [Vue.js] client to URL and [http://machine/apps/impot/client-vuejs/]. This resulted in the following changes:
At the root of [workspace] from [VSCode], the following [vue.config.js] file was created:

The file [vue.config.js] is as follows:
// vue.config.js
module.exports = {
// the client's URL service [vuejs] of the tax calculation server
publicPath: '/apps/impot/client-vuejs/'
}
The file [router.js] [3] has also been modified:
// imports
import Vue from 'vue'
import VueRouter from 'vue-router'
...
// routing plugin
Vue.use(VueRouter)
// application routes
const routes = [
...
]
// the router
const router = new VueRouter({
// the roads
routes,
// the URL display mode
mode: 'history',
// the application's basic URL
base: '/apps/impot/client-vuejs/'
})
// route verification
router.beforeEach((to, from, next) => {
...
})
// router export
export default router
Comments
- line 21: the base of URL has been modified;
The [config.js] file is modified as follows:
// using the [axios] library
const axios = require('axios');
// query timeout HTTP
axios.defaults.timeout = 5000;
// the URL base of the tax calculation server
// schema [https] causes problems for Firefox because the calculation server
// sends a self-signed certificate. ok with Chrome and Edge. Safari not tested.
// with Firefox it's possible by requesting the URL below directly and telling Firefox
// that you accept the risk of an unsigned certificate. Then the [vuejs] client will work.
axios.defaults.baseURL = 'http://.../apps/impot/server-php7';
// we'll use cookies
axios.defaults.withCredentials = true;
// configuration export
export default {
// object [axios]
axios: axios,
// maximum session inactivity time: 5 min = 300 s = 300000 ms
duréeSession: 300000
}
Comments
- line 10: we set the URL from the tax calculation server;
The project's production version was generated using the [build] command from the following [package.json] and [5] files:
{
"name": "vuejs",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve vuejs-22/main.js",
"build": "vue-cli-service build vuejs-22-ovh-withBootstrapVue/main.js",
"lint": "vue-cli-service lint"
},
...
}
Once this was done, the [dist] folder, which contained the generated production version, was ‘uploaded’ to the OVH server in the [/.../apps/impot] folder and then renamed to [client-vuejs] so that the client code would be in the [/.../apps/impot/client-vuejs/] folder as planned. Then, in that folder, we downloaded the following file: [.htaccess]:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /apps/impot/client-vuejs/
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /apps/impot/client-vuejs/index.html [L]
</IfModule>
This is because the OVH web server used here is an Apache server. For other types of servers, please refer to the documentation |https://cli.vuejs.org/guide/deployment.html|.
The PHP 7 server application can be tested |here|.
The [Vue.js] client can be tested |here|.
20.3. Conclusion
The version [vuejs-21] was not essential. We had seen that the version [vuejs-20] handled user-entered URL correctly. Nevertheless, the new version provides additional convenience for the user. They can navigate by typing URL. The app then offers the view that best suits the app’s current state (session). Additionally, the version [vuejs-22] brings improvements to the app’s display on mobile devices.