has_plugin('fr.core.dynamicform')){
			Plugin::need('dynamicform/DynamicForm');
			//le premier argument contient le slug du formulaire contenant toutes les colonnes possibles, le second les colonnes non choisies,la requete, l'alias si nécessaire
			$dynamicFields = DynamicForm::list('fiche-example');
			DynamicForm::query_column_add($dynamicFields,$query,'main');
			//On récupère les types de champs qui possèdent une propriété onLoad afin de l'appliquer si on a un champ dynamique
			$fieldTypes = array();
			foreach($dynamicFields as $field){
				$fieldTypes[$field['slug']] = $field['type'];
				$allowedFields[] = 'dynamicField_'.$field['id'].'.value';
			}
		}
		//Recherche simple
		if(!empty($_['filters']['keyword'])){
			$query .= ' AND main.label LIKE ?';
			$data[] = '%'.$_['filters']['keyword'].'%';
		}
		//Recherche avancée
		if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array_merge($allowedFields,array('main.label','main.phone','main.birth','main.hour','main.firm','main.manager','main.address','main.properties','main.vehicle','main.storyshort','main.story','main.password','main.icon','main.available','main.solvability','main.handicap','main.childs','main.size','main.color','main.salary','main.orientation','main.website','main.mail','main.mobile')),$query,$data);
		//Tri des colonnes
		if(isset($_['sort'])) sort_secure_query($_['sort'],array_merge($allowedFields,array('main.label','main.phone','main.birth','main.hour','main.firm','main.manager','main.address','main.properties','main.vehicle','main.storyshort','main.story','main.password','main.icon','main.available','main.solvability','main.handicap','main.childs','main.size','main.color','main.salary','main.orientation','main.website','main.mail','main.mobile')),$query,$data);
		//Pagination
		//Par défaut pour une recherche, 20 items, pour un export 5000 max
		$itemPerPage = !empty($_['itemPerPage']) ? $_['itemPerPage'] : 20;
		//force le nombre de page max a 50 coté serveur
		$itemPerPage = $itemPerPage>50 ? 50 : $itemPerPage;
		if($_['export'] == 'true') $itemPerPage = 5000;
		$response['pagination'] = ContactExample::paginate($itemPerPage,(!empty($_['page'])?$_['page']:0),$query,$data,'main');
		$contacts = ContactExample::staticQuery($query,$data,true,1);
		
		$vehicleList = Dictionary::slugToArray('example_contact_vehicle',true);
		$handicapList = Dictionary::slugToArray('example_contact_handicap',true);
		$response['rows'] = array();
		//Mise en forme des résultats
		foreach($contacts as $contact){
			$row = $contact->toArray();
			$row['birth-readable'] = complete_date($row['birth']).' à '.date('H:i',$row['birth']); 
			$user = User::byLogin($row['manager']); 
			$row['manager'] = $user->toArray(); 
			$row['manager']['fullname'] = $user->fullname(); 
			$row['manager']['avatar'] = $user->getAvatar(); 
			$row['firm'] = $contact->join('firm')->toArray(); 
			
			$row['vehicle'] = isset($vehicleList[$row['vehicle']]) ? $vehicleList[$row['vehicle']] : new Dictionary(); 
			
			$row['handicaps'] = array();
			foreach(explode(',',$row['handicap']) as $id){
				if(empty($id)) continue;
				$row['handicaps'][] = isset($handicapList[$id]) ? $handicapList[$id] : new Dictionary(); 
			}
			
			
			$row['properties'] = explode(',',$row['properties']); 
			$row['story'] = html_entity_decode($row['story']); 
			$row['solvability'] = ContactExample::solvabilities($row['solvability']); 
			$row['orientation'] = ContactExample::orientations($row['orientation']); 
			$row['cv'] = array();
			foreach (glob(File::dir().'example'.SLASH.'contact'.SLASH.$row['id'].'/cv/*') as $file) {
				$row['cv'][] = array(
					'label' => basename($file),
					'url' => 'action.php?action=example_contact_cv&type=download&path='.base64_encode('example/contact/'.$row['id'].'/cv/'.basename($file)),
				);
			}
			
			
			$row['avatar'] = 'action.php?action=example_contact_avatar&type=download&path='.base64_encode('example/contact/'.$row['id'].'/avatar.*');
			
			if($_['export'] == 'true'){
				$row['created'] = date('d-m-Y',$row['created']);
				$row['updated'] = date('d-m-Y',$row['updated']);
			}
			
			//Gestion des champs dynamiques
			if($myFirm->has_plugin('fr.core.dynamicform'))
				DynamicForm::search_values($row,array(
					'slugs' => $contact->foreign(),
					'types' => $fieldTypes,
					'scope' => 'contact',
				));
			$response['rows'][] = $row;
		}
		
		/* Mode export */
		if($_['export'] == 'true'){
			if(empty($response['rows'])) $response['rows'][] = array('Vide'=>'Aucune données');
			$fieldsMapping = array();
			foreach (ContactExample::fields(false) as $key => $value) 
				$fieldsMapping[$value['label']] = $key;
			$stream = Excel::exportArray($response['rows'],$fieldsMapping ,'Export');
			File::downloadStream($stream,'export-contacts-'.date('d-m-Y').'.xlsx');
			exit();
		}
		
	});
	
	
	//Ajout ou modification d'élément contact
	Action::register('example_contact_save',function(&$response){
		global $_,$myFirm,$myUser;
		User::check_access('example','edit');
		require_once(__DIR__.SLASH.'ContactExample.class.php');
		
		//Check champs dynamiques
		if($myFirm->has_plugin('fr.core.dynamicform')){
			Plugin::need('dynamicform/DynamicForm');
			$dynamicFields = Dynamicform::check_required('fiche-example',array(),$_);
		}
		$item = ContactExample::provide();
		//on garde l'ancien objet a l'instant t pour le log comparatif (voir en fin d'action)
		$oldItem = clone $item;
		$item->label = $_['label'];
		$item->phone = $_['phone'];
		$item->birth = timestamp_date($_['birth']);
		$item->hour = $_['hour'];
		$item->firm = $_['firm'];
		$item->manager = $_['manager'];
		$item->address = $_['address'];
		$item->properties = $_['properties'];
		if(!empty($_['vehicle']) ) $item->vehicle = $_['vehicle'];
		$item->storyshort = $_['storyshort'];
		$item->story = $_['story'];
		$item->password = $_['password'];
		$item->icon = $_['icon'];
		$item->available = $_['available'];
		$item->solvability = $_['solvability'];
		$item->handicap = (isset($_['handicap']) && !empty($_['handicap'])) ? value_encapsulate($_['handicap'], ',') : NULL;
		$item->childs = $_['childs'];
		if(is_numeric($_['size'])) $item->size = $_['size'];
		$item->color = $_['color'];
		$item->salary = $_['salary'];
		if(!empty($_['orientation']))  $item->orientation = $_['orientation'];
		$item->website = $_['website'];
		$item->mail = $_['mail'];
		$item->save();
		//save champs dynamiques
		if($myFirm->has_plugin('fr.core.dynamicform')){
			
			Dynamicform::record('fiche-example',array(
				'scope'=>'contact',
				'uid'=>$item->id,
				'fields' => $dynamicFields
			),$_);
		}
		//Ajout upload Cv
		if(!empty($_['cv']))
			File::save_component('cv', 'example/contact/'.$item->id.'/cv/{{label}}');
		//Ajout upload Avatar
		if(!empty($_['avatar']))
			File::save_component('avatar', 'example/contact/'.$item->id.'/avatar.{{extension}}');
		//Exemple de mise en place de logs comparatif
		History::entityChange('contact',$oldItem,$item);
		//trigger pour utilisation sur le workflow
		if($myFirm->has_plugin('fr.core.workflow')){
			Plugin::need('workflow/WorkflowEvent');
			WorkflowEvent::trigger('example-contact-'.($oldItem->id==0?'create':'update'),array('old'=>$oldItem,'current'=>$item));
		}
		// GESTION ENVOI NOTIFICATION
		Plugin::callHook('emit_notification',array(array(
				'label' => isset($item->id) ? 'Édition d\'un contact' : 'Création d\'un contact',
				'html' => isset($item->id) ? 'Le contact '.$item->label.' a été édité' : 'Création du contact '.$item->label,
				'type' => "notice",
				'meta' => array('link' => ROOT_URL.'/index.php?module=example&page=sheet&id='.$item->id),
				'recipients' => array($myUser->login) // recipients contient login
			)
		));
		$response = $item->toArray();
	});
	
	
	Action::register('contact_wysiwyg_attachments',function(&$response){
		$directory = File::dir().SLASH.'public'.SLASH.'example';
		User::check_access('example','read');
		global $_;
		if(!isset($_FILES['stream'])) throw new Exception("Fichier inexistant");
		if(!in_array($_FILES['stream']['type'], array('image/png','image/jpg','image/jpeg','image/gif','image/bmp','application/pdf'))) throw new Exception("Format du fichier non autorisé :".$_FILES['stream']['type']);
		
		$ext = mb_strtolower(getExt($_['name']));
		//Gère l'upload d'un fichier image collé dans le wysiwyg
		$pathes = File::upload('stream', 'example/public/screens/'.time().'.'.$ext, 1048576, null);
	
		if(preg_match('/^image\//', $_FILES['stream']['type'])){
			$response['html'] = '
';
		}else{
			$response['html'] = ''.$_['name'].'';
		}
		
	});
	//Suppression d'élement contact
	Action::register('example_contact_delete',function(&$response){
		global $myUser,$_,$myFirm;
		User::check_access('example','delete');
		require_once(__DIR__.SLASH.'ContactExample.class.php');
		if(empty($_['id']) || !is_numeric($_['id'])) throw new Exception("Identifiant incorrect");
		ContactExample::deleteById($_['id']);
		//Gestion des champs dynamiques
		if($myFirm->has_plugin('fr.core.dynamicform')){
			Plugin::need('dynamicform/DynamicForm');
			Dynamicform::remove('fiche-example',array(
				'scope'=>'contact',
				'uid'=>$_['id']
			));
		}
	});
	
	
	//ContactExample : Gestion upload Cv
	Action::register('example_contact_cv',function(&$response){
			File::handle_component(array(
				'namespace' => 'example', //stockés dans file/example/*.*
				'access' => 'example', // crud sur example,
				'size' => '1000000000', // taille max
				'storage' => 'example/contact/{{data.id}}/cv/*' //chemin complet vers le fichier stocké
			),$response);
	});//ContactExample : Gestion upload Avatar
	Action::register('example_contact_avatar',function(&$response){
			File::handle_component(array(
				'namespace' => 'example', //stockés dans file/example/*.*
				'access' => 'example', // crud sur example,
				'size' => '1000000000', // taille max
				'limit' => '1', // nb max de fichiers
				'storage' => 'example/contact/{{data.id}}/avatar.*' //chemin complet vers le fichier stocké
			),$response);
	});
		/** QUICKFORM **/
	//Création rapide par quickform
	Action::register('contact_quick_create',function(&$response){
		
			global $myUser,$_;
			User::check_access('example','edit');
			require_once(__DIR__.SLASH.'ContactExample.class.php');
			
			ob_start();
			require_once(__DIR__.SLASH.'page.quick.example.php');
			$response['content'] = ob_get_clean();
		});
	
	/** CARD **/
	//Récupération card d'un contact
	Action::register('example_contact_card',function(&$response){
		
			global $myUser,$myFirm,$_;
			User::check_access('example','read');
			require_once(__DIR__.SLASH.'ContactExample.class.php');
			$contact = ContactExample::provide();
			ob_start();
			require_once(__DIR__.SLASH.'card.example.contact.php');
			$stream = ob_get_clean();
			$response['content'] = $stream;
		});
	Action::register('example_widget_load',function(&$response){
		Plugin::need('dashboard/DashboardWidget');
		User::check_access('example','read');
		$widget = DashboardWidget::current();
		$widget->title = 'Widget Example';
		ob_start();
		//Décommenter après avoir créé widget.php
		//require_once(__DIR__.SLASH.'widget.php');
		//$widget->content = ob_get_clean();
		$widget->content = 'Widget non développé';
		echo json_encode($widget);
	});
	
	//Sauvegarde des configurations de Example
	Action::register('example_setting_save',function(&$response){
		global $_,$conf;
		User::check_access('example','configure');
		//Si input file "multiple", possibilité de normaliser le
		//tableau $_FILES récupéré avec la fonction => normalize_php_files();
		foreach(Configuration::setting('example') as $key=>$value){
			if(!is_array($value)) continue;
			$allowed[] = $key;
		}
		foreach ($_['fields'] as $key => $value) {
			if(in_array($key, $allowed))
				$conf->put($key,$value);
		}
	});
	
?>