Partage
  • Partager sur Facebook
  • Partager sur Twitter

[TUTO] MVC, bonnes pratiques et site complet !

Espace membres - À venir : livre d'or, news, etc.

    26 juin 2013 à 7:13:43

    bah tu ajoute un champ "selected" dans ta classe form qui pointe vers celui que tu veux sélectionner...

    • Partager sur Facebook
    • Partager sur Twitter
      6 août 2013 à 7:48:31

      Salut tout le monde !

      Super tuto Savageman ! Il m'a permis de mieux comprendre le modèle MVC et ses applications concrètes !

      Et merci beaucoup de proposer ces libraires bien pratiques comme la classe Form ! D'ailleurs comme j'applique parfois des classes aux labels de mes formulaires (en occurrence pour les champs requis pour les mettre en gras et les faire suivre d'un astérisque rouge) j'ai changé un petit peu ta class. Comme je débute en POO, je ne suis pas très sûr de mes modifications mais si quelqu'un est intéressé (ou y voit des erreurs) je poste la version que j'utilise avec les changements suivants :

      - linge 123 : ajout d'une méthode (public function setLabel_suffix($text)) à la Form pour pouvoir changer le suffixe des labels du formulaire (protected $label_suffix).

      - ligne 344 : modification de l'attribut $label pour pouvoir y ajouter des classes dans un tableau "className".

      - ligne 391 : modification de la méthode label pour pouvoir lui donner les classes à assigner au label.

      - lignes 582, 647, 865, 902, 973, 1064, 1146, 1198 : modification de la méthode magique __toString() pour ajouter les classes au label lors de l'intégratiom HTML.

      <?php
      /**
       * Class Form to create, test, and validate a form
       * @author Savageman
       * @tutorial http://www.siteduzero.com/informatique/tutoriels/votre-site-php-presque-complet-architecture-mvc-et-bonnes-pratiques/gestion-des-formulaires-avec-la-classe-form
       * @see http://www.siteduzero.com/forum-83-356916-p1-tuto-mvc-bonnes-pratiques-et-site-complet.html
       * @version 1.1 (?) last-edited on august, 05th 2013 by Chtroumpf
       */
      
      // ---------------------------------------------------------------------------
      class Form {
      
      	protected $fields;
      	protected $hidden_fields;
      	protected $submit_fields;
      	protected $fieldsets;
      	protected $errors;
      	protected $auto_id;
      	protected $label_suffix;
      	protected $bounded_data;
      	protected $cleaned_data;
      	protected $attrs;
      	protected $uniqid;
      
      	protected static $instances = array();
      
      	public function __construct($uniqid, $method = 'get') {
      
      		$this->fields= array();
      		$this->hidden_fields = array();
      		$this->submit_fields = array();
      		$this->fieldsets     = array();
      		$this->errors        = array();
      		$this->auto_id       = 'id_%s';
      		$this->label_suffix  = ' :';
      		$this->bounded_data  = array();
      		$this->cleaned_data  = array();
      		$this->attrs         = new AttributeList(array('method' => $method));
      
      		if (false !== $uniqid && in_array($uniqid, self::$instances)) {
      
      			trigger_error("Un formulaire identifié par '$uniqid' existe déjà ! Conflits potentiels détectés !", E_USER_WARNING);
      
      		} else {
      
      			self::$instances[] = $uniqid;
      			$this->uniqid = $uniqid;
      			$this->add('Hidden', 'uniqid')->value($uniqid);
      		}
      	}
      
      	public function is_valid(array $values) {
      
      		if ($this->is_submited()) {
      
      			$valid = true;
      
      			foreach($this->fields as $name => $f) {
      
      				$values[$name] = (isset($values[$name])) ? $values[$name] : null;
      				$valid = $f->is_valid($values[$name]) && $valid;
      			}
      
      			if ($valid) {
      
      				$this->cleaned_data = array();
      
      				foreach($this->fields as $name => $f) {
      
      					$this->cleaned_data[$f->get_name()] = $f->get_cleaned_value($values[$name]);
      				}
      			}
      			return $valid;
      		}
      		return false;
      	}
      
      	public function fields() {
      
      		return $this->fields;
      	}
      
      	public function field($name) {
      
      		return $this->fields[$name];
      	}
      
      	public function errors() {
      
      		$this->errors = array();
      
      		foreach($this->fields as $name=>$f) {
      
      			$this->errors[$name] = $f->errors();
      		}
      		return $this->errors;
      	}
      
      	public function bound($data) {
      
      		return $this->bind($data);
      	}
      
      	public function bind($data) {
      
      		foreach($data as $k=>$v) {
      
      			$this->bounded_data[$k] = $v;
      		}
      		return $this;
      	}
      
      	public function label_suffix() {
      
      		return $this->label_suffix;
      	}
      
      	public function auto_id() {
      
      		return $this->auto_id;
      	}
            
            // ajout de la méthode setLabel_suffix permettant de modifier le suffixe des labels de l'instance
            public function setLabel_suffix($text) {
                if(is_string($text)) {
                    $this->label_suffix = $text;
                }
            }
      
      	public function action($action) {
      
      		$this->attrs['action'] = $action;
      		return $this;
      	}
      
      	public function enctype($enctype) {
      
      		$enctype = strtolower($enctype);
      
      		if (in_array($enctype, array('multipart/form-data', 'application/x-www-form-urlencoded'))) {
      
      			$this->attrs['enctype'] = $enctype;
      		}
      		return $this;
      	}
      
      	public function method($method) {
      
      		$method = strtolower($method);
      
      		if (in_array($method, array('get', 'post'))) {
      
      			$this->attrs['method'] = $method;
      		}
      		return $this;
      	}
      
      	public function fieldsets($array) {
      
      		$this->fieldsets = $array;
      	}
      
      	public function is_submited() {
      
      		return $this->is_submitted();
      	}
      
      	public function is_submitted() {
      
      		$check = ($_SERVER['REQUEST_METHOD'] == 'POST') ? $_POST : $_GET;
      
      		if (!empty($check['uniqid']) && $check['uniqid'] == $this->uniqid) {
      
      			foreach($this->submit_fields as $s) {
      
      				if (isset($check[$s->get_name()])) { return true; }
      			}
      		}
      		return false;
      	}
      
      	public function add($field, $name) {
      
      		if (!isset($this->fields[$name])) {
      
      			$field = 'Form_'.ucfirst($field);
      			$field_object = new $field($name, $this);
      
      			if ('Form_Submit' == $field) {
      
      				$this->submit_fields[$name] = $field_object;
      
      			} else if ('Form_Hidden' == $field) {
      
      				$this->hidden_fields[$name] = $field_object;
      			}
      			$this->fields[$name] = $field_object;
      
      			return $field_object;
      
      		} else {
      
      			trigger_error("Un champ nommé '$name' existe déjà dans le formulaire identifié par '{$this->uniqid}'.", E_USER_WARNING);
      		}
      	}
      
      	public function get_bounded_data($name = null) {
      
      		if (null !== $name) {
      
      			return isset($this->bounded_data[$name]) ? $this->bounded_data[$name] : '';
      
      		} else {
      
      			return $this->bounded_data;
      		}
      		return null;
      	}
      
      	public function get_cleaned_data($name = null) {
      
      		if (!empty($this->cleaned_data)) {
      
      			$out = array();
      
      			if (func_num_args() > 1) {
      
      				if (!is_array($name)) {
      
      					$name = func_get_args();
      				}
      
      				foreach($name as $n) {
      
      					$out[] = isset($this->cleaned_data[$n]) ? $this->cleaned_data[$n] : '';
      				}
      
      				return $out;
      			}
      
      			if (null !== $name) {
      
      				return isset($this->cleaned_data[$name]) ? $this->cleaned_data[$name] : '';
      
      			} else {
      
      				return $this->cleaned_data;
      			}
      		}
      		return null;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$o = $tab.'<form'.$this->attrs.'>'."\n";
      
      		if (empty($this->fieldsets)) {
      
      			$o .= $this->_html_fields($tab."\t", array_diff_key($this->fields, $this->hidden_fields, $this->submit_fields));
      			if (!empty($this->hidden_fields)) { $o .= $this->_html_hidden_fields($tab."\t", $this->hidden_fields); }
      			$o .= $this->_html_fields($tab."\t", $this->submit_fields);
      
      		} else {
      
      			$hidden_fields = $this->hidden_fields;
      			$submit_fields = $this->submit_fields;
      
      			foreach ($this->fieldsets as $legend => $fields) {
      
      				$o .= $this->_html_fieldset($tab, $legend, $fields);
      
      				foreach($fields as $f) {
      
      					unset($hidden_fields[$f], $submit_fields[$f]);
      				}
      			}
      			if (!empty($hidden_fields)) { $o .= $this->_html_hidden_fields($tab."\t", $hidden_fields); }
      			if (!empty($submit_fields)) { $o .= $this->_html_fields($tab."\t", $submit_fields); }
      		}
      		$o .= $tab.'</form>';
      		return $o;
      	}
      
      	protected function _html_fields($tab, $fields, $filter = array()) {
      
      		$o = '';
      
      		foreach($fields as $f) {
      
      			if (empty($filter) || in_array($f->get_name(), $filter)) {
      
      				$o .= "$tab<p>\n".$f->__toString($tab."\t")."\n$tab</p>\n";
      			}
      		}
      		return $o;
      	}
      
      	protected function _html_hidden_fields($tab, $fields, $filter = array()) {
      
      		$o = ''; // "$tab<p>\n";
      
      		foreach($fields as $f) {
      
      			if (empty($filter) || in_array($f->get_name(), $filter)) {
      
      				$o .= $tab.$f->__toString($tab)."\n";
      			}
      		}
      		// $o .= "$tab</p>\n";
      		return $o;
      	}
      
      	protected function _html_fieldset($tab, $legend, $fields) {
      
      		$o  = "$tab\t".'<fieldset>'."\n";
      		$o .= "$tab\t".'<legend>'.$legend.'</legend>'."\n";
      		$o .= $this->_html_fields($tab."\t\t", $this->fields, $fields);
      		$o .= "$tab\t".'</fieldset>'."\n";
      		return $o;
      	}
      }
      
      // ---------------------------------------------------------------------------
      
      abstract class Form_Field {
      
      	protected $form;
      	protected $required;
      	protected $label;
      	protected $value;
      	protected $class;
      	protected $attrs;
      	protected $error_messages;
      	protected $custom_error_messages;
      
      	protected static $error_list = array();
      
      	public function __construct($name, $form) {
      
      		$this->form     = $form;
      		$this->required = true;
      		$this->label    = array('text'=>'','className'=>array());   // changé en tableau pour pouvoir ajouter des classes aux labels
      		$this->value    = '';
      		$this->class    = array();
      		$this->attrs    = new AttributeList;
      		$this->attrs['name'] = $name;
      		$this->error_messages= new ErrorList;
      		$this->custom_error_messages = array();
      
      		$this->_init();
      	}
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['required'])) {
      
      			self::$error_list['required'] = 'Ce champ est obligatoire.';
      		}
      		if (!isset(self::$error_list['maxlength'])) {
      
      			self::$error_list['maxlength'] = 'La longueur maximale est de %d caractères.';
      		}
      	}
      
      	public function is_valid($value) {
      
      		$value = $this->get_cleaned_value($value);
      
      		$valid = true;
      
      		if ($this->required && $value == '') {
      
      			$this->_error('required');
      			$valid = false;
      		}
      
      		if (isset($this->attrs['maxlength'])) {
      
      			if (isset($value[$this->attrs['maxlength']])) {
      
      				$this->_error('maxlength');
      				$valid = false;
      			}
      		}
      
      		return $valid;
      	}
            
            // modification de la méthode pour pouvoir ajouter des classes aux labels
      	public function label($text,$className = array()) {
      
      		$this->label['text'] = $text;
                  if(!empty($className)) {
                      foreach ($className as $value){
                          if(is_string($value))
                              $this->label['className'][] = $value;
                      }
                  }
      		return $this;
      	}
      
      	public function value($text) {
      
      		$this->value = $text;
      		return $this;
      	}
      
      	public function add_class($class) {
      
      		if (!in_array($class, $this->class)) { $this->class[] = $class; }
      		return $this;
      	}
      
      	public function required($bool = true) {
      
      		if (true === $bool) { $this->attrs['required'] = 'required'; $this->required = true; }
      		else { unset($this->attrs['required']); $this->required = false; }
      		return $this;
      	}
      
      	public function disabled($bool = true) {
      
      		if (true === $bool) { $this->attrs['disabled'] = 'disabled'; }
      		else { unset($this->attrs['disabled']); }
      		return $this;
      	}
      
      	public function readonly($bool = true) {
      
      		if (true === $bool) { $this->attrs['readonly'] = 'readonly'; }
      		else { unset($this->attrs['readonly']); }
      		return $this;
      	}
      
      	public function maxlength($value) {
      
      		if (ctype_digit((string)$value) && $value > 0) { $this->attrs['maxlength'] = $value; }
      		else { unset($this->attrs['maxlength']); }
      		return $this;
      	}
      
      	public function errors() {
      
      		return $this->error_messages;
      	}
      
      	public function get_name() {
      
      		return $this->attrs['name'];
      	}
      
      	public function get_cleaned_value($value) {
      
      		return $value;
      	}
      
      	public function get_value() {
      
      		return isset($this->attrs['value']) ? $this->attrs['value'] : '';
      	}
      
      	public function custom_error_message($id_error, $message) {
      
      		if (!isset(self::$error_list[$id_error])) {
      
      			trigger_error("Le message d'erreur identifié par '$id_error' ne s'applique pas à la classe ".get_class($this).".");
      
      		} else {
      
      			$this->custom_error_messages[$id_error] = $message;
      		}
      		return $this;
      	}
      
      	protected function _error($id_error) {
      
      		$error = $this->_get_error_message($id_error);
      
      		if ('maxlength' == $id_error) {
      
      			$this->error_messages[$id_error] = vsprintf($error, $this->attrs['maxlength']);
      
      		} else if (!$this->_custom_errors($id_error, $error)) {
      
      			$this->error_messages[$id_error] = $error;
      		}
      	}
      
      	protected function _custom_errors($id_error, $error) {
      
      		return false;
      	}
      
      	abstract public function __toString();
      
      	static protected function _generate_for_id($auto_id, $name) {
      
      		if (!empty($auto_id)) {
      
      			$for = sprintf(' for="'.$auto_id.'"', $name);
      			$id  = sprintf(' id="'.$auto_id.'"',  $name);
      			return array($for, $id);
      		}
      		return array('', '');
      	}
      
      	protected function _generate_class() {
      
      		if (!empty($this->class)) {
      
      			$this->attrs['class'] = implode(' ', $this->class);
      		}
      	}
      
      	protected function _get_error_message($id_error) {
      
      		if (isset($this->custom_error_messages[$id_error])) {
      
      			return $this->custom_error_messages[$id_error];
      
      		} else if (isset(self::$error_list[$id_error])) {
      
      			return self::$error_list[$id_error];
      		}
      		return 'Erreur inconnue : "'.$id_error.'"';
      	}
      }
      
      // ---------------------------------------------------------------------------
      abstract class Form_Input extends Form_Field {
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'text';
      	}
      
      	public function get_cleaned_value($value) {
      
      		$value = trim($value);
      		return parent::get_cleaned_value($value);
      	}
      
      	// abstract public function __toString($tab = '');
      }
      
      // ---------------------------------------------------------------------------
      class Form_Text extends Form_Input {
      
      	protected $autocomplete;
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'text';
      		$this->autocomplete = true;
      	}
      
      	public function autocomplete($bool) {
      
      		if (false === $bool) { $this->attrs['autocomplete'] = 'off'; $this->autocomplete = false; }
      		else { unset($this->attrs['autocomplete']); $this->autocomplete = true; }
      		return $this;
      
      	}
      
      	public function get_cleaned_value($value) {
      
      		return parent::get_cleaned_value(preg_replace('`[\x00-\x19]`i', '', $value));
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';
      		if (!empty($this->label['text'])) {
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
      			list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
      			$label = '<label'.$for.' class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";
      		}
      
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      
      		if (true === $this->autocomplete) {
      
      			$value = $this->form->get_bounded_data($this->attrs['name']);
      			$value = (!empty($value)) ? $value : $this->value;
      			$value = (!empty($value)) ? ' value="'.htmlspecialchars($value).'"' : '';
      
      		} else {
      
      			$value = '';
      		}
      
      		$field = '<input'.$id.$this->attrs.$value.' />';
      		return $tab.sprintf("%2\$s%1\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Hidden extends Form_Input {
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'hidden';
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		return $tab.'<input'.$this->attrs.' value="'.htmlspecialchars($this->value).'" />';
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Password extends Form_Text {
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'password';
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';
                  // nouvelle vérification de la présence d'un label
                  if (!empty($this->label['text'])) {
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
      			list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
      			$label = '<label'.$for.' class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";   // ajout de l'attribut class et des classes correspondantes au label
      		}
      
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      
      		$field = '<input'.$id.$this->attrs.' />';
      		return $tab.sprintf("%2\$s%1\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Email extends Form_Text {
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['invalid_email'])) {
      
      			self::$error_list['invalid_email'] = "Ce n'est pas une adresse e-mail valide.";
      		}
      	}
      
      	public function is_valid($value) {
      
      		if (parent::is_valid($value)) {
      
      			if (0 < preg_match('`^[[:alnum:]]([-_.]?[[:alnum:]])*@[[:alnum:]]([-.]?[[:alnum:]])*\.([a-z]{2,4})$`', $value)) {
      
      				return true;
      			}
      			$this->_error('invalid_email');
      			return false;
      		}
      		return false;
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Date extends Form_Text {
      
      	protected $format;
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['invalid_date'])) {
      
      			self::$error_list['invalid_date'] = "La date entrée n'existe pas.";
      		}
      		if (!isset(self::$error_list['invalid_date_format'])) {
      
      			self::$error_list['invalid_date_format'] = "La date entrée ne respecte pas le format imposé (%s).";
      		}
      	}
      
      	public function format($format) {
      
      		$this->format = $format;
      		return $this;
      	}
      
      	public function is_valid($value) {
      
      		if (parent::is_valid($value)) {
      
      			$from = array('dd', 'mm', 'yyyy', 'yy', 'HH', 'MM', 'SS');
      			$to   = array('%d', '%m',  '%Y',  '%y', '%H', '%M', '%S');
      			$format = str_replace($from, $to, $this->format);
      
      			date_default_timezone_set('Europe/Paris');
      			$datetime = strptime($value, $format);
      
      			if (false !== ($datetime)) {
      
      				if (!checkdate($datetime['tm_mon']+1, $datetime['tm_mday'], $datetime['tm_year']+1900)) {
      
      					$this->_error('invalid_date');
      					return false;
      				}
      				return true;
      			}
      			$this->_error('invalid_date_format');
      			return false;
      		}
      		return false;
      	}
      
      	protected function _custom_errors($id_error, $error) {
      
      		if ('invalid_date_format' == $id_error) {
      
      			$this->error_messages[$id_error] = vsprintf($error, $this->format);
      			return true;
      		}
      		return false;
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_File extends Form_Input {
      
      	protected $extensions;
      	protected $max_size;
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'file';
      		$this->form->enctype('multipart/form-data');
      		$this->extensions = array();
      		$this->max_size = 0;
      	}
      
      	public function filter_extensions($extensions) {
      
      		if (!is_array($extensions)) {
      
      			$extensions = func_get_args();
      		}
      		$this->extensions = $extensions;
      
      		return $this;
      	}
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['invalid_file_extension'])) {
      
      			self::$error_list['invalid_file_extension'] = "Cette extension est interdite ! (sont autorisées : %s).";
      		}
      		if (!isset(self::$error_list['file_too_big'])) {
      
      			self::$error_list['file_too_big'] = "Fichier trop volumineux ! (maximum : %d octets).";
      		}
      	}
      
      	public function is_valid($value) {
      
      		$name = $this->attrs['name'];
      
      		if (isset($_FILES[$name])) {
      
      			$value = isset($_FILES[$name]) ? $_FILES[$name]['name'] : null;
      
      			if (parent::is_valid($value)) {
      
      				if (!$this->required) {
      
      					return true;
      				}
      
      				if (!empty($this->extensions)) {
      
      					$ext = pathinfo($value, PATHINFO_EXTENSION);
      					if (!in_array($ext, $this->extensions)) {
      
      						$this->_error('invalid_file_extension');
      						$valid = false;
      					}
      				}
      
      				if (0 < $this->max_size && $this->max_size < $_FILES[$name]['size']) {
      
      					$this->_error('file_too_big');
      					$valid = false;
      				}
      
      				return ($_FILES[$name]['error'] == UPLOAD_ERR_OK && is_uploaded_file($_FILES[$name]['tmp_name']));
      			}
      		}
      		return false;
      	}
      
      	public function get_cleaned_value($value) {
      
      		return isset($_FILES[$this->attrs['name']]) ? $_FILES[$this->attrs['name']]['tmp_name'] : null;
      	}
      
      	public function max_size($size) {
      
      		$this->form->add('Hidden', 'POST_MAX_SIZE')->value($size);
      		$this->max_size = $size;
      
      		return $this;
      	}
      
      	protected function _custom_errors($id_error, $error) {
      
      		if ('invalid_file_extension' == $id_error) {
      
      			$this->error_messages[$id_error] = vsprintf($error, implode(', ', $this->extensions));
      			return true;
      		}
      		if ('file_too_big' == $id_error) {
      
      			$this->error_messages[$id_error] = vsprintf($error, implode(', ', $this->max_size));
      			return true;
      		}
      		return false;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';
                  // nouvelle vérification de la présence d'un label
                  if (!empty($this->label['text'])) {
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
      			list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
      			$label = '<label'.$for.' class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";
      		}
      
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      
      		$field = '<input'.$id.$this->attrs.' />';
      		return $tab.sprintf("%2\$s%1\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Submit extends Form_Input {
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'submit';
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      
      		$this->_generate_class();
      
      		// Pas d'auto_id pour les champs Submit...
                  if (!empty($this->label['text'])) {// nouvelle vérification de la présence d'un label
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
                      $label = '<label class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";
      		}
                  else $label = "";
      		$value = empty($this->value) ? '' : ' value="'.$this->value.'"';
      
      		$field = '<input'.$this->attrs.$value.' />';
      		return $tab.sprintf("%2\$s%1\$s", $field, $label);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Radio extends Form_Input {
      
      	protected $choices;
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'radio';
      		$this->choices = array();
      	}
      
      	public function choices($array) {
      
      		if (!is_array($array)) {
      
      			$array = func_get_args();
      		}
      		$this->choices = $array;
      
      		return $this;
      	}
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['incorrect_value'])) {
      
      			self::$error_list['incorrect_value'] = "La valeur fournie est interdite.";
      		}
      	}
      
      	public function is_valid($value) {
      
      		if (parent::is_valid($value)) {
      
      			if ($this->required && !in_array($value, $this->choices)) {
      
      				$this->_error('incorrect_value');
      				return false;
      			}
      			return true;
      		}
      		return false;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$i = $this->form->auto_id();
                  if (!empty($this->label['text'])) {// nouvelle vérification de la présence d'un label
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
                      $label = '<span class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'<br/></span>';
      		}
                  else $span = "";
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      		$value = $this->form->get_bounded_data($this->attrs['name']);
      		$value = (!empty($value)) ? $value : $this->value;
      
      		$j = 0;
      		$fields = array();
      		foreach($this->choices as $v => $c) {
      
      			$id = '';
      			$label = '';
      			if (!empty($i)) {
      
      				list($for, $id) = self::_generate_for_id($this->form->auto_id().'_'.(++$j), $this->attrs['name']);
      				$label = '<label'.$for.'>'.$c.'</label>';
      			}
      			$this->attrs['value'] = htmlspecialchars($v);
      			$checked = '';
      			if ($value == $v) { $checked = ' checked="checked"';  }
      			$fields[] = '<input'.$id.$this->attrs.$checked.' /> '.$label.'<br />';
      
      		}
      		$field = "\n$tab".implode("\n$tab", $fields);
      		return $tab.sprintf("%2\$s%3\$s%1\$s", $field, $span, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Select extends Form_Input {
      
      	protected $choices;
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->choices = array();
      		unset($this->attrs['type']);
      	}
      
      	public function choices($array) {
      
      		if (!is_array($array)) {
      
      			$array = func_get_args();
      		}
      		$this->choices = $array;
      
      		return $this;
      	}
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['incorrect_value'])) {
      
      			self::$error_list['incorrect_value'] = "La valeur fournie est interdite.";
      		}
      	}
      
      	public function is_valid($value) {
      
      		if (parent::is_valid($value)) {
      
      			if ($this->required && !in_array($value, $this->choices)) {
      
      				$this->_error('incorrect_value');
      				return false;
      			}
      			return true;
      		}
      		return false;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';
                  if (!empty($this->label['text'])) {// nouvelle vérification de la présence d'un label
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
                      list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
                      $label = '<label'.$for.' class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";
      		}
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      		$value = $this->form->get_bounded_data($this->attrs['name']);
      		$value = (!empty($value)) ? $value : $this->value;
      
      		$j = 0;
      		$fields = array();
      		foreach($this->choices as $v => $c) {
      
      			if (is_array($c)) {
      
      				$fields[] = "$tab\t".'<optgroup label="'.htmlspecialchars($v).'">';
      				foreach($c as $vv => $cc) {
      
      					$selected = '';
      					if ($value == $vv) { $selected = ' selected="selected"';  }
      					$fields[] = "$tab\t\t".'<option value="'.htmlspecialchars($vv).'"'.$selected.'> '.$cc.'</option>';
      				}
      				$fields[] = "$tab\t".'</optgroup>';
      
      			} else {
      				$selected = '';
      				if ($value == $v) { $selected = ' selected="selected"';  }
      				$fields[] = "$tab\t".'<option value="'.htmlspecialchars($v).'"'.$selected.'> '.$c.'</option>';
      			}
      		}
      
      		$field = '<select'.$id.$this->attrs.'>'."\n".implode("\n", $fields)."\n$tab</select>";
      		return $tab.sprintf("%2\$s%1\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Checkbox extends Form_Input {
      
      	public function __construct($name, $form) {
      
      		parent::__construct($name, $form);
      		$this->attrs['type'] = 'checkbox';
      	}
      
      	protected function _init() {
      
      		if (!isset(self::$error_list['incorrect_value'])) {
      
      			self::$error_list['incorrect_value'] = "La valeur fournie est interdite.";
      		}
      	}
      
      	public function is_valid($value) {
      
      		if (parent::is_valid($value)) {
      
      			if ($this->required && !empty($this->value) && $value != $this->value) {
      
      				$this->_error('incorrect_value');
      				return false;
      			}
      			return true;
      		}
      		return false;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';
                  if (!empty($this->label['text'])) {// nouvelle vérification de la présence d'un label
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
                      list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
                      $label = "\n$tab".'<label'.$for.' class="'.$class.'">'.$this->label['text'].'</label>';
      		}
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      
      		$value = (!empty($this->value)) ? ' value="'.htmlspecialchars($this->value).'"' : '';
      		$checked = ($this->value == $this->form->get_bounded_data($this->attrs['name'])) ? ' checked="checked"' : '';
      
      		$field = '<input'.$id.$this->attrs.$value.$checked.' />';
      		return $tab.sprintf("%1\$s%2\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class Form_Textarea extends Form_Field {
      
      	public function cols($value) {
      
      		if (ctype_digit((string)$value) && $value > 0) { $this->attrs['cols'] = $value; }
      		else { unset($this->attrs['cols']); }
      		return $this;
      	}
      
      	public function get_cleaned_value($value) {
      
      		return preg_replace('`[\x00\x08-\x0b\x0c\x0e\x19]`i', '', $value);
      	}
      
      	public function rows($value) {
      
      		if (ctype_digit((string)$value) && $value > 0) { $this->attrs['rows'] = $value; }
      		else { unset($this->attrs['rows']); }
      		return $this;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		$this->_generate_class();
      
      		$id = '';
      		$label = '';		
                  if (!empty($this->label['text'])) {// nouvelle vérification de la présence d'un label
                      
                      if(!empty($this->label['className'])) {
                          $class = "";
                          foreach ($this->label['className'] as $value) {
                              $class .= $value.' ';
                          }
                      }
                      list($for, $id) = self::_generate_for_id($this->form->auto_id(), $this->attrs['name']);
                      $label = '<label'.$for.' class="'.$class.'">'.$this->label['text'].$this->form->label_suffix().'</label>'."\n$tab";
      		}
      		$errors = $this->error_messages->__toString($tab);
      		if (!empty($errors)) { $errors = "\n".$errors; }
      		$value = $this->form->get_bounded_data($this->attrs['name']);
      		$value = (!empty($value)) ? htmlspecialchars($value) : htmlspecialchars($this->value);
      
      		$field = '<textarea'.$id.$this->attrs.'>'.$value.'</textarea>';
      		return $tab.sprintf("%2\$s%1\$s%3\$s", $field, $label, $errors);
      	}
      }
      
      // ---------------------------------------------------------------------------
      class ListArray implements Iterator, ArrayAccess {
      
      	protected $array = array();
      	private $valid = false;
      
      	function __construct(Array $array = array()) {
      		$this->array = $array;
      	}
      
      	/* Iterator */
      	function rewind()  { $this->valid = (FALSE !== reset($this->array)); }
      	function current() { return current($this->array);      }
      	function key()     { return key($this->array);  }
      	function next()    { $this->valid = (FALSE !== next($this->array));  }
      	function valid()   { return $this->valid;  }
      
      	/* ArrayAccess */
      	public function offsetExists($offset) {
      		return isset($this->array[$offset]);
      	}
      	public function offsetGet($offset) {
      		return $this->array[$offset];
      	}
      	public function offsetSet($offset, $value) {
      		return $this->array[$offset] = $value;
      	}
      	public function offsetUnset($offset) {
      		unset($this->array[$offset]);
      	}
      }
      
      
      // ---------------------------------------------------------------------------
      class ErrorList extends ListArray {
      
      	public function as_array() {
      
      		return $this->array;
      	}
      
      	public function __toString() {
      
      		$tab = func_num_args() > 0 ? func_get_arg(0) : '';
      		
      		if (!empty($this->array)) {
      
      			return sprintf($tab."<ul>\n\t$tab<li>%s</li>\n$tab</ul>", implode("</li>\n\t$tab<li>", $this->array));
      		}
      		return '';
      	}
      }
      
      // ---------------------------------------------------------------------------
      class AttributeList extends ListArray {
      
      	public function __toString() {
      
      		$o = '';
      		if (!empty($this->array)) {
      
      			foreach($this->array as $a=>$v) {
      
      				$o .= sprintf(' %s="%s"', $a, htmlspecialchars($v));
      			}
      		}
      		return $o;
      	}
      }
      
      // ---------------------------------------------------------------------------
      
      
      /**
        * Parse a time/date generated with strftime().
        *
        * This function is the same as the original one defined by PHP (Linux/Unix only),
        *  but now you can use it on Windows too.
        *  Limitation : Only this format can be parsed %S, %M, %H, %d, %m, %Y
        *
        * @author Lionel SAURON
        * @version 1.0
        * @public
        *
        * @param $sDate(string)    The string to parse (e.g. returned from strftime()).
        * @param $sFormat(string)  The format used in date  (e.g. the same as used in strftime()).
        * @return (array)  Returns an array with the <code>$sDate</code> parsed, or <code>false</code> on error.
        */
      if(function_exists("strptime") == false) {
      
      	function strptime($sDate, $sFormat) {
      		$aResult = array (
      			'tm_sec'   => 0,
      			'tm_min'   => 0,
      			'tm_hour'  => 0,
      			'tm_mday'  => 1,
      			'tm_mon'   => 0,
      			'tm_year'  => 0,
      			'tm_wday'  => 0,
      			'tm_yday'  => 0,
      			'unparsed' => $sDate,
      		);
      
      		while(!empty($sFormat)) {
      		// ===== Search a %x element, Check the static string before the %x =====
      
      			$nIdxFound = strpos($sFormat, '%');
      
      			if($nIdxFound === false)
      			{
      				// There is no more format. Check the last static string.
      				$aResult['unparsed'] = ($sFormat == $sDate) ? "" : $sDate;
      				break;
      			}
      			$sFormatBefore = substr($sFormat, 0, $nIdxFound);
      			$sDateBefore   = substr($sDate,   0, $nIdxFound);
      			if($sFormatBefore != $sDateBefore) break;
      
      			// ===== Read the value of the %x found =====
      			$sFormat = substr($sFormat, $nIdxFound);
      			$sDate   = substr($sDate,   $nIdxFound);
      			$aResult['unparsed'] = $sDate;
      			$sFormatCurrent = substr($sFormat, 0, 2);
      			$sFormatAfter   = substr($sFormat, 2);
      			$nValue = -1;
      			$sDateAfter = "";
      
      			switch($sFormatCurrent) {
      
      				case '%S': // Seconds after the minute (0-59)
      					sscanf($sDate, "%2d%[^\\n]", $nValue, $sDateAfter);
      					if(($nValue < 0) || ($nValue > 59)) return false;
      					$aResult['tm_sec']  = $nValue;
      				break;
      				// ----------
      
      				case '%M': // Minutes after the hour (0-59)
      					sscanf($sDate, "%2d%[^\\n]", $nValue, $sDateAfter);
      					if(($nValue < 0) || ($nValue > 59)) return false;
      					$aResult['tm_min']  = $nValue;
      				break;
      				// ----------
      
      				case '%H': // Hour since midnight (0-23)
      					sscanf($sDate, "%2d%[^\\n]", $nValue, $sDateAfter);
      					if(($nValue < 0) || ($nValue > 23)) return false;
      					$aResult['tm_hour']  = $nValue;
      				break;
      
      				// ----------
      				case '%d': // Day of the month (1-31)
      					sscanf($sDate, "%2d%[^\\n]", $nValue, $sDateAfter);
      					if(($nValue < 1) || ($nValue > 31)) return false;
      					$aResult['tm_mday']  = $nValue;
      				break;
      
      				// ----------
      				case '%m': // Months since January (0-11)
      					sscanf($sDate, "%2d%[^\\n]", $nValue, $sDateAfter);
      					if(($nValue < 1) || ($nValue > 12)) return false;
      					$aResult['tm_mon']  = ($nValue - 1);
      				break;
      
      				// ----------
      				case '%Y': // Years since 1900
      					sscanf($sDate, "%4d%[^\\n]", $nValue, $sDateAfter);
      					if($nValue < 1900) return false;
      					$aResult['tm_year']  = ($nValue - 1900);
      				break;
      
      				// ----------
      				default: break 2; // Break Switch and while
      			}
      			// ===== Next please =====
      			$sFormat = $sFormatAfter;
      			$sDate   = $sDateAfter;
      			$aResult['unparsed'] = $sDate;
      		}
      		// END while($sFormat != "")
      
      		// ===== Create the other value of the result array =====
      		$nParsedDateTimestamp = mktime($aResult['tm_hour'], $aResult['tm_min'], $aResult['tm_sec'], $aResult['tm_mon'] + 1, $aResult['tm_mday'], $aResult['tm_year']+1900-28*floor((($aResult['tm_year']-100)/28)));
      
      		// Before PHP 5.1 return -1 when error
      		if(($nParsedDateTimestamp === false) || ($nParsedDateTimestamp === -1))
      			return false;
      
      		$aResult['tm_wday'] = strftime("%w", $nParsedDateTimestamp); // Days since Sunday (0-6)
      		$aResult['tm_yday'] = (strftime("%j", $nParsedDateTimestamp) - 1); // Days since January 1 (0-365)
      
      		return $aResult;
      	}
      	// END of function
      }
      // END if(function_exists("strptime") == false)
      
      // end of file */
      
      ?>

      Bonne journée à tous !

      • Partager sur Facebook
      • Partager sur Twitter
        6 août 2013 à 8:21:28

        pourquoi les erreurs sont mises en static? ca me parait illogique?

        • Partager sur Facebook
        • Partager sur Twitter
          3 octobre 2013 à 16:05:38

          Bonjour à tous et merci par avance à ceux d'entre vous qui prendront le temps de me répondre.

          Je suis entrain de faire ce tuto et bloque un peu dans la création de l'espace membres.

          J'ai crée presque tout mes fichiers il y a juste le contrôleur de l'inscription ou je ne vois pas de nom de fichier donné et ne vois pas l'endroit ou celui-ci est appelé. si je ne me trompe pas ça devrait être dans l'action du submit ?? mais du coup je vois pas la ligne de code correspondante ....

          Pouvez vous m'éclairer ?

          • Partager sur Facebook
          • Partager sur Twitter
            7 novembre 2013 à 14:14:05

            Bonjour,

            J'utilise votre tutoriel pour me familiariser avec le modèle MVC ; tout d'abord je vous remercie pour votre travail.

            Je rencontre un petit problème dans la mise à jour de l'avatar (fichier modules/membres/inscription.php)

            En effet, pathinfo($avatar->get_filename(), PATHINFO_EXTENSION) est vide alors qu'il devrait être égal à png, jpg ou gif

            Je ne comprends pas pourquoi.

            J'ai temporairement résolu le souci en ajoutant, dans la fonction resize_to de la classe image, les lignes suivantes :

                    switch($this->info[2]) {
                        case IMAGETYPE_PNG: $ext = "png"; break;
                        case IMAGETYPE_JPEG: $ext = "jpg"; break;
                        case IMAGETYPE_GIF: $ext = "gif"; break;
                        default : $ext="";
                    }

            et à la fin de cette fonction, avant return $this; le texte $this->ext = $ext;

            Dans inscription, j'ai remplacé pathinfo($avatar->get_filename(), PATHINFO_EXTENSION) par $avatar->ext

            Avec ces modifs, tout fonctionne mais j'aimerais savoir pourquoi la solution initiale est inopérante.

            Merci d'avance pour votre aide.

            GeF

            • Partager sur Facebook
            • Partager sur Twitter
            Gerard FONTAINE
              17 novembre 2013 à 3:39:27

              Bonjour,

              Je vous remercier d'abord pour ce site et ce toto,

              Je viens de comprendre comment faire un site avec MVC et PHP5 et après ma lecture de toutes les parties "votre-site-php-presque-complet-architecture-mvc-et-bonnes-pratiques" j'ai quelques problèmes  :

              1) Où je vais mettre  le code ci-dessous  ( dans connexion.php ou deconnexion.php )

              2)Comment je peux créer les pages exemple ( contact, servies )

              3)Comment créer et ajouter les modules  "slider"(JavaScript et php) et "newsletter" seulement dans la page d’accueil du site

              **************Merci pour votre aide c'est urgent *************************

                 <?php

              // Vérifications pour la connexion automatique

              // On a besoin du modèle des membres
              include CHEMIN_MODELE.'membres.php';

              // Le mec n'est pas connecté mais les cookies sont là, on y va !
              if (!utilisateur_est_connecte() && !empty($_COOKIE['id']) && !empty($_COOKIE['connexion_auto']))
              {
                  $infos_utilisateur = lire_infos_utilisateur($_COOKIE['id']);
                 
                  if (false !== $infos_utilisateur)
                  {
                      $navigateur = (!empty($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : '';
                      $hash = sha1('aaa'.$infos_utilisateur['nom_utilisateur'].'bbb'.$infos_utilisateur['mot_de_passe'].'ccc'.$navigateur.'ddd');
                     
                      if ($_COOKIE['connexion_auto'] == $hash)
                      {
                          // On enregistre les informations dans la session
                          $_SESSION['id']     = $_COOKIE['id'];
                          $_SESSION['pseudo'] = $infos_utilisateur['nom_utilisateur'];
                          $_SESSION['avatar'] = $infos_utilisateur['avatar'];
                          $_SESSION['email']  = $infos_utilisateur['adresse_email'];
                      }
                  }
              }

              • Partager sur Facebook
              • Partager sur Twitter
                3 janvier 2014 à 10:18:05

                Bonjour !

                Merci pour ce magnifique tuto Savageman.

                J'ai pas encore tout saisi mais j'y travaille :)

                Par contre je galère pour savoir dans quel fichier coller les bout de codes donnés en exemple.

                Et lorsque je pense savoir il faut encore supprimer des choses dans le code précédemment ajouté :S

                Du coup je me demandai s'il existait une archive du projet pour ne perdre du temps sur les copier-coller et vraiment me concentré sur le fonctionnement.

                EDIT :

                En fait mon problème est pour l'instant de savoir ou mettre cette partie de code :

                <?php
                // Tire de la documentation PHP sur <http://fr.php.net/uniqid>
                $hash_validation = md5(uniqid(rand(), true));
                
                // Tentative d'ajout du membre dans la base de donnees
                list($nom_utilisateur, $mot_de_passe, $adresse_email, $avatar) =
                	$form_inscription->get_cleaned_data('nom_utilisateur', 'mdp', 'adresse_email', 'avatar');
                
                // On veut utiliser le modele de l'inscription (~/modeles/inscription.php)
                include CHEMIN_MODELE.'inscription.php';
                
                // ajouter_membre_dans_bdd() est défini dans ~/modeles/inscription.php
                $id_utilisateur = ajouter_membre_dans_bdd($nom_utilisateur, sha1($mot_de_passe), $adresse_email, $hash_validation);
                
                // Si la base de données a bien voulu ajouter l'utliisateur (pas de doublons)
                if (ctype_digit($id_utilisateur)) {
                ...
                }



                Dans le contrôleur inscription.php ? à la suite de ce qui s'y trouve déjà ?

                Merci à toute bonne volonté.

                ++ BobaL

                -
                Edité par BobaL 3 janvier 2014 à 15:34:35

                • Partager sur Facebook
                • Partager sur Twitter
                  27 février 2014 à 14:25:13

                  Bonjour à tous!

                  Je souhaite tout d'abord remercier Savageman pour ce tuto d'une grande qualité, mais qui manque cependant de clareté dans ses instructions, et de sa lib Form.php.

                  Après une journée entière à lire le tuto et à mettre en place un site sans aucun bug, ouf!, je cherche à l'améliorer. Tout d'abord, j'aimerai savoir s'il est possible que par défaut une checkbox soit décochée? Car toute checkbox créée est cochée par défaut.

                  A+ !

                  -
                  Edité par william78 27 février 2014 à 14:41:23

                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 mai 2014 à 10:47:40

                    ESt ce qu'il n y a pas les fichiers sources car le tuto ne veutpas marche malgre que j'ai mis le mem code
                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 mai 2014 à 23:28:42

                      Bonjour à Tous!

                      Pour commencer, je remercie Savageman pour ce merveilleux tutoriel.

                      J'ai fait le TP de la 2eme partie du cours. Il s'avère que j'ai 3 petits soucis:

                      • Le 1er: Je ne sais pas dans quel fichier mettre ce code (J'ai du mal à suivre...).
                      <?php
                      
                      // Vérifications pour la connexion automatique
                      
                      // On a besoin du modèle des membres
                      include CHEMIN_MODELE.'membres.php';
                      
                      // Le mec n'est pas connecté mais les cookies sont là, on y va !
                      if (!utilisateur_est_connecte() && !empty($_COOKIE['id']) && !empty($_COOKIE['connexion_auto']))
                      {
                      	$infos_utilisateur = lire_infos_utilisateur($_COOKIE['id']);
                      	
                      	if (false !== $infos_utilisateur)
                      	{
                      		$navigateur = (!empty($_SERVER['HTTP_USER_AGENT'])) ? $_SERVER['HTTP_USER_AGENT'] : '';
                      		$hash = sha1('aaa'.$infos_utilisateur['nom_utilisateur'].'bbb'.$infos_utilisateur['mot_de_passe'].'ccc'.$navigateur.'ddd');
                      		
                      		if ($_COOKIE['connexion_auto'] == $hash)
                      		{
                      			// On enregistre les informations dans la session
                      			$_SESSION['id']     = $_COOKIE['id'];
                      			$_SESSION['pseudo'] = $infos_utilisateur['nom_utilisateur'];
                      			$_SESSION['avatar'] = $infos_utilisateur['avatar'];
                      			$_SESSION['email']  = $infos_utilisateur['adresse_email'];
                      		}
                      	}
                      }

                      Ce code est présent dans le paragraphe: La connexion automatique (2eme Partie du cours, chapitre1).

                      • Le 2eme: L'action afficher_profil (Source Files/modules/membres/afficher_profil.php) me pose problème. Apparemment la variable $_Get['id'] n'est pas reconnue (bien que je sois connectée). :(

                      J'obtiens ce message:

                      Erreur d'affichage du profil
                      
                      Paramètre id est manquant ou invalide
                      • Le 3eme: la fonction initial(); n'est pas définie dans la class From.ph 

                      J'obtiens ce message:

                      Fatal error: Call to undefined method Form_Submit::initial() in /home/surla910/public_html/Source Files/modules/membres/modifier_profil.php on line 33

                      Je constate que le sujet n'est plus d'actualité. Mais, s'il y a des gens qui veulent bien m'aider, en tout cas n'hésitez pas. :)

                      Merci d'avance!

                      Cordialement,

                      -
                      Edité par BM_Chancie 28 mai 2014 à 23:32:35

                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 mai 2014 à 13:40:22

                        Super tuto! La seul chose négative est le manque de clarté pour l'emplacement des bouts de codes! J'ai passé des heures à essayer de deviner quel bout se mettait où! Mais bon au bout d'un moment on comprend comment sa marche :) Si vous voulez je peux poster une archive.

                        Petite faute dans l'expression régulière pour le traitement des doublons: je ne comprend pas pourquoi il y a /d à la fin alors que l'erreur n'est pas un nombre?!! Sans doute était-ce pour une ancienne version de sql quand ce tuto à été écris mais maintenant elle n'est plus valide. L'option i aussi ne sert pas à grand chose. Voici l'expression modifiée: #Duplicate entry '(.+)' for key #s

                        @Chancie

                        Alors pour le 1: c'est à la suite dans le controlleur connexion.php :)

                        le 2: soit plus précise ;)

                        le 3: je pense que c'est une erreur de la part de l'auteur, met value comme d'habitude

                        -
                        Edité par gargan 31 mai 2014 à 14:26:29

                        • Partager sur Facebook
                        • Partager sur Twitter
                          1 juin 2014 à 1:06:45

                          Salut Gargan!

                          Hors mis mon 1er souci, pour le reste j'ai pu les régler. ça marche à merveille maintenant.

                          Je vous remercie. :ange::)

                          • Partager sur Facebook
                          • Partager sur Twitter
                            5 juin 2014 à 18:55:36

                            Voici le zip avec tout le code source plus quelques petites améliorations!

                            -
                            Edité par gargan 6 juin 2014 à 2:48:11

                            • Partager sur Facebook
                            • Partager sur Twitter
                              8 juin 2014 à 13:51:20

                              Merci pour le code source, c'est gentil. :)

                              De mon côté aussi, j'ai corrigé et amélioré le tutoriel précédent, en ajoutant quelques fonctionnalités... (sans pourtant changer la classe  Form, même si j'avoue qu'elle n'est pas complète).

                              -
                              Edité par BM_Chancie 8 juin 2014 à 14:01:42

                              • Partager sur Facebook
                              • Partager sur Twitter
                                18 juin 2014 à 14:39:30

                                Bonjour,

                                J'ai créé un espace membre en suivant le tuto (fonctionne nickel) mais quand je veux rajouter un élément au formulaire de la classe form, j'ai un soucis :

                                Mon élément (dans Modèles)

                                $form_inscription->add('Radio', 'genre')
                                                  ->choices(array(  'male' => 'Vous êtes un Homme',  'female' => 'Vous êtes une Femme'
                                ));

                                *************************************************************************

                                Le controleur inscription :

                                list($nom_utilisateur, $mot_de_passe, $adresse_email, $avatar, $genre) =
                                    $form_inscription->get_cleaned_data('nom_utilisateur', 'mdp', 'adresse_email', 'avatar', 'genre');

                                // On veut utiliser le modele de l'inscription (~/modeles/inscription.php)
                                include CHEMIN_MODELES.'ajouter_membres.php';

                                // ajouter_membre_dans_bdd() est défini dans ~/modeles/inscription.php
                                $id_utilisateur = ajouter_membre_dans_bdd($nom_utilisateur, sha1($mot_de_passe), $adresse_email, $hash_validation, $genre);
                                *****************************************************************************************************

                                Le modèle Membres :

                                function lire_infos_utilisateur($id_utilisateur) {

                                    $pdo = PDO2::getInstance();

                                    $requete = $pdo->prepare("SELECT nom_utilisateur, mot_de_passe, adresse_email, avatar, date_inscription, hash_validation, genre
                                        FROM Membres
                                        WHERE
                                        id = :id_utilisateur");

                                    $requete->bindValue(':id_utilisateur', $id_utilisateur);
                                    $requete->execute();
                                   
                                    if ($result = $requete->fetch(PDO::FETCH_ASSOC)) {
                                   
                                        $requete->closeCursor();
                                        return $result;
                                    }
                                    return false;
                                }

                                ****************************************************************************************************

                                Dans le controleur de connection j'enregistre les valeurs comme ceci (à titre informatif car l'erreur est à l'inscription donc avant)

                                $_SESSION['genre']  = $infos_utilisateur['genre'];

                                ******************************************************************************************************

                                Mon modèle ajouter_membres :

                                function ajouter_membre_dans_bdd($nom_utilisateur, $mdp, $adresse_email, $hash_validation, $genre) {

                                    $pdo = PDO2::getInstance();

                                    $requete = $pdo->prepare("INSERT INTO Membres SET
                                        nom_utilisateur = :nom_utilisateur,
                                        mot_de_passe = :mot_de_passe,
                                        adresse_email = :adresse_email,
                                        hash_validation = :hash_validation,
                                        date_inscription = NOW(),
                                        genre = :genre");

                                    $requete->bindValue(':nom_utilisateur', $nom_utilisateur);
                                    $requete->bindValue(':mot_de_passe',    $mdp);
                                    $requete->bindValue(':adresse_email',   $adresse_email);
                                    $requete->bindValue(':hash_validation', $hash_validation);
                                    $requete->bindValue(':genre', $genre);

                                    if ($requete->execute()) {
                                   
                                        return $pdo->lastInsertId();
                                    }
                                    return $requete->errorInfo();
                                }

                                *******************************************************************************************************

                                L'erreur :

                                . La valeur fournie est interdite. (Sur le radio boutton)

                                Une idée ?

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  18 juin 2014 à 14:48:56

                                  Poste ton code avec l'outil de coloration pour le rendre lisible s'il te plait.

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    18 juin 2014 à 14:55:26

                                    Bonjour,
                                    
                                    J'ai créé un espace membre en suivant le tuto (fonctionne nickel) mais quand je veux rajouter un élément au formulaire de la classe form, j'ai un soucis :
                                    
                                    Mon élément (dans Modèles)
                                    
                                    $form_inscription->add('Radio', 'genre')
                                                      ->choices(array(  'male' => 'Vous êtes un Homme',  'female' => 'Vous êtes une Femme'
                                    ));
                                    
                                    *************************************************************************
                                    
                                    Le controleur inscription :
                                    
                                    list($nom_utilisateur, $mot_de_passe, $adresse_email, $avatar, $genre) =
                                        $form_inscription->get_cleaned_data('nom_utilisateur', 'mdp', 'adresse_email', 'avatar', 'genre');
                                    
                                    // On veut utiliser le modele de l'inscription (~/modeles/inscription.php)
                                    include CHEMIN_MODELES.'ajouter_membres.php';
                                    
                                    // ajouter_membre_dans_bdd() est défini dans ~/modeles/inscription.php
                                    $id_utilisateur = ajouter_membre_dans_bdd($nom_utilisateur, sha1($mot_de_passe), $adresse_email, $hash_validation, $genre);
                                    *****************************************************************************************************
                                    
                                    Le modèle Membres :
                                    
                                    function lire_infos_utilisateur($id_utilisateur) {
                                    
                                        $pdo = PDO2::getInstance();
                                    
                                        $requete = $pdo->prepare("SELECT nom_utilisateur, mot_de_passe, adresse_email, avatar, date_inscription, hash_validation, genre
                                            FROM Membres
                                            WHERE
                                            id = :id_utilisateur");
                                    
                                        $requete->bindValue(':id_utilisateur', $id_utilisateur);
                                        $requete->execute();
                                       
                                        if ($result = $requete->fetch(PDO::FETCH_ASSOC)) {
                                       
                                            $requete->closeCursor();
                                            return $result;
                                        }
                                        return false;
                                    }
                                    
                                    ****************************************************************************************************
                                    
                                    Dans le controleur de connection j'enregistre les valeurs comme ceci (à titre informatif car l'erreur est à l'inscription donc avant)
                                    
                                    $_SESSION['genre']  = $infos_utilisateur['genre'];
                                    
                                    ******************************************************************************************************
                                    
                                    Mon modèle ajouter_membres :
                                    
                                    function ajouter_membre_dans_bdd($nom_utilisateur, $mdp, $adresse_email, $hash_validation, $genre) {
                                    
                                        $pdo = PDO2::getInstance();
                                    
                                        $requete = $pdo->prepare("INSERT INTO Membres SET
                                            nom_utilisateur = :nom_utilisateur,
                                            mot_de_passe = :mot_de_passe,
                                            adresse_email = :adresse_email,
                                            hash_validation = :hash_validation,
                                            date_inscription = NOW(),
                                            genre = :genre");
                                    
                                        $requete->bindValue(':nom_utilisateur', $nom_utilisateur);
                                        $requete->bindValue(':mot_de_passe',    $mdp);
                                        $requete->bindValue(':adresse_email',   $adresse_email);
                                        $requete->bindValue(':hash_validation', $hash_validation);
                                        $requete->bindValue(':genre', $genre);
                                    
                                        if ($requete->execute()) {
                                       
                                            return $pdo->lastInsertId();
                                        }
                                        return $requete->errorInfo();
                                    }
                                    
                                    *******************************************************************************************************
                                    
                                    L'erreur :
                                    
                                    . La valeur fournie est interdite. (Sur le radio boutton)
                                    
                                    Une idée ?
                                    
                                    Voila j'ai essayé la coloration (option du site) Mais c'est la première fois (j'espère que c'est bon)

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      18 juin 2014 à 16:27:00

                                      Résolu : (Mais bizarre)

                                      Dans ma BDD le format de la colonne "genre" est un enum : m ou f .

                                      et pour faire fonctionner le tout j'ai du mettre 'm' => 'm', 'f' => 'f' (dans mon radio boutton) INCOMPRÉHENSIBLE ET TRÈS MOCHE pour un site

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        19 juin 2014 à 16:01:31

                                        c'est plutôt l'énum qui est très moche en fait mais soit.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          10 septembre 2014 à 17:30:24

                                          Salut à tous,

                                          je suis coincé dans la dernière partie du tuto, à savoir la modification du profil.

                                          Quand j'affiche mes deux formulaires, voici le message d'erreur que j'obtiens: 

                                          Warning: Invalid argument supplied for foreach() in /libs/form.php on line 258

                                          Je n'ai eu aucun soucis jusque là avec la bibliothèque form et j'ai repris le code fournis par Savageman pour afficher mes deux formulaires. Je ne comprend pas trop pourquoi j'ai ce message maintenant. 
                                          Merci de votre aide. 

                                          -
                                          Edité par dionysos73 11 septembre 2014 à 10:32:14

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            10 septembre 2014 à 17:46:08

                                            Merci artagis,

                                            comme je l'ai dis, j'ai repris le code fournis par Savageman dans le tuto... A moins que j'oublie quelque chose au passage?

                                            <?php
                                            
                                            // Vérification des droits d'accès de la page
                                            if (!utilisateur_est_connecte()) {
                                            
                                            	// On affiche la page d'erreur comme quoi l'utilisateur doit être connecté pour voir la page
                                            	include CHEMIN_VUE_GLOBALE.'erreur_non_connecte.php';
                                            	
                                            } else {
                                            	
                                            	// Ne pas oublier d'inclure la librairie Form
                                            	include CHEMIN_LIB.'form.php';
                                            	
                                            	// "form_modif_infos" est l'ID unique du formulaire
                                            	$form_modif_infos = new Form("form_modif_infos");
                                            	
                                            	$form_modif_infos->add('Email', 'adresse_email')
                                                                     ->label("Votre adresse email")
                                                                     ->Required(false)
                                                                     ->value($_SESSION['email']);
                                            	
                                            	$form_modif_infos->add('Checkbox', 'suppr_avatar')
                                                                     ->label("Je veux supprimer mon avatar")
                                                                     ->Required(false);
                                            	
                                            	$form_modif_infos->add('File', 'avatar')
                                                                     ->filter_extensions('jpg', 'png', 'gif')
                                                                     ->max_size(8192) // 8 Kb
                                                                     ->label("Votre avatar (facultatif)")
                                                                     ->Required(false);
                                            	
                                            	$form_modif_infos->add('Submit', 'submit')
                                                                     ->initial("Modifier ces informations !");
                                            	
                                            	// "form_modif_mdp" est l'ID unique du formulaire
                                            	$form_modif_mdp = new Form("form_modif_mdp");
                                            	
                                            	$form_modif_mdp->add('Password', 'mdp_ancien')
                                                                   ->label("Votre ancien mot de passe");
                                            	
                                            	$form_modif_mdp->add('Password', 'mdp')
                                                                   ->label("Votre nouveau mot de passe");
                                            	
                                            	$form_modif_mdp->add('Password', 'mdp_verif')
                                                                   ->label("Votre nouveau mot de passe (vérification)");
                                            	
                                            	$form_modif_mdp->add('Submit', 'submit')
                                                                   ->initial("Modifier mon mot de passe !");
                                            	
                                            	// Création des tableaux des erreurs (un par formulaire)
                                            	$erreurs_form_modif_infos = array();
                                            	$erreurs_form_modif_mdp   = array();
                                            	
                                            	// et d'un tableau des messages de confirmation
                                            	$msg_confirm = array();
                                            	
                                            	// Validation des champs suivant les règles en utilisant les données du tableau $_POST
                                            	if ($form_modif_infos->is_valid($_POST)) {
                                            	
                                            		list($adresse_email, $suppr_avatar, $avatar) = $form_modif_infos->get_cleaned_data('adresse_email', 'suppr_avatar', 'avatar');
                                            	
                                            		// On veut utiliser le modèle de l'inscription(~/modules/membres.php)
                                            		include CHEMIN_MODELE.'membres.php';
                                            	
                                            		// Si l'utilisateur veut modifier son adresse e-mail
                                            		if (!empty($adresse_email)) {
                                            	
                                            			$test = maj_adresse_email_membre($_SESSION['id'], $adresse_email);
                                            	
                                            			if (true === $test) {
                                            	
                                            				// Ça a marché, trop cool !
                                            				$msg_confirm[] = "Adresse e-mail mise à jour avec succès !";
                                            	
                                            			// Gestion des doublons
                                            			} else {
                                            	
                                            				// Changement de nom de variable (plus lisible)
                                            				$erreur =& $test;
                                            	
                                            				// On vérifie que l'erreur concerne bien un doublon
                                            				if (23000 == $erreur[0]) { // Le code d'erreur 23000 signifie "doublon" dans le standard ANSI SQL
                                            	
                                            					preg_match("`Duplicate entry '(.+)' for key \d+`is", $erreur[2], $valeur_probleme);
                                            					$valeur_probleme = $valeur_probleme[1];
                                            	
                                            					if ($adresse_email == $valeur_probleme) {
                                            	
                                            						$erreurs_form_modif_infos[] = "Cette adresse e-mail est déjà utilisée.";
                                            	
                                            					} else {
                                            	
                                            						$erreurs_form_modif_infos[] = "Erreur ajout SQL : doublon non identifié présent dans la base de données.";
                                            					}
                                            	
                                            				} else {
                                            	
                                            					$erreurs_form_modif_infos[] = sprintf("Erreur ajout SQL : cas non traité (SQLSTATE = %d).", $erreur[0]);
                                            				}
                                            	
                                            			}
                                            		}
                                            	
                                            		// Si l'utilisateur veut supprimer son avatar...
                                            		if (!empty($suppr_avatar)) {
                                            	
                                            			maj_avatar_membre($_SESSION['id'], '');
                                            			$_SESSION['avatar'] = '';
                                            	
                                            			$msg_confirm[] = "Avatar supprimé avec succès !";
                                            	
                                            		// ... ou le modifier !
                                            		} else if (!empty($avatar)) {
                                            	
                                            			// On souhaite utiliser la librairie Image
                                            			include CHEMIN_LIB.'image.php';
                                            	
                                            			// Redimensionnement et sauvegarde de l'avatar
                                            			$avatar = new Image($avatar);
                                            			$avatar->resize_to(100, 100); // Image->resize_to($largeur_maxi, $hauteur_maxi)
                                            			$avatar_filename = DOSSIER_AVATAR.$id_utilisateur .'.'.strtlower(pathinfo($avatar->get_filename(), PATHINFO_EXTENSION));
                                            			$avatar->save_as($avatar_filename);
                                            	
                                            			// On veut utiliser le modèle des membres (~/modules/membres.php)
                                            			include CHEMIN_MODELE.'membres.php';
                                            	
                                            			// Mise à jour de l'avatar dans la table
                                            			// maj_avatar_membre() est définit dans ~/modules/membres.php
                                            			maj_avatar_membre($_SESSION['id'] , $avatar_filename);
                                            			$_SESSION['avatar'] = $avatar_filename;
                                            	
                                            			$msg_confirm[] = "Avatar modifié avec succès !";
                                            		}
                                            	
                                            	} else if ($form_modif_mdp->is_valid($_POST)) {
                                            	
                                            		// On vérifie si les 2 mots de passe correspondent
                                            		if ($form_modif_mdp->get_cleaned_data('mdp') != $form_modif_mdp->get_cleaned_data('mdp_verif')) {
                                            	
                                            			$erreurs_form_modif_mdp[] = "Les deux mots de passes entrés sont différents !";
                                            	
                                            		// C'est bon, on peut modifier la valeur dans la BDD
                                            		} else {
                                            	
                                            	
                                            			// On veut utiliser le modèle de l'inscription (~/modules/membres.php)
                                            			include CHEMIN_MODELE.'membres.php';
                                            			maj_mot_de_passe_membre($_SESSION['id'], $mdp);
                                            	
                                            			$msg_confirm[] = "Votre mot de passe a été modifié avec succès !";
                                            		}
                                            	
                                            	}
                                            }
                                            
                                            // Affichage des formulaires de modification du profil
                                            include ('formulaires_modifier_profil.php');
                                            <h2>Modification de votre profil utilisateur</h2>
                                            
                                            <?php
                                            
                                            if (!empty($msg_confirm)) {
                                            
                                            	echo '<ul>'."\n";
                                            
                                            	foreach($msg_confirm as $m) {
                                            
                                            		echo '	<li>'.$m.'</li>'."\n";
                                            	}
                                            
                                            	echo '</ul>';
                                            }
                                            
                                            if (!empty($erreurs_form_modif_infos)) {
                                            
                                            	echo '<ul>'."\n";
                                            
                                            	foreach($erreurs_form_modif_infos as $e) {
                                            
                                            		echo '	<li>'.$e.'</li>'."\n";
                                            	}
                                            
                                            	echo '</ul>';
                                            }
                                            
                                            $form_modif_infos->fieldsets("Modification de l'e-mail et de l'avatar", array('adresse_email', 'suppr_avatar', 'avatar'));
                                            
                                            echo $form_modif_infos;
                                            
                                            if (!empty($erreurs_form_modif_mdp)) {
                                            
                                            	echo '<ul>'."\n";
                                            
                                            	foreach($erreurs_form_modif_mdp as $e) {
                                            
                                            		echo '	<li>'.$e.'</li>'."\n";
                                            	}
                                            
                                            	echo '</ul>';
                                            }
                                            
                                            $form_modif_mdp->fieldsets("Modification du mot de passe", array('mdp_ancien', 'mdp', 'mdp_verif'));
                                            
                                            echo $form_modif_mdp;




                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              11 septembre 2014 à 10:35:59

                                              Bonjour,

                                              Problème résolu: l'argument attendu aux lignes 29 et 45 de la vue formulaires_modifier_profil.php n'est pas fieldsets mais fields...

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                19 septembre 2014 à 17:43:31

                                                salut a tous très bon tuto je voudrais savoir si je veux modifier la classe form pour ajouter une propriété "placeholder" dans les champs de textes j'ai enlever les labels avec le css comment je m y prends pour le faire
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Get rich or die trying
                                                  7 octobre 2014 à 13:50:57

                                                  salut en fait j'ai utilisé la class Form pour créer mes formulaires et j'ai un souci, je n'arrive pas à accéder aux inputs que je veux avec javascript.

                                                  En effet j'ai un input de type Date dans mes formulaires que j'aimerai insérer le date-picker du jquery lors d'un enregistrement et je ne sais pas cmment faire pour accéder à un champ a partir du javascript pour pouvoir inserer le date-picker du jquery dans mes formulaires si quelqu'un pourrait m'aider...

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    20 octobre 2015 à 14:21:21

                                                    "Premièrement, l'affichage du profil est une nouvelle action pour le module membres ! Il faut donc créer une page
                                                    afficher_profil.php dans le dossier ~/modules/membres/. Nous ne l'ajouterons pas dans le menu, l'affichage du profil se fera
                                                    depuis des liens sur d'autres pages du site. Si vous le souhaitez, vous pouvez tout de même ajouter un lien pour que l'utilisateur
                                                    affiche son propre profil (en utilisant $_SESSION['id'] comme attribut GET nommé id dans le lien) dans le menu."

                                                    comment passer en paramètre '$_SESSION' dans le lien'' <li><a href="index.php? module=membres&amp;action=afficher_profil">Afficher mon Profil</a></li>''???

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      20 octobre 2015 à 14:37:41

                                                      j'ai essayé mais ça ne marchait pas... :<
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        27 octobre 2015 à 15:45:14

                                                        Bonjour! Voila cela fait quelque temps que je suis ce tutoriel que je trouve très instructif d’ailleurs mais la je suis bloquer au niveau de l'inscription car j'ai le message d'erreur suivant 

                                                        • Erreur d'ajout SQL : cas non traiter (SQLATE = 42 000)

                                                        Pourriez vous m’éclairer s'il vous plait car je n'arrive pas a trouver la solution !

                                                        Merci d'avance!

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        You need to strive, to be determinate, and believe in yourself
                                                          16 novembre 2015 à 8:38:20

                                                          Bonjour, et grand merci pour ce big tuto. Moi je viens juste de commencer et je trouve cela très bien enrichi vue que je suis débutant. Je vais revenir pour des quesions avec la comminauté. 

                                                          Merci

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          @mic5tera HTML5 CSS3 JS PHP - Web Dev
                                                            14 mars 2016 à 20:44:01

                                                            Salut,

                                                            Merci @Savageman pour cet excellent tutoriel. ^^
                                                            Y a-t-il moyen d'avoir le chemin (ou au moins le nom) des fichiers associés aux codes donnés dans le tutoriel ?
                                                            J'ai du mal à me faire à l'architecture MVC et je ne suis pas tout le temps, et je suis donc souvent bloqué.

                                                            Merci.

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            [TUTO] MVC, bonnes pratiques et site complet !

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown