Initial commit

This commit is contained in:
2020-11-02 15:46:52 +01:00
commit 17f974127c
13788 changed files with 1921656 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : thelia@openstudio.fr */
/* web : http://www.openstudio.fr */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* Ê Êalong with this program. ÊIf not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class ActionsBase {
private function __construct() {
}
}
?>

View File

@@ -0,0 +1,126 @@
<?php
/**
* Ce singleton permet de gérer la manipulation des client dans le front-office.
*
* @author Franck Allimant <franck@cqfdev.fr>
* @version $Id$
*/
require_once __DIR__ . "/../../fonctions/autoload.php";
class ActionsDevises extends ActionsBase {
private static $instance = false;
private $id_devise_defaut = false;
protected function __construct() {
}
/**
* Cette classe est un singleton
* @return ActionsAdminModules une instance de ActionsAdminModules
*/
public static function instance() {
if (self::$instance === false) self::$instance = new ActionsDevises();
return self::$instance;
}
/**
* Substitutions mail spécifiques aux devises
*
* @param string $texte
* @return string le texte avec les substitutions réalisées
*/
public function subsititutions_mail($devise, $texte) {
return $this->_substitutions($devise, $texte, '__', '__');
}
/**
* Substitutions simples spécifiques aux devises
*/
public function substitutions($devise, $texte) {
return $this->_substitutions($devise, $texte, '#', '');
}
/**
* Méthode générique de substitutions
*/
protected function _substitutions($devise, $texte, $prefixe, $suffixe) {
if (strstr($texte, "${prefixe}DEVISE")) {
$texte = str_replace("${prefixe}DEVISE_HTMLSYMBOLE${suffixe}", htmlentities($devise->symbole, ENT_COMPAT, 'UTF-8', false), $texte);
$texte = str_replace("${prefixe}DEVISE_SYMBOLE${suffixe}", $devise->symbole, $texte);
$texte = str_replace("${prefixe}DEVISE_DEFAUT${suffixe}", $devise->defaut, $texte);
$texte = str_replace("${prefixe}DEVISE_TAUX${suffixe}", $devise->taux, $texte);
$texte = str_replace("${prefixe}DEVISE_CODE${suffixe}", $devise->code, $texte);
$texte = str_replace("${prefixe}DEVISE_NOM${suffixe}", $devise->nom, $texte);
$texte = str_replace("${prefixe}DEVISE_ID${suffixe}", $devise->id, $texte);
$texte = str_replace("${prefixe}DEVISE${suffixe}", $devise->id, $texte);
}
return $texte;
}
/**
* Retourne l'ID de la devise par défaut. Pour améliorer les perfs, on cache cet ID
* dans une variable statique.
*/
public function get_id_devise_defaut() {
if ($this->id_devise_defaut === false) {
$devise = new Devise();
if ($devise->charger_defaut()) {
$this->id_devise_defaut = $devise->id;
}
else {
$this->id_devise_defaut = 1;
}
}
return $this->id_devise_defaut;
}
/**
* Retourne la devise courante.
*/
public function get_devise_courante() {
return new Devise($this->get_id_devise_courante());
}
/**
* Retourne l'ID de la devise courante.
*/
public function get_id_devise_courante() {
return $this->id_devise_courante_definie() ? $this->get_id_devise_session() : $this->get_id_devise_defaut();
}
/**
* Met à jour l'ID de la devise courante.
*/
public function set_id_devise_courante($id_devise) {
$_SESSION['navig']->devise = $id_devise;
}
/**
* Détermine si une devise est définie en session.
*/
public function id_devise_courante_definie() {
return (isset($_SESSION['navig']->devise) && $_SESSION['navig']->devise !== false);
}
/**
* Retourne la devise actuellement définie en session
*/
public function get_id_devise_session() {
return $_SESSION['navig']->devise;
}
}
?>

View File

@@ -0,0 +1,148 @@
<?php
/**
* Ce singleton permet de gérer la manipulation des langues dans le front-office.
*
* @author Franck Allimant <franck@cqfdev.fr>
* @version $Id$
*/
require_once __DIR__ . "/../../fonctions/autoload.php";
class ActionsLang extends ActionsBase {
// Les constantes définissant l'action a effectuer si une traduction demandée est vide ou absente
const UTILISER_LANGUE_PAR_DEFAUT = 1;
const UTILISER_LANGUE_INDIQUEE = 2;
const VAR_UN_DOMAINE_PAR_LANGUE = 'un_domaine_par_langue';
const VAR_ACTION_SI_TRAD_ABSENTE = 'action_si_trad_absente';
private static $instance = false;
private $id_langue_defaut = false;
private $action_si_trad_absente = false;
private $un_domaine_par_langue = false;
private $mode_backoffice = false;
protected function __construct() {
}
/**
* Cette classe est un singleton
* @return ActionsLang une instance de ActionsLang
*/
public static function instance() {
if (self::$instance === false) self::$instance = new ActionsLang();
return self::$instance;
}
/**
* Méthode substitutions
*/
public function substitutions($lang, $texte) {
if (strstr($texte, "LANG")) {
$texte = str_replace("#LANG", $lang->id, $texte);
$texte = str_replace("#CODELANG", $lang->code, $texte);
}
return $texte;
}
public function est_mode_backoffice() {
return $this->mode_backoffice;
}
public function set_mode_backoffice($bool) {
$this->mode_backoffice = $bool;
}
/**
* Détermine si on fonctionne avec un domaine par langue (1), ou un domaine pour toutes les langues (0)
*/
public function get_un_domaine_par_langue() {
// Intialiser l'action à affectuer si la traduction n'est pas definie
if ($this->un_domaine_par_langue === false) {
$this->un_domaine_par_langue = Variable::lire(self::VAR_UN_DOMAINE_PAR_LANGUE);
}
return $this->un_domaine_par_langue;
}
/**
* Retourne l'ID de la langue par défaut. Pour améliorer les perfs, on cache cet ID
* dans une variable statique.
*/
public function get_id_langue_defaut() {
if ($this->id_langue_defaut === false) {
$lang = new Lang();
if ($lang->charger_defaut()) {
$this->id_langue_defaut = $lang->id;
}
else {
$this->id_langue_defaut = 1;
}
}
return $this->id_langue_defaut;
}
/**
* Retourner l'action à effectuer si une traduction est absente
* @return boolean
*/
public function get_action_si_trad_absente() {
// Intialiser l'action à affectuer si la traduction n'est pas definie
if ($this->action_si_trad_absente === false) {
$this->action_si_trad_absente = Variable::lire(self::VAR_ACTION_SI_TRAD_ABSENTE);
}
return $this->action_si_trad_absente;
}
/**
* Retourne la langue courante.
*/
public function get_langue_courante() {
return new Lang($this->get_id_langue_courante());
}
/**
* Retourne l'ID de la langue courante.
*/
public function get_id_langue_courante() {
return $this->id_langue_courante_defini() ? $this->get_id_lang_session() : $this->get_id_langue_defaut();
}
/**
* Met à jour l'ID de la langue courante.
*/
public function set_id_langue_courante($id_langue) {
if ($this->mode_backoffice)
$_SESSION["util"]->lang = $id_langue;
else
$_SESSION['navig']->lang = $id_langue;
}
/**
* Détermine si une langue est définie en session.
*/
public function id_langue_courante_defini() {
return $this->mode_backoffice ? isset($_SESSION["util"]->lang) : isset($_SESSION['navig']->lang);
}
/**
* Retourne la langue actuellement définie en session
*/
public function get_id_lang_session() {
return $this->mode_backoffice ? $_SESSION["util"]->lang : $_SESSION['navig']->lang;
}
}
?>

View File

@@ -0,0 +1,253 @@
<?php
/**
* Utilisation des modules depuis le front-office
*
* Ce singleton permet de gérer la manipulation des modules dans le front-office.
*
* @author Franck Allimant <franck@cqfdev.fr>
* @version $Id$
*/
require_once __DIR__ . "/../../fonctions/autoload.php";
require_once(__DIR__ . '/../../fonctions/traduction.php');
class ActionsModules extends ActionsBase {
private static $instance = false;
private $utiliser_cache_plugins = false;
protected $plugins_base_dir;
protected function __construct() {
// Définir le répertoire de base des plugins
$this->plugins_base_dir = __DIR__ . "/../../client/plugins";
$this->utiliser_cache_plugins = intval(Variable::lire("utilisercacheplugin")) != 0;
}
public static function instance() {
if (self::$instance === false) self::$instance = new ActionsModules();
return self::$instance;
}
/**
* @return string le chemin d'accès au dossier plugins sur le disque
*/
public function lire_chemin_base() {
return $this->plugins_base_dir;
}
/**
* @return string l'URL de base d'accès au dossier plugins
*/
public function lire_url_base() {
return rtrim(urlsite(), '/') . "/client/plugins";
}
/**
* @method string Retourne le chemin d'accès au répertoire d'un module
* @return Répertoire dans lequel se trouve le module
* @throws TheliaException::MODULE_REPERTOIRE_NON_TROUVE si le repertoire module n'existe pas
*/
public function lire_chemin_module($nom_module, $controle_existence = true) {
$path = "$this->plugins_base_dir/$nom_module";
if ($controle_existence === false || (file_exists($path) && is_dir($path)) ) return $path;
throw new TheliaException(trad("Répertoire du module %s non trouvé", 'admin', $nom_module), TheliaException::MODULE_REPERTOIRE_NON_TROUVE);
}
/**
* @method mixed Crée une instance d'un module à partir de son nom
* @return l'instance créée
* @throws TheliaException::MODULE_CLASSE_NON_TROUVEE si le module n'a pas été trouvé.
*/
private static $cache = array();
public function instancier($nom_module) {
$clazz = ucfirst($nom_module);
if (! $this->utiliser_cache_plugins || ! isset(self::$cache[$nom_module])) {
$classpath = $this->lire_chemin_module($nom_module) . "/$clazz". ".class.php";
// Ne pas utiliser @include, qui masque les éventuelles erreurs dans le fichier classe,
if (file_exists($classpath) && include_once($classpath))
{
$instance = new $clazz();
// S'assurer que le module a fourni son nom
if (empty($instance->nom_plugin)) $instance->nom_plugin = $nom_module;
self::$cache[$nom_module] = $instance;
}
else {
throw new TheliaException(trad("Aucune classe trouvé pour %s", 'admin', $nom_module), TheliaException::MODULE_CLASSE_NON_TROUVEE);
}
}
return self::$cache[$nom_module];
}
/**
* Récupérer le contenu du descripteur XML d'un module
*
* @param Module $module le module concerné
* @throws TheliaException si le descripteur XML n'existe pas ou est invalide
*/
protected function lire_descripteur_xml($module) {
if (! isset($module->xml)) {
$fic_xml = $this->lire_chemin_module($module->nom) . '/plugin.xml';
if (file_exists($fic_xml)) {
// Valider le fichier plugin.xml
$pdv = new PluginDescriptorValidator(__DIR__."/thelia_plugin.xsd");
$pdv->validate($fic_xml);
if ($xml = @simplexml_load_file($fic_xml)) {
$module->xml = $xml;
return;
}
}
unset($module->xml);
throw new TheliaException(trad("Fichier descripteur XML inexistant ou invalide pour %s", 'admin', $module->nom), TheliaException::MODULE_DESCRIPTEUR_XML_NON_TROUVE);
}
}
/**
* @method bool Déterminer si un module est activable
* @param Modules modules un object Modules chargé
* @return bool true si le module est activable, ou n'a pas d'indication de version
*/
public function est_activable($modules) {
try {
$this->lire_descripteur_xml($modules);
if (isset($modules->xml->thelia)) {
$version_courante = rtrim(preg_replace("/(.)/", "$1.", Variable::lire('version')), ".");
return version_compare($version_courante, $modules->xml->thelia) != -1;
}
} catch (Exception $e) {}
return true;
}
/**
* @method Modules[] Lister les modules d'un type donné. Utilisation d'un cache.
* @param int $type: le type de module (Classique, Paiement, Transport, Filtre)
* @param bool $actifs_seulement: seulement les modules actifs ?
* @param string $nom_module: retourner uniquement le module indiqué
*/
private static $list_cache = array();
public function lister($type = false, $actifs_seulement = false, $nom_module = '') {
$modules = new Modules();
$where = '';
if ($type !== false) $where .= "and type=$type ";
if ($actifs_seulement !== false) $where .= "and actif=1 ";
if ($nom_module !== '') $where .= "and nom='$nom_module' ";
$hash = md5($where);
if (! isset(self::$list_cache[$hash])) {
self::$list_cache[$hash] = array();
$resul = CacheBase::getCache()->query("select * from $modules->table where 1 $where order by classement", 'Modules');
if($resul != "") {
foreach($resul as $modules) {
try {
if (! $actifs_seulement)
{
if ($this->est_activable($modules)) {
$modules->activable = 1;
} else {
$modules->activable = 0;
}
}
self::$list_cache[$hash][] = $modules;
} catch (TheliaException $e) {
// Ignorer ce module
}
}
}
}
return self::$list_cache[$hash];
}
/**
* @method void Appel d'une méthode des modules qui l'implémentent
* @param string $methode le nom de la méthode
* @param mixed $arg2 l'argument 1 à passer à la méthode
* @param mixed $arg2 l'argument 2 à passer à la méthode
* @param string $nom_module si spécifié, seul ce module sera appelé
*/
public function appel_module($methode, &$arg1 = '', &$arg2 = '', $nom_module = '') {
$liste = $this->lister(false, true, $nom_module);
foreach($liste as $module) {
try {
$instance = $this->instancier($module->nom);
if (method_exists($instance, $methode)) $instance->$methode($arg1, $arg2);
} catch (Exception $e) {}
}
}
/**
*
* @method void Mise à jour de la description d'un module
* @param string $nom nom du module associé
* @param int $lang ID de la langue de la description
* @param string $titre titre du module
* @param string $chapo chapo du module
* @param string $description description du module
* @param int $devise ID de la devise associée
*/
public function mise_a_jour_description($nom_module, $lang, $titre, $chapo, $description, $devise) {
$md = new Modulesdesc();
$existe = $md->verif($nom_module, $lang);
$md->titre = $titre;
$md->chapo = $chapo;
$md->description = $description;
$md->devise = $devise;
if ($existe) {
$md->maj();
} else {
$md->id = '';
$md->lang = $lang;
$md->plugin = $nom_module;
$md->add();
}
}
}
?>

View File

@@ -0,0 +1,50 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : thelia@openstudio.fr */
/* web : http://www.openstudio.fr */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* <20> <20>along with this program. <20>If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class TheliaException extends Exception {
/**
* Codes des exception relatives aux Modules
*/
const MODULE_REPERTOIRE_NON_TROUVE = 100;
const MODULE_INACTIF = 101;
const MODULE_ERR_SUPPRESSION_REPERTOIRE = 102;
const MODULE_INCOMPATIBLE = 103;
const MODULE_ECHEC_CHARGEMENT = 104;
const MODULE_ECHEC_INSTALL = 105;
const MODULE_CLASSE_NON_TROUVEE = 106;
const MODULE_INVALIDE = 107;
const MODULE_FICHIER_ADMIN_NON_TROUVE = 108;
const MODULE_DESCRIPTEUR_XML_NON_TROUVE = 109;
const MODULE_ECHEC_UPLOAD = 110;
const MODULE_PREREQUIS_NON_VERIFIES = 111;
const MODULE_ECHEC_MIGRATION_DESCRIPTEUR = 112;
const MODULE_ECHEC_VALIDATION_DESCRIPTEUR = 113;
}
?>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding='UTF-8'?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="plugin">
<xs:complexType>
<xs:sequence>
<xs:element name="descriptif" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>le descriptif complet, dans autant de langues que nécessaire.
Le code de la langue doit être un code pays ISO 639</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="titre" minOccurs="1" maxOccurs="1"/>
<xs:element type="xs:string" name="chapo" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:string" name="description" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:string" name="postscriptum" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute type="xs:string" name="lang"/>
</xs:complexType>
</xs:element>
<xs:element type="xs:string" name="version">
<xs:annotation>
<xs:documentation>La version du plugin. Format libre</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="auteur">
<xs:annotation>
<xs:documentation>Auteur du plugin</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="nom"/>
<xs:element type="xs:string" name="societe" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:string" name="email" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:anyURI" name="web" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="type">
<xs:annotation>
<xs:documentation>Le type du plugin: classique, transport, paiement, filtre, taxe</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="classique"/>
<xs:enumeration value="transport"/>
<xs:enumeration value="paiement"/>
<xs:enumeration value="filtre"/>
<xs:enumeration value="taxe"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="prerequis" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Les plugins qui doivent déjà être présents</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="plugin" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="version" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="thelia">
<xs:annotation>
<xs:documentation>La version minimum requise de Thelia, au format 'dot' (1.2.3.4 par exemple)</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[0-9.]+"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="etat">
<xs:annotation>
<xs:documentation>Le statut actuel du plugin: alpha, beta, rc, production</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="alpha"/>
<xs:enumeration value="beta"/>
<xs:enumeration value="rc"/>
<xs:enumeration value="production"/>
<xs:enumeration value="autre"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element type="xs:string" name="documentation" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Le nom du fichier contenant la documentation. Ce fichier doit se trouver dans le répertoire du plugin.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element type="xs:anyURI" name="urlmiseajour" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>L'URL a interroger pour vérifier la présence d'une nouvelle version, appellé avec le nom du plugin et sa version</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>