Skip to content
Snippets Groups Projects
Commit 4b670daf authored by Thibaut Vallee's avatar Thibaut Vallee
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #35316 passed
Showing
with 978 additions and 0 deletions
.idea/
vendor/
.sass-cache/
stages:
- publish
update-satis:
stage: publish
image: python:3.9
script:
- apt-get update && apt-get -y upgrade && apt-get -y install curl
- curl https://gest.unicaen.fr/packagist/update
CHANGELOG
=========
1.0.0 (10/02/24)
-----
- Création de la librairie unicaen-fichier
<?php
namespace Fichier;
use Laminas\Http\Request as HttpRequest;
use Laminas\Mvc\ModuleRouteListener;
use Laminas\Mvc\MvcEvent;
use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\Glob;
use Laminas\Config\Factory as ConfigFactory;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->getSharedManager()->attach('Laminas\Mvc\Controller\AbstractActionController', 'dispatch',
function (MvcEvent $e) {
$request = $e->getRequest();
if ($request instanceof HttpRequest && $request->isXmlHttpRequest()) {
$e->getTarget()->layout('layout/ajax.phtml');
}
}
);
}
public function getConfig()
{
$configInit = [
__DIR__ . '/config/module.config.php'
];
$configFiles = ArrayUtils::merge(
$configInit,
Glob::glob(__DIR__ . '/config/merged/{,*.}{config}.php', Glob::GLOB_BRACE)
);
return ConfigFactory::fromFiles($configFiles);
}
public function getAutoloaderConfig()
{
return array(
'Laminas\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
# UnicaenFichier
### Fichier et Nature
Fichier : Entité gérant les informations sur le fichier tel que sont nom, sa taille ...
Nature : Entité permettant de gerer les types de Fichier.
Par défaut, une seul : Document
Quelques routes par défaut permettant les actions de bases :
* `fichier/upload`
* `fichier/download`
* `fichier/archiver`
* `fichier/restaurer`
* `fichier/supprimer`
* Attention, il n'y a pas d'assertion par défaut et les ajout / suppression se font également sur le storage*
### Formulaire d'Upload
Le formulaire d'upload par défaut peux être partiellement configurer, notamment en ce qui concerne les types de fichier attentdu et la taille max.
il est possibles de rajouter ses propres validateur
```
'fichier' => [
'uplpoad' => [
'max-size' => '2MB',
'extentions' => ['pdf', 'csv'], // Extention des fichiers autorisée
//Pour les csv typeMine = text/plain
'type-mine' => ['application/pdf', 'text/plain'],
'validators' => [],
],
]
```
### Storage
Dépendance avec UnicaenStorage pour gerer le stockage des fichiers
A définir dans la config
```
'fichier' => [
...
'storage' => [
'adapters' => [
FilesystemStorageAdapter::class => [
'root_path' => "/tmp/",
],
... (conf des autres storage éventuel)
],
/**
* Adapter de stockage activé (unique).
*/
'adapter' => FilesystemStorageAdapter::class,
]
...
]
```
Les fonctions `FichierService:create(Fichier $fichier, ?bool $addToStorage=true)` et
`FichierService:delete(Fichier $fichier, bool $deleteFromStorage=true)` permettent de préciser si l'on souhaite déposer/supprimer le fichier du stockage.
La fonction `FichierService:createFichierFromUpload(array $file, Nature $nature, ?bool $addToStorage=true)`
permet de récupérer le fichier sous forme de tableau (via un formulaire), de creer se fichier et de la déposer dans le storage
### FileNameFormatter
Provider permettant de personnaliser comment sont nommés les fichiers.
2 fonctions a implémentée + 1 héritée :
* getFileName : nom du fichier
* getFileDir : nom du reper
* getFullName : = getFileDir().'/'. getFileName(); //
* Ces fonciton ne font pas de modification dans l'entité, charge a vous lors de l'ajout de modifier le NomStockage (a priori avec getFullName)*
A définir dans la config
```
'fichier' => [
...
'file-name-formatter' => DefaultFileNameProvider::class
...
]
```
2 exemple existe déjà :
* DefaultFileNameProvider : `Ymd-His-uid-NomOriginale`
* NatureBasedFileNameProvider : `CodeNature/Ymd-His-uid-NomOriginale`
-- Table nécessaire au document
create table fichier_nature
(
id bigserial PRIMARY KEY,
code varchar(64) not null,
libelle varchar(256) not null,
description varchar(2048),
ordre int DEFAULT 0 NOT NULL
);
create unique index fichier_nature_code_unique on fichier_nature (code);
/** !!! on n'utilise pas un id de type int ici mais de type varchar (permet entre autre de mieux gerer la génration d'un nom de fichier)*/
create table fichier_fichier
(
id varchar(25) not null constraint fichier_fichier_pk primary key,
nom_original varchar(256) not null,
nom_stockage varchar(256) not null,
nature integer not null,
type_mime varchar(256) not null,
taille varchar(256),
histo_creation timestamp not null,
histo_createur_id integer not null,
histo_modification timestamp,
histo_modificateur_id integer,
histo_destruction timestamp,
histo_destructeur_id integer,
FOREIGN KEY ( nature ) REFERENCES fichier_nature ( id ),
FOREIGN KEY ( histo_createur_id ) REFERENCES unicaen_utilisateur_user ( id ),
FOREIGN KEY ( histo_createur_id ) REFERENCES unicaen_utilisateur_user ( id ),
FOREIGN KEY ( histo_createur_id ) REFERENCES unicaen_utilisateur_user ( id )
);
--
INSERT INTO fichier_nature (code, libelle, description, ordre) VALUES
('doc', 'Document', 'Document divers', 1)
ON CONFLICT (code) DO UPDATE
set libelle = excluded.libelle,
description = excluded.description,
ordre = excluded.ordre
;
\ No newline at end of file
INSERT INTO unicaen_privilege_categorie (code, libelle, ordre, namespace)
VALUES ('fichier', 'Gesion de fichiers', 200, 'Fichier\Provider\Privilege');
INSERT INTO unicaen_privilege_privilege(CATEGORIE_ID, CODE, LIBELLE, ORDRE)
WITH d(code, lib, ordre) AS (
SELECT 'fichier_afficher', 'Afficher l''index des fichiers', 1
UNION SELECT 'fichier_televerser', 'Téléverser des fichiers', 2
UNION SELECT 'fichier_telecharger', 'Télécharger des fichiers', 3
UNION SELECT 'fichier_modifier', 'Modifier des fichiers', 4
UNION SELECT 'fichier_archiver', 'Archiver des fichiers', 5
UNION SELECT 'fichier_restaurer', 'Restaurer des fichiers', 6
UNION SELECT 'fichier_supprimer', 'Supprimer des fichiers', 7
)
SELECT cp.id, d.code, d.lib, d.ordre
FROM d
JOIN unicaen_privilege_categorie cp ON cp.CODE = 'fichier'
;
-- Temporaire : pour des test :
with roles as (
SELECT * from unicaen_utilisateur_role where role_id = 'Admin_tech'
),
privileges as (
SELECT p.* from unicaen_privilege_privilege p
join unicaen_privilege_categorie c on p.categorie_id = c.id
where c.code = 'fichier'
)
INSERT INTO demo.public.unicaen_privilege_privilege_role_linker (role_id, privilege_id)
SELECT roles.id, privileges.id FROM roles, privileges
on CONFLICT (role_id, privilege_id) do NOTHING;
\ No newline at end of file
{
"name": "unicaen/fichier",
"description": "Module de gestion de fichier",
"repositories": [
{
"type": "composer",
"url": "https://gest.unicaen.fr/packagist"
}
],
"require": {
"php": "^8.0",
"unicaen/privilege": "^8.0",
"unicaen/storage": "^1.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"classmap": [
"./Module.php"
]
}
}
<?php
return [
];
\ No newline at end of file
<?php
use Fichier\Filter\FileName\NatureBasedFileNameFormatter;
use UnicaenStorage\Adapter\FilesystemStorageAdapter;
return [
'fichier' => [
//Permet de fournir une configuration spécifique pour les formulaire d'upload de fichier
'uplpoad' => [
'max-size' => '2MB',
'extentions' => ['pdf', 'csv'], // Extention des fichiers autorisée
//Pour les csv typeMine = text/plain
'type-mine' => ['application/pdf', 'text/plain'],
'validators' => [],
],
'file-name-formatter' => NatureBasedFileNameFormatter::class,
],
];
\ No newline at end of file
<?php
/**
* Config concernant les fichiers NON liés à une thèse.
*/
namespace Fichier;
use Fichier\Controller\Factory\FichierControllerFactory;
use Fichier\Controller\FichierController;
use Fichier\Filter\FileName\DefaultFileNameFormatter;
use Fichier\Filter\FileName\NatureBasedFileNameFormatter;
use Fichier\Form\Upload\UploadForm;
use Fichier\Form\Upload\UploadFormFactory;
use Fichier\Form\Upload\UploadHydrator;
use Fichier\Provider\Privilege\FichierPrivileges;
use Fichier\Service\Fichier\FichierService;
use Fichier\Service\Fichier\FichierServiceFactory;
use Fichier\Service\Nature\NatureService;
use Fichier\Service\Nature\NatureServiceFactory;
use Fichier\View\Helper\FichierViewHelper;
use Laminas\Router\Http\Literal;
use Laminas\Router\Http\Segment;
use UnicaenPrivilege\Guard\PrivilegeController;
use UnicaenUtilisateur\ORM\Event\Listeners\HistoriqueListener;
return [
'bjyauthorize' => [
'guards' => [
PrivilegeController::class => [
[
'controller' => FichierController::class,
'action' => [
'upload',
],
'privileges' => [
FichierPrivileges::FICHIER_TELEVERSER,
],
],
[
'controller' => FichierController::class,
'action' => [
'download',
],
'privileges' => [
FichierPrivileges::FICHIER_TELECHARGER,
],
],
[
'controller' => FichierController::class,
'action' => [
'historiser'
],
'privileges' => [
FichierPrivileges::FICHIER_ARCHIVER,
],
],
[
'controller' => FichierController::class,
'action' => [
'restaurer'
],
'privileges' => [
FichierPrivileges::FICHIER_RESTAURER,
],
],
[
'controller' => FichierController::class,
'action' => [
'delete',
],
'privileges' => [
FichierPrivileges::FICHIER_SUPPRIMER,
],
],
],
],
],
// PRoblème dans les routes ? d
'router' => [
'routes' => [
'fichier' => [
'type' => Literal::class,
'options' => [
'route' => '/fichier',
],
'may_terminate' => true,
'child_routes' => [
'upload' => [
'type' => Segment::class,
'may_terminate' => true,
'options' => [
'route' => '/upload[/:nature]',
'constraints' => [
"affectationStage" => '[a-zA-Z0-9]+',
],
'defaults' => [
'controller' => FichierController::class,
'action' => 'upload',
],
],
],
'download' => [
'type' => Segment::class,
'may_terminate' => true,
'options' => [
'route' => '/download/:fichier',
'defaults' => [
'controller' => FichierController::class,
'action' => 'download'
],
],
],
'historiser' => [
'type' => Segment::class,
'may_terminate' => true,
'options' => [
'route' => '/historiser/:fichier',
'defaults' => [
'controller' => FichierController::class,
'action' =>'historiser',
],
],
],
'restaurer' => [
'type' => Segment::class,
'may_terminate' => true,
'options' => [
'route' => '/restaurer/:fichier',
'defaults' => [
'controller' => FichierController::class,
'action' => 'restaurer',
],
],
],
'supprimer' => [
'type' => Segment::class,
'may_terminate' => true,
'options' => [
'route' => '/supprimer/:fichier',
'defaults' => [
'controller' => FichierController::class,
'action' => 'delete',
],
],
],
],
],
],
],
'form_elements' => [
'factories' => [
UploadForm::class => UploadFormFactory::class,
],
],
'hydrators' => [
'invokables' => [
UploadHydrator::class => UploadHydrator::class,
],
],
'service_manager' => [
'invokables' => [
DefaultFileNameFormatter::class => DefaultFileNameFormatter::class,
NatureBasedFileNameFormatter::class => NatureBasedFileNameFormatter::class,
],
'factories' => [
FichierService::class => FichierServiceFactory::class,
NatureService::class => NatureServiceFactory::class,
],
],
'controllers' => [
'factories' => [
FichierController::class => FichierControllerFactory::class,
],
],
'view_helpers' => [
'invokables' => [
'fichier' => FichierViewHelper::class,
],
],
'doctrine' => [
'eventmanager' => [
'orm_default' => [
'subscribers' => [
HistoriqueListener::class,
],
],
],
],
];
<?php
use Doctrine\ORM\Mapping\Driver\XmlDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
use Fichier\Controller\Factory\IndexControllerFactory;
use Fichier\Controller\IndexController;
use Fichier\Provider\Privilege\FichierPrivileges;
use Laminas\Router\Http\Literal;
use UnicaenPrivilege\Guard\PrivilegeController;
return array(
'bjyauthorize' => [
'guards' => [
PrivilegeController::class => [
[
'controller' => IndexController::class,
'action' => [
'index',
],
'privileges' => [
FichierPrivileges::FICHIER_AFFICHER,
],
],
],
],
],
'doctrine' => [
'driver' => [
'orm_default' => [
'class' => MappingDriverChain::class,
'drivers' => [
'Fichier\Entity\Db' => 'orm_default_xml_driver',
],
],
'orm_default_xml_driver' => [
'class' => XmlDriver::class,
'cache' => 'Fichier',
'paths' => [
__DIR__ . '/../src/Entity/Db/Mapping',
],
],
],
'cache' => [
'UnicaneFichier' => [
'namespace' => 'FICHIER__' . __NAMESPACE__,
],
],
],
'router' => [
'routes' => [
'fichier' => [
'type' => Literal::class,
'options' => [
'route' => '/fichier',
'defaults' => [
'controller' => IndexController::class,
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [],
],
],
],
'controllers' => [
'factories' => [
IndexController::class => IndexControllerFactory::class,
],
],
'service_manager' => [
'factories' => [
],
],
'form_elements' => [
'factories' => [
],
],
'hydrators' => [
'invokables' => [
],
],
'view_helpers' => [
'invokables' => [
],
],
'view_manager' => [
'template_path_stack' => [
__DIR__ . '/../view',
],
],
);
<?php
namespace Fichier\Controller\Factory;
use Fichier\Controller\FichierController;
use Fichier\Form\Upload\UploadForm;
use Fichier\Service\Fichier\FichierService;
use Fichier\Service\Nature\NatureService;
use Interop\Container\ContainerInterface;
class FichierControllerFactory {
/**
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \Psr\Container\ContainerExceptionInterface
*/
public function __invoke(ContainerInterface $container): FichierController
{
/**
* @var NatureService $natureService
* @var FichierService $fichierService
*/
$natureService = $container->get(NatureService::class);
$fichierService = $container->get(FichierService::class);
// $s3Service = $container->get(S3Service::class);
/**
* @var UploadForm $uploadForm
*/
$uploadForm = $container->get('FormElementManager')->get(UploadForm::class);
$controller = new FichierController();
$controller->setNatureService($natureService);
$controller->setFichierService($fichierService);
$controller->setUploadForm($uploadForm);
return $controller;
}
}
\ No newline at end of file
<?php
namespace Fichier\Controller\Factory;;
use Fichier\Controller\IndexController;
use Interop\Container\ContainerInterface;
class IndexControllerFactory {
public function __invoke(ContainerInterface $container) : IndexController
{
return new IndexController();
}
}
\ No newline at end of file
<?php
namespace Fichier\Controller;
use Fichier\Entity\Db\Fichier;
use Fichier\Form\Upload\UploadFormAwareTrait;
use Fichier\Service\Fichier\FichierServiceAwareTrait;
use Fichier\Service\Nature\NatureServiceAwareTrait;
use Laminas\Form\Element\Select;
use Laminas\Http\Request;
use Laminas\Http\Response;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
class FichierController extends AbstractActionController {
use NatureServiceAwareTrait;
use UploadFormAwareTrait;
use FichierServiceAwareTrait;
/**
* @return \Laminas\View\Model\ViewModel
*/
public function uploadAction() : ViewModel
{
$natureCode = $this->params()->fromRoute('nature');
if(isset($natureCode)) {
$nature = $this->getNatureService()->getNatureByCode($natureCode);
}
$fichier = new Fichier();
$form = $this->getUploadForm();
$form->setAttribute('action', $this->url()->fromRoute('fichier/upload',[] , [], true));
$form->bind($fichier);
if (isset($nature)) {
/** @var Select $select */
$select = $form->get('nature');
$select->setValueOptions([ $nature->getId() => $nature->getLibelle()]);
}
/** @var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$data = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($data);
if ($form->isValid()) {
$natureId = ($data['nature']) ?? null;
$file = ($data['fichier']) ?? null;
if ($file['name'] != '') {
$nature = $this->getNatureService()->getNature($natureId);
$this->getFichierService()->createFichierFromUpload($file, $nature);
}
exit();
}
}
$vm = new ViewModel();
$vm->setVariables([
'title' => 'Téléversement d\'un fichier',
'form' => $form,
]);
return $vm;
}
public function downloadAction() : Response|ViewModel
{
$fichier = $this->getFichierService()->getRequestedFichier($this);
if (!$fichier) {
return $this->notFoundAction();
}
$contentType = $fichier->getTypeMime() ?: 'application/octet-stream';
$contenuFichier = $this->getFichierService()->getStorageFileContent($fichier);
header('Content-Description: File Transfer');
header('Content-Type: ' . $contentType);
header('Content-Disposition: attachment; filename=' . $fichier->getNomOriginal());
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . $fichier->getTaille());
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
header('Pragma: public');
echo $contenuFichier;
exit;
}
/**
* @throws \Exception
*/
public function deleteAction() : Response|ViewModel
{
$retour = $this->params()->fromQuery('retour');
$fichier = $this->getFichierService()->getRequestedFichier($this);
$request = $this->getRequest();
if ($request->isPost()) {
$data = $request->getPost();
if ($data["reponse"] === "oui") {
if ($fichier) $this->getFichierService()->delete($fichier);
}
if ($retour) {
return $this->redirect()->toUrl($retour);
}
exit();
}
$vm = new ViewModel();
if ($fichier !== null) {
$vm->setTemplate('fichier/default/confirmation');
$vm->setVariables([
'title' => "Suppression du fichier " . $fichier->getNomOriginal(),
'text' => "La suppression est définitive êtes-vous sûr&middot;e de vouloir continuer ?",
'action' => $this->url()->fromRoute('fichier/supprimer', ["fichier" => $fichier->getId()], [], true),
]);
}
return $vm;
}
public function historiserAction() : Response
{
$fichier = $this->getFichierService()->getRequestedFichier($this);
$this->getFichierService()->historise($fichier);
$retour = $this->params()->fromQuery('retour');
if ($retour) return $this->redirect()->toUrl($retour);
exit();
}
public function restaurerAction() : Response
{
$fichier = $this->getFichierService()->getRequestedFichier($this);
$this->getFichierService()->restore($fichier);
$retour = $this->params()->fromQuery('retour');
if ($retour) return $this->redirect()->toUrl($retour);
exit();
}
}
\ No newline at end of file
<?php
namespace Fichier\Controller;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
class IndexController extends AbstractActionController {
public function indexAction() : ViewModel
{
return new ViewModel([]);
}
}
\ No newline at end of file
<?php
namespace Fichier\Entity\Db;
use UnicaenUtilisateur\Entity\Db\HistoriqueAwareInterface;
use UnicaenUtilisateur\Entity\Db\HistoriqueAwareTrait;
class Fichier implements HistoriqueAwareInterface {
use HistoriqueAwareTrait;
/** @var string|null */
protected ?string $id = null;
/** @var ?string|null */
protected ?string $nomOriginal = null;
/** @var string|null */
protected ?string $nomStockage = null;
/** @var Nature|null */
protected ?Nature $nature = null;
/** @var string|null */
protected ?string $typeMime = null;
/** @var string|null */
protected ?string $taille = null;
/** @var string|null
* @desc tmpName permet à la création d'un fichier de connaitre sont emplacement temporaire.
* Par définition, il n'est pas stoqué en bdd
*/
protected ?string $tmpName = null;
/**
* @return string|null
*/
public function getId() : ?string
{
return $this->id;
}
/**
* @param string $id
* @return Fichier
*/
public function setId(string $id) : static
{
$this->id = $id;
return $this;
}
/**
* @return string|null
*/
public function getNomOriginal() : ?string
{
return $this->nomOriginal;
}
/**
* @param string $nomOriginal
* @return Fichier
*/
public function setNomOriginal(string $nomOriginal) : static
{
$this->nomOriginal = $nomOriginal;
return $this;
}
/**
* @return string|null
*/
public function getNomStockage() : ?string
{
return $this->nomStockage;
}
/**
* @param string $nomStockage
* @return Fichier
*/
public function setNomStockage(string $nomStockage) : static
{
$this->nomStockage = $nomStockage;
return $this;
}
/**
* @return Nature|null
*/
public function getNature() : ?Nature
{
return $this->nature;
}
/**
* @param Nature $nature
* @return Fichier
*/
public function setNature(Nature $nature) : static
{
$this->nature = $nature;
return $this;
}
/**
* @return string|null
*/
public function getTypeMime() : ?string
{
return $this->typeMime;
}
/**
* @param string $typeMime
* @return Fichier
*/
public function setTypeMime(string $typeMime) : static
{
$this->typeMime = $typeMime;
return $this;
}
/**
* @return string|null
*/
public function getTaille() : ?string
{
return $this->taille;
}
/**
* @param string $taille
* @return Fichier
*/
public function setTaille(string $taille) : static
{
$this->taille = $taille;
return $this;
}
public function getTmpName(): ?string
{
return $this->tmpName;
}
public function setTmpName(?string $tmpName): static
{
$this->tmpName = $tmpName;
return $this;
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Fichier\Entity\Db\Fichier" table="fichier_fichier">
<!-- !!!Remarque!!! il s'agit d'une chaine de caractère générée avec uniqid pour éviter les problèmes de forgeage ! -->
<id name="id" type="string" length="13" column="id" />
<field name="nomOriginal" type="string" length="256" column="nom_original" nullable="false"/>
<field name="nomStockage" type="string" length="256" column="nom_stockage" nullable="false"/>
<many-to-one target-entity="Fichier\Entity\Db\Nature" field="nature">
<join-column name="nature" referenced-column-name="id"/>
</many-to-one>
<field name="typeMime" type="string" length="256" column="type_mime" nullable="true"/>
<field name="taille" type="string" length="256" column="taille" nullable="true"/>
<!-- HISTORISATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<field name="histoCreation" type="datetime" column="histo_creation" nullable="false"/>
<field name="histoModification" type="datetime" column="histo_modification" nullable="false"/>
<field name="histoDestruction" type="datetime" column="histo_destruction" nullable="true"/>
<many-to-one target-entity="UnicaenUtilisateur\Entity\Db\User" field="histoCreateur">
<join-column name="histo_createur_id" referenced-column-name="ID"/>
</many-to-one>
<many-to-one target-entity="UnicaenUtilisateur\Entity\Db\User" field="histoModificateur">
<join-column name="histo_modificateur_id" referenced-column-name="ID"/>
</many-to-one>
<many-to-one target-entity="UnicaenUtilisateur\Entity\Db\User" field="histoDestructeur">
<join-column name="histo_destructeur_id" referenced-column-name="ID"/>
</many-to-one>
</entity>
</doctrine-mapping>
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Fichier\Entity\Db\Nature" table="fichier_nature">
<id name="id" type="integer" column="id">
<generator strategy="IDENTITY"/>
</id>
<field name="code" type="string" length="64" column="code" nullable="false"/>
<field name="libelle" type="string" length="256" column="libelle" nullable="false"/>
<field name="description" type="string" length="2048" column="description" nullable="true"/>
<field name="ordre" type="integer" column="ordre" nullable="false">
<options>
<option name="unsigned"/>
<option name="default">1</option>
</options>
</field>
</entity>
</doctrine-mapping>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment