DocumentsTable.php 12.8 KB
<?php
namespace App\Model\Table;

use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\TableRegistry;

// (EP) ajouté pour delete()
use Cake\Datasource\EntityInterface;


/**
 * Documents Model
 *
 * @property \Cake\ORM\Association\BelongsTo $Materiels
 * @property \Cake\ORM\Association\BelongsTo $Suivis
 */
class DocumentsTable extends AppTable
{

    // Formats autorisés pour photo
    var $photo_formats = ['png','jpg','jpeg'];

    
    /**
     * Initialize method
     *
     * @param array $config
     *            The configuration for the Table.
     * @return void
     */
    public function initialize(array $config) {
        parent::initialize($config);
        
        $this->setTable('documents');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');
        
        $this->belongsTo('Materiels')
            ->setForeignKey('materiel_id')
            ->setJoinType('INNER');
            //->setConditions($conditions) // un tableau de conditions compatibles find() ou de chaînes SQL comme ['Users.active' => true]
            //->setFinder($finder) // La méthode finder à utiliser lors du chargement des enregistrements associés
        /*
        $this->belongsTo('Materiels', [
            'foreignKey' => 'materiel_id',
            'joinType' => 'INNER'
        ]);
        */
        
        $this->belongsTo('Suivis', [
            'foreignKey' => 'suivi_id',
            'joinType' => 'INNER'
        ]);
        
        $this->belongsTo('TypeDocuments', [
            'foreignKey' => 'type_document_id'
        ]);
    }

    /**
     * Default validation rules.
     *
     * @param \Cake\Validation\Validator $validator
     *            Validator instance.
     * @return \Cake\Validation\Validator
     */
    public function validationDefault(Validator $validator)
    {
        $validator->integer('id')->allowEmpty('id', 'create');
        
        $validator->allowEmpty('type_doc');
        
        $validator->allowEmpty('chemin_file');
        
        $validator->notEmpty('nom');
        
        $validator->allowEmpty('type_document_id');
        
        $validator->allowEmpty('description');
        
        $validator->allowEmpty('materiel_id');
        
        $validator->allowEmpty('photo');
        
        $validator->allowEmpty('suivi_id');
        
        //Mi regex pour mettre la règle alphaNumericDashUnderscore
        $validator->add('nom', 'alphaNumericDashUnderscore', [
        		'rule' => ['custom', '|^[0-9a-zA-Z_-]*$|'],
        		'message' => __('Le nom du document ne doit contenir ni espace ni accent (seulement des lettres, chiffres, ou tirets)'),
                //'message' => __('Le nom du document ne doit contenir que des chiffres, des lettres, des tirets, ou des tirets.'),
        ]);

        return $validator;
    }

    
    
    /**
     * Returns a rules checker object that will be used for validating
     * application integrity.
     *
     * @param \Cake\ORM\RulesChecker $rules
     *            The rules object to be modified.
     * @return \Cake\ORM\RulesChecker
     */
    public function buildRules(RulesChecker $rules)
    {
        $config = TableRegistry::get('Configurations')->find()
            ->where([
            'id =' => 1
        ])
            ->first();
        
        $checkSize = function ($entity) {
            // Taille fichier doit être inférieure à taille max upload du php.ini
            if ( empty($entity->get('chemin_file')['tmp_name']) ) 
                return empty($entity->get('chemin_file')['name']);
            // Taille fichier doit être inférieure à taille max définie dans config labinvent
            else {
                $size = $entity->get('chemin_file')['size'];
                if ($size === null) return false;
                $config = TableRegistry::get('Configurations')->get(1);
                /*
                $config = TableRegistry::get('Configurations')->find()
                    ->where([
                    'id =' => 1
                ])->first();
                */
                //if ($size !== null) {
                return ($size <= $config->taille_max_doc);
            } 
            return true;
        };
        
        $checkPhotoFormat = function ($entity) {
            //debug($entity); exit;
            if (! empty($entity->get('chemin_file')['tmp_name'])) {
                //if ($entity->get('photo') || $entity->get('type_document_id')==4) {
                if ($entity->get('photo')) {
                    $extension = strtolower(pathinfo($entity->get('chemin_file')['name'], PATHINFO_EXTENSION));
                    return in_array($extension, $this->photo_formats);
                }
                return true;
            }
            /*
            if ( $entity->get('edit') && $entity->get('type_document_id')==4 && !in_array($entity->get('type_doc'), $this->photo_formats))
                return false;
            */
            return true;
        };
        /*
        $checkPhotoFormat = function ($entity) {
            if (! empty($entity->get('chemin_file')['tmp_name'])) {
                if ($entity->get('photo') || $entity->get('type_document_id')==4) {
                    $extension = strtolower(pathinfo($entity->get('chemin_file')['name'], PATHINFO_EXTENSION));
                    return in_array($extension, $this->photo_formats);
                } 
                return true;
            }
            if ( $entity->get('edit') && $entity->get('type_document_id')==4 && !in_array($entity->get('type_doc'), $this->photo_formats))
                return false;
            return true;
        };
        */
        
        $checkFilePresence = function ($entity) {
            if (!$entity->get('edit')) 
                return ( !empty($entity->get('chemin_file')['tmp_name']) || !empty($entity->get('chemin_file')['name']) );
            return true;
        };
        
        // Attention, c'est la DERNIERE règle ajoutée qui est testée en premier !!! (c'est une pile)
        
        // REGLE 3 - Si photo, format doit être ok
        $rules->add($checkPhotoFormat, [
            //'errorField' => 'chemin_file',
            'errorField' => 'type_document_id',
            'message' => 'La photo doit etre au format png, jpg (ou jpeg)'
        ]);
        $rules->add($checkPhotoFormat, [
            'errorField' => 'chemin_file',
            'message' => 'La photo doit etre au format png, jpg (ou jpeg)'
        ]);
        
        // REGLE 2 - Fichier pas trop gros
        // - upload_max_size de php.ini
        $upload_max_size_phpini = round((int)ini_get("upload_max_filesize"),1);
        // - upload_max_size de notre config
        $upload_max_size_localconfig = round($config->taille_max_doc/(1024*1024), 1);
        //$upload_max_size_localconfig = substr( $config->taille_max_doc/(1024*1024), 0, 4);
        // - upload_max_size final = min des 2
        $upload_max_size_min = min($upload_max_size_localconfig,$upload_max_size_phpini);
        $rules->add($checkSize, [
            'errorField' => 'chemin_file',
            'message' => "Le fichier ne peut pas avoir une taille supérieure à $upload_max_size_min Mo (taille max configurée $upload_max_size_localconfig Mo ; taille max php.ini : $upload_max_size_phpini Mo)"
        ]);
        
        // REGLE 1 - Fichier présent
        $rules->add($checkFilePresence, [
            'errorField' => 'chemin_file',
            'message' => 'Un fichier doit être désigné'
        ]);
        
        return $rules;
    }

    /**
     * Custom Validation Rules
     */
    public function fileExtension($check, $extensions, $allowEmpty = false)
    {
        $file = current($check);
        if ($allowEmpty && empty($file['tmp_name'])) {
            return true;
        }
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        return in_array($extension, $extensions);
    }

    /**
     * CakePHP Model Functions
     */
    /* AVANT la sauvegarde: 
     * - renseigner le champ "type_doc" avec l'extension, 
     * - mettre le type à photo si N/A alors que c'est une photo
     */
    public function beforeSave($event, $entity, $options)
    {
        $fileinfos = $entity->get('chemin_file');
        /*
        debug($fileinfos);
        Exemple de résultat :
        [
        	'tmp_name' => '/private/var/tmp/phpD0Wky7',
        	'error' => (int) 0,
        	'name' => 'admission.pdf',
        	'type' => 'application/pdf',
        	'size' => (int) 18735
        ]
        */
        if (! empty($fileinfos['tmp_name'])) {
            $extension = strtolower(pathinfo($fileinfos['name'], PATHINFO_EXTENSION));
            $entity->set('type_doc', $extension);
        }
        else {
            $extension = $entity->get('type_doc');
        }
        /*
        debug($entity);
        Exemple de résultat:
        object(App\Model\Entity\Document) {
        	'materiel_id' => (int) 12007,              // ou suivi_id
        	'nom' => 'zeoriazpe',
        	'type_document_id' => (int) 1,
        	'description' => '',
        	'photo' => false,
        	'chemin_file' => [
        		'tmp_name' => '/private/var/tmp/php9jc50F',
        		'error' => (int) 0,
        		'name' => 'admission.pdf',
        		'type' => 'application/pdf',
        		'size' => (int) 18735
        	],
        	'type_doc' => 'pdf',
        	'[new]' => true,
        	'[accessible]' => [
        		'*' => true,
        		'id' => false
        	],
        	'[dirty]' => [
        		'materiel_id' => true,
        		'nom' => true,
        		'type_document_id' => true,
        		'description' => true,
        		'photo' => true,
        		'chemin_file' => true,
        		'type_doc' => true
        	],
        	'[original]' => [],
        	'[virtual]' => [],
        	'[hasErrors]' => false,
        	'[errors]' => [],
        	'[invalid]' => [],
        	'[repository]' => 'Documents'
        }
        */
        /* (EP 2021 09) désactivé, sert à rien et fait buguer !
        // Si photo, set type_document_id = photo
        if ( in_array($extension, $this->photo_formats) ) {
            if ( $entity->get('type_document_id')==1 ) 
                $entity->set('type_document_id', 4);
        }
        */

        return true;
    }
    
    /*
    // Surcharge de la methode delete de AppTable
    public function delete(EntityInterface $entity, $options = []) {
        // On sauvegarde l'entité pour la réutiliser dans les notifications (ou ailleurs)
        $this->current_entity = $entity;
        return parent::delete($entity,$options);
    }
    */

    /**
     * CakePHP Model Functions
     */
    /* APRES la sauvegarde: 
     * - renommer le fichier attaché selon norme : id(du matériel ou suivi associé)_NomDoc_id(Doc).extension
     * - l'enregistrer au bon endroit :
     *  - si type photo => img/photos/
     *  - sinon (doc pdf ou autre) => files/
     */
    public function afterSave($event, $entity, $options)
    {
        $file = $entity->get('chemin_file');
        if (! empty($file['tmp_name'])) {
            $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
            // MI nouvelle norme pour les noms de documents uploadés
            // id(du matériel ou suivi associé)_NomDoc_id(Doc).extension
            /*
            if(!$entity->get('materiel_id') == Null ) {
            	$id=$entity->get('materiel_id');
            } else {
            	$id=$entity->get('suivi_id');
            }
            */
            $id = ( $entity->get('materiel_id') !== Null ) ? $entity->get('materiel_id') : $entity->get('suivi_id'); 
            $nom = $id."_".$entity->get('nom')."_".$entity->get('id'). '.' . $extension;
            //if ($entity->get('photo')) {
            if ( in_array($entity->get('type_doc'), $this->photo_formats) ) {
                // Photos dans img/photos/
            	move_uploaded_file($file['tmp_name'], 'img' . DS . 'photos' . DS . $nom );
            } else {
                // Docs dans files/
                move_uploaded_file($file['tmp_name'], 'files' . DS . $nom );
            }
        }
    }

    /**
     * CakePHP Model Functions
     */
    // APRES la suppression: supprimer le fichier attaché (avec le bon nom)
    public function afterDelete($event, $entity, $options)
    {
    	// MI nouvelle norme pour les noms de documents uploadés
    	// id(du matériel ou suivi associé)_NomDoc_id(Doc).extension
    	/*
    	if(!$entity->get('materiel_id')== Null ) {
    		$id=$entity->get('materiel_id');
    	} else {
    		$id=$entity->get('suivi_id');
    	}
    	*/
    	$id = ( $entity->get('materiel_id') !== Null ) ? $entity->get('materiel_id') : $entity->get('suivi_id');
    	$nomFichier = $id."_".$entity->get('nom')."_".$entity->get('id').'.' . $entity->get('type_doc');
        //if ($entity->get('photo')) {
    	if ( in_array($entity->get('type_doc'), $this->photo_formats) ) {
        	unlink('img' . DS . 'photos' . DS . $nomFichier);
        } else {
        	unlink('files' . DS . $nomFichier);
        }
    }
}