Commit 9634818e authored by Laurent Lécluse's avatar Laurent Lécluse
Browse files

Système de mise à jour automatique des privilèges

parent 8c08df2f
......@@ -29,6 +29,7 @@ ne sont plus affichées lorsqu'on clique sur l'utilisateur en haut à droite.
* Formules de calcul : nouveau système de récupération des paramètres spécifiques directement implanté dans les formules.
Les vues V_FORMULE_LOCAL_I_PARAMS et V_FORMULE_LOCAL_VH_PARAMS ne sont plus nécessaires.
* Renforcement du script de mise à jour (pour les futures mises à jour) : détection de l'accès à la BDD OK ou non avant de démarrer la procédure et avertissement sans blocage si le cache ne peut pas se nettoyer.
* Système de mise à jour automatique : les privilèges sont maintenus à jour automatiquement
# OSE 8.1.2
......
<?php
$oa->majPrivileges();
\ No newline at end of file
......@@ -37,4 +37,11 @@ $schema->setLogger($scl);
$schema->alter($ref, $ddlConfig, true);
$c->println('Fin de mise à jour des définitions');
$c->println('Mise à jour des privilèges', $c::COLOR_LIGHT_PURPLE);
$oa->majPrivileges();
$c->println('Fin de la mise à jour des privilèges');
$c->println('');
\ No newline at end of file
......@@ -49,9 +49,6 @@ $c->passthru([
"php composer.phar install",
]);
// Néttoyage des caches et mise à jour des proxies, lancement du script de migration éventuel
$oa->run('clear-cache');
// Mise à jour des liens vers les répertoires publics des dépendances
$c->println("\nMise à jour des liens vers les répertoires publics des dépendances", $c::COLOR_LIGHT_CYAN);
$res = $oa->majUnicaenSymLinks($osedir);
......@@ -66,5 +63,8 @@ $oa->migration('pre');
$oa->run('update-bdd');
$oa->migration('post');
// Néttoyage des caches et mise à jour des proxies
$oa->run('clear-cache');
$c->println("\nFin de la mise à jour. N'oubliez pas de sortir du mode maintenance!");
$c->println('');
\ No newline at end of file
......@@ -194,6 +194,20 @@ class Bdd
/**
* @param string $sequenceName
*
* @return int
*/
public function sequenceNextVal(string $sequenceName): int
{
$r = $this->select("SELECT $sequenceName.NEXTVAL seqval FROM DUAL");
return (int)$r[0]['SEQVAL'];
}
/**
* @param string $sql
* @param array $params
......@@ -287,76 +301,15 @@ class Bdd
/**
* @param $table
* @param $data
*
* @return bool
*/
public function insert($table, $data, array $params = [])
{
$cols = array_keys($data);
$cols = implode(',', $cols);
$vals = '';
foreach ($data as $col => $val) {
if ($vals != '') $vals .= ',';
$vals .= ":$col";
}
$sql = "INSERT INTO $table ($cols) VALUES ($vals)";
return $this->exec($sql, $data);
}
public function copy(self $source, string $table)
{
}
/**
* @param string $table
* @param array|string|integer $data
* @param string $name
*
* @return bool
*/
public function delete(string $table, $data)
{
if (!is_array($data)) {
$data = ['ID' => $data];
}
$sql = "DELETE FROM \"$table\" WHERE ";
$conds = "";
foreach ($data as $col => $val) {
if ($conds != '') {
$conds .= ' AND ';
}
$conds .= "$col = :$col";
}
$sql .= $conds;
return $this->exec($sql, $data);
}
/**
* Vide une table
*
* @param string $table
*
* @return bool
* @return Table
*/
public function truncate(string $table)
public function getTable(string $name): Table
{
$sql = "TRUNCATE TABLE \"$table\"";
$table = new Table($this, $name);
return $this->exec($sql);
return $table;
}
......
<?php
namespace BddAdmin\Data;
use BddAdmin\Bdd;
use BddAdmin\BddAwareTrait;
class Updater
{
use BddAwareTrait;
/**
* @inheritDoc
*/
public function __construct(Bdd $bdd)
{
$this->setBdd($bdd);
}
/**
* @param string $table
* @param array $data
* @param string|array $key
* @param array $ignoredCols
*
* @throws \BddAdmin\Exception\BddCompileException
* @throws \BddAdmin\Exception\BddException
* @throws \BddAdmin\Exception\BddIndexExistsException
*/
public function update(string $table, array $data, $key, array $options = [])
{
$ddlObject = new \BddAdmin\Ddl\DdlTable($this->getBdd());
$ddl = $ddlObject->get($table)[$table];
$tableWithId = isset($ddl['columns']['ID']);
$tableWithSequence = !empty($ddl['sequence']);
/* Initialisation */
$records = [];
$newRecord = [
'id' => null,
'bdd' => [],
'data' => [],
];
if ($tableWithId) {
$options['ID']['ignore'] = true;
}
/* Chargement des enregistrements actuels */
$result = $this->getBdd()->select('SELECT * FROM ' . $ddl['name']);
foreach ($result as $record) {
$keyVal = $this->makeValWithKey($record, $key);
if (!isset($records[$keyVal])) {
$records[$keyVal] = $newRecord;
}
if ($tableWithId) {
$records[$keyVal]['id'] = (int)$record['ID'];
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$colVal = $record[$colName];
$records[$keyVal]['bdd'][$colName] = $this->sqlToVal($colVal, $colDdl);
}
}
}
/* Chargement des données */
foreach ($data as $d) {
foreach( $d as $k => $v ){
if (isset($options[$k]['transformer'])){
$d[$k] = $this->transform($v, $options[$k]['transformer'], $ddl['columns'][$k]);
}
}
$keyVal = $this->makeValWithKey($d, $key);
if (!isset($records[$keyVal])) {
$records[$keyVal] = $newRecord;
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$records[$keyVal]['data'][$colName] = $d[$colName];
}
}
}
/* Mise à jour de la table */
foreach ($records as $index => $record) {
if (empty($record['bdd'])) { // INSERT
if (empty($record['id']) && $tableWithSequence) {
$record['id'] = $this->getBdd()->sequenceNextVal($ddl['sequence']);
}
$new = [];
if ($tableWithId){
$new['ID'] = $record['id'];
}
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
$new[$colName] = $record['data'][$colName];
}
}
$this->getBdd()->insert($ddl['name'], $new);
} elseif (empty($record['data'])) { // DELETE
$this->getBdd()->delete($ddl['name'], $record['id']);
} else { // UPDATE ?
$diff = [];
foreach ($ddl['columns'] as $colName => $colDdl) {
if (!isset($options[$colName]['ignore']) || !$options[$colName]['ignore']) {
if ($record['bdd'][$colName] !== $record['data'][$colName]) {
$diff[$colName] = $record['data'][$colName];
}
}
}
if (!empty($diff)) {
$this->getBdd()->update($ddl['name'], $diff, ['ID' => $record['id']]);
}
}
}
}
protected function transform($value, string $transformer, array $ddl)
{
$val = $this->getBdd()->select(sprintf($transformer,':val'), ['val' => $value]);
$result = $this->sqlToVal(current($val[0]), $ddl);
return $result;
}
protected function makeValWithKey( array $data, $key)
{
$result = '';
$key = (array)$key;
foreach( $key as $k ){
if ($result != ''){
$result .= '_&@&@&@&_';
}
$result .= $data[$k];
}
return $result;
}
protected function sqlToVal($value, array $ddl)
{
switch ($ddl['type']) {
case 'NUMBER':
if (1 == $ddl['precision']) {
return $value === '1';
} else {
return (int)$value;
}
case 'FLOAT':
return (float)$value;
case 'VARCHAR2':
case 'CLOB':
return $value;
case 'DATE':
$date = \DateTime::createFromFormat('Y-m-d', $value);
$date->setTime(0, 0, 0, 0);
return $date;
case 'BLOB':
return $value;
default:
throw new \Exception("Type de donnée " . $ddl['type'] . " non géré.");
}
return $value;
}
}
\ No newline at end of file
<?php
namespace BddAdmin;
use BddAdmin\Ddl\DdlTable;
class Table
{
use BddAwareTrait;
/**
* @var string
*/
private $name;
/**
* @var array
*/
private $ddl;
/**
* @var array
*/
private $transformCache = [];
/**
* @inheritDoc
*/
public function __construct(Bdd $bdd, string $name)
{
$this->setBdd($bdd);
$this->name = $name;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return array
*/
public function getDdl(): array
{
if (empty($this->ddl)) {
$ddlObject = new DdlTable($this->getBdd());
$this->ddl = $ddlObject->get($this->name)[$this->name];
}
return $this->ddl;
}
/**
* @param array|integer|null $where
* @param string|null $orderBy
*
* @return array
* @throws Exception\BddCompileException
* @throws Exception\BddException
* @throws Exception\BddIndexExistsException
*/
public function select($where = null, array $options = []): array
{
/* Initialisation des entrées */
$defaultOptions = [
'orderBy' => '',
'key' => null,
];
$options = array_merge($defaultOptions, $options);
$ddl = $this->getDdl();
/* Construction et exécution de la requête */
$cols = '';
foreach ($ddl['columns'] as $colDdl) {
if ($cols != '') $cols .= ', ';
if ($colDdl['type'] == 'DATE') {
$cols .= 'to_char(' . $colDdl['name'] . ',\'YYYY-mm-dd\') ' . $colDdl['name'];
} else {
$cols .= $colDdl['name'];
}
}
$sql = "SELECT $cols FROM \"$this->name\"";
$params = [];
$sql .= $this->makeWhere($where, $options, $params);
if ($options['orderBy']) {
$sql .= ' ORDER BY ' . $options['orderBy'];
}
$select = $this->getBdd()->select($sql, $params);
/* Mise en forme des résultats */
$data = [];
foreach ($select as $d) {
foreach ($d as $c => $v) {
$d[$c] = $this->sqlToVal($v, $ddl['columns'][$c]);
}
$keyValue = $this->makeKey($d, $options['key']);
$data[$keyValue] = $d;
}
return $data;
}
/**
* @param array $data
* @param array $options
*
* @return bool
* @throws Exception\BddCompileException
* @throws Exception\BddException
* @throws Exception\BddIndexExistsException
*/
public function insert(array $data, array $options = []): bool
{
if (!isset($data['ID']) && $this->hasId() && $this->hasSequence()) {
$data['ID'] = $this->getBdd()->sequenceNextVal($this->ddl['sequence']);
}
$cols = array_keys($data);
$cols = implode(', ', $cols);
$vals = '';
foreach ($data as $col => $val) {
if ($vals != '') $vals .= ',';
$transVal = ':' . $col;
if (isset($options['columns'][$col]['transformer'])) {
$transVal = '(' . sprintf($options['columns'][$col]['transformer'], $transVal) . ')';
}
$vals .= $transVal;
}
$sql = "INSERT INTO \"$this->name\" ($cols) VALUES ($vals)";
return $this->getBdd()->exec($sql, $data);
}
public function update(array $data, $where = null, array $options = []): bool
{
$params = [];
$dataSql = '';
foreach ($data as $col => $val) {
if ($dataSql != '') $dataSql .= ',';
$transVal = ':new_' . $col;
if (isset($options['columns'][$col]['transformer'])) {
$transVal = '(' . sprintf($options['columns'][$col]['transformer'], $transVal) . ')';
}
$dataSql .= $col . '=' . $transVal;
$params['new_' . $col] = $val;
}
$sql = "UPDATE \"$this->name\" SET $dataSql" . $this->makeWhere($where, $options, $params);
return $this->getBdd()->exec($sql, $params);
}
/**
* @param int|string|array|null $where
* @param array $options
*
* @return bool
*/
public function delete($where, array $options = []): bool
{
$params = [];
$sql = "DELETE FROM \"$this->name\"" . $this->makeWhere($where, $options, $params);
return $this->getBdd()->exec($sql, $params);
}
/**
* Vide une table
*
* @param string $table
*
* @return bool
*/
public function truncate(): bool
{
$sql = "TRUNCATE TABLE \"$this->name\"";
return $this->getBdd()->exec($sql);
}
public function merge(array $data, $key, array $options = [])
{
/* Initialisation */
$defaultOptions = [
'where' => null,
'key' => $key,
];
$options = array_merge($defaultOptions, $options);
$ddl = $this->getDdl();
$diff = [];
/* Chargement des données actuelles, à mettre à jour */
$oldData = $this->select($options['where'], $options);
foreach ($oldData as $k => $d) {
if (!isset($diff[$k])) {
$diff[$k] = ['old' => [], 'new' => []];
}
$diff[$k]['old'] = $d;
}
/* Mise en forme des nouvelles données */
foreach ($data as $d) {
foreach ($d as $c => $v) {
if (isset($options['columns'][$c]['transformer'])) {
$d[$c] = $this->transform($v, $options['columns'][$c]['transformer'], $ddl['columns'][$c]);
}
}
$k = $this->makeKey($d, $key);
if (!isset($diff[$k])) {
$diff[$k] = ['old' => [], 'new' => []];
}
$diff[$k]['new'] = $d;
}
/* Traitement */
foreach($diff as $dr){
$old = $dr['old'];
$new = $dr['new'];
if (empty($old)){ // INSERT
$this->insert($new);
}elseif(empty($new)){ // DELETE
$this->delete($this->makeKeyArray($old, $key));
}else{ // UPDATE si différent!!
$toUpdate = [];
foreach($old as $c => $ov){
if ($c != 'ID' && isset($new[$c]) && $new[$c] !== $old[$c]){
$toUpdate[$c] = $new[$c];
}
}
if (!empty($toUpdate)){
$this->update($toUpdate, $this->makeKeyArray($old,$key));
}
}
}
}
private function makeKeyArray(array $data, $key): array
{
if (!$key && $this->hasId()) {
$key = 'ID';