français

a/X développement web 2

Ce site est construit sur le modèle MVC.

Il pourrait n'être qu'un ensemble de page statique HTML, mais il est plus rapide, plus simple à faire évoluer et beaucoup plus ouvert en terme de possibilité de partir dès le début d'un tel modèle.

Dans ce cas il est relativement simplifié par rapport à une grosse application, qui utiliserait le module MVC de Zend par exemple. La partie modèle (de données), en particulier, est réduite au plus simple : quelques variables de sessions.

Cette page, comme toutes celles de ce site, utilise les fichiers suivants :

Enfin, le contrôleur ajax, qui se substitue au contrôleur principal quand la page est modifiée par le menu « automatique ».

Toute cette mécanique n'est invoquée que si la page n'est pas en cache, c'est à dire seulement suite à une modification dans notre cas. Quand le contenu est en cache, seul un contrôleur frontal est activé.

.htaccess

php_flag display_errors off
php_flag session.use_only_cookies 1
php_value session.use_trans_sid 0

php_flag register_globals off 

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-javascript text/css
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary

RewriteEngine on
RewriteBase /
# RewriteRule ^Microsoft-Server-ActiveSync z-push/index.php [QSA,L]
RewriteRule ^a_x/(.*) $1 [QSA]
RewriteRule ^ajax/([^/]*).html ajax_.php?sujet=$1 [QSA]
RewriteRule ^([^/]*).html index.php?sujet=$1 [QSA]

	

index.php

<?php
if (isset($_SERVER["HTTP_ACCEPT"]) and stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) {
	header('Content-type: application/xhtml+xml');
} else 
header ('content-type: text/html; charset="utf-8"');

set_include_path(get_include_path() . PATH_SEPARATOR . '..');
require_once 'lib/functions.php';
require_once 'hop/hop.php';

//session
require_once 'Zend/Session/Namespace.php';
$session = new Zend_Session_Namespace();

//languages, define available translation
require_once("Zend/Translate.php");
$tr = new Zend_Translate('gettext', 'i18n/fr.mo', 'fr');
$tr->addTranslation('i18n/en.mo', 'en');

if ($request->lang and in_array($request->lang, $tr->getList())) {
	//lang in request parameter
	$tr->setLocale($request->lang);
	// in session
	$session->lang = $request->lang;
}
elseif (isset($session->lang) ) $tr->setLocale($session->lang); // lang already set in session
else {
	//get best gess language from browser
	require_once 'Zend/Locale.php';
	$locale = new Zend_locale();
	if (in_array($locale->getLanguage(), $tr->getList())) $tr->setLocale($locale->getLanguage());
	else $tr->setLocale('en');
	// in session
	$session->lang = $tr->getLocale();
}

// target page
$sujet = $request->get('sujet', 'accueil');
if ($sujet == 'hop') $sujet_lang = "views/{$sujet}_en.html";
else $sujet_lang = "views/{$sujet}_{$session->lang}.html";
include 'adm/compteurs.php';

// cache management
require_once 'Zend/Cache.php';
$ref_file = "views/$sujet.php";
//check for most recently modified file
if (file_exists($sujet_lang)) {
	if (filemtime($sujet_lang) > filemtime($ref_file)) $ref_file = $sujet_lang;
} elseif (file_exists("views/{$sujet}_fr.html") and filemtime("views/{$sujet}_fr.html") > filemtime($ref_file)) $ref_file = "views/{$sujet}_fr.html";
if (filemtime("views/theme.php") > filemtime($ref_file)) $ref_file = "views/theme.php";

$cache_page = Zend_Cache::factory('File', 'File', array('lifetime' => null, 'master_file' => $ref_file), array('cache_dir' => 'cache')); //, 'automatic_serialization' => true
$cache_page_id = "theme_{$sujet}_{$session->lang}";
if (!(isset($session->style) and $session->style != 'views/a_x.css') and $cache_page->test($cache_page_id)) {
	$page_h =  $cache_page->load($cache_page_id);
} else {
	// page generation
	$page = include 'views/theme.php';
	//save in cache
	if (!$cache_page->test($cache_page_id)) $cache_page->save($page_h = $page->render(), $cache_page_id); //render and save if needed
	//no cache
	if (isset($session->style) and $session->style != 'views/a_x.css') {
		$page->head->feuille_style->set_href($session->style);
		if ($session->style == 'views/vide.css') $page->head->hop_menu->set_href($session->style);
		$page_h = $page->render();
	}
}

// output html
echo $page_h;
?>
	

views/theme.php

<?php

// génération page
// require_once 'hop/hop.php';

$page = Hop_page::factory(array('title' =>"a/X : {$tr->_("développement web 2")} - {$tr->_($sujet)}", 'lang' => $session->lang));

$page->head->add($hop->meta('keywords')->auto_name()->set_attr('content', $tr->_("développement web, indépendant, web2, web 2, xhtml, php, javascript, ajax, jquery, prototype, mysql")));
$page->head->add($hop->link('feuille_style')->auto_id()
	->set_rel('stylesheet')->set_type('text/css')->set_media('screen')->set_href('views/a_x.css'));

$page->head
	->add($hop->link()->rel('alternate')->type('text/html')->hreflang('fr')->href('?lang=fr')->title('français'))
	->add($hop->link()->rel('alternate')->type('text/html')->hreflang('en')->href('?lang=en')->title('English'))
	->add($hop->script()->set_type('text/javascript')->set_src('lib_js/prototype.js'))
	->add($hop->script()->set_type('text/javascript')->set_src('lib_js/effects.js'))
	->add($hop->script()->set_type('text/javascript')->set_src('lib_js/dragdrop.js'))
	->add($hop->script()->set_type('text/javascript')->set_src('js/a_x.js'))
	->add($hop->script()->set_type('text/javascript')->set_src('js/ajax_menu.js'))
;

//SVG vector image
//commented out : Safari is the only browser to display and scale
// $page->body->add($hop->object('fond_logo')->auto_id()
// 	->set_type('image/svg+xml')
// 	->set_data('views/logo.svg')
// 	);

//titre page
$page->body
	->add($hop->p($hop->a($tr->getLocale() == 'en' ? 'français' : 'English')->set_href($tr->getLocale() == 'en' ? '?lang=fr' : '?lang=en'), 'lang')->auto_id())
	->add($hop->h1('<span class="a_X">a/X</span> ' . $tr->_("développement web 2"),'titre_page')->auto_id())
	;

// menu
$menu = Hop_menu::factory(array(
	'id' => 'menu_g',
	'page' => $page,
	'css' => 'views/hop_menu_IE6.css',
	'items' => array(
		'accueil' => $hop->a($tr->_("accueil"))->set_href('accueil.html'),
		'contributions' => $tr->_("contributions"),
		'web2' => $hop->a("Ajax, web 2")->set_href('web2.html'),
		'xhtml' => $hop->a("XHTML")->set_href('xhtml.html'),
		'css' => $hop->a("CSS")->set_href('css.html'),
		'javascript' => $hop->a("JavaScript")->set_href('javascript.html'),
		'php' => $hop->a("PHP")->set_href('php.html'),
		'zend' => $hop->a("Zend framework")->set_href('zend.html'),
		'mvc' => $hop->a("MVC")->set_href('mvc.html'),
		'mysql' => $hop->a("MySQL")->set_href('mysql.html'),
		'i18n' => $hop->a("i18n")->set_href('i18n.html'),
		'spip' => $hop->a("CMS, SPIP")->set_href('spip.html')
		)))
	->sub_menu(Hop_menu::factory(array(
		'id'=>'logiciels',
		'items' => array(
			'hop' => $hop->a("Ho<sub>in</sub>P")->set_href('hop.html'),
			'menus' => $hop->a($tr->_("menus en CSS"))->set_href('menus.html')
			)))
	, 'contributions')
	->auto_id()
	;
$hop->pool()->$sujet->add_class('actif'); //pool access for submenu items
$page->head->hop_menu->auto_id(); //for javascript vivibility
//menu div
$page->body->add($hop->div('menu')->auto_id()->add($menu));

// subject zone
$page->body->add($hop->div('travail')->auto_id()->add(include('cache_sujet.php')));

//footer
$page->body->add($hop->p('<a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Strict" height="15" width="44" /></a>')
	->set_class('pied'));

// return as object
return $page; 

?>
	

cache_sujet.php

<?php
// gestion cache
require_once 'Zend/Cache.php';
	
//test si modif sur sujet
$ref_file = "views/$sujet.php";
if (file_exists($sujet_lang)) {
	if (filemtime($sujet_lang) > filemtime($ref_file)) $ref_file = $sujet_lang;
} else
	if (file_exists("views/{$sujet}_fr.html") and filemtime("views/{$sujet}_fr.html") > filemtime($ref_file)) $ref_file = "views/{$sujet}_fr.html";
$cache_sujet = Zend_Cache::factory('File', 'File', array('lifetime' => null, 'master_file' => $ref_file), array('cache_dir' => 'cache')); //, 'automatic_serialization' => true
$cache_id = "{$sujet}_{$session->lang}";
if ($cache_sujet->test($cache_id)) {
	//en cache
	// echo "sujet issu du cache\n";
	return $cache_sujet->load($cache_id);
}

// génération page
$html_obj = include("views/$sujet.php");
$html = $html_obj->render();
//mise à jour cache
if ($cache_sujet) $cache_sujet->save($html);
//return html string
return $html;

?>
	

views/mvc.php

<?php
require_once 'lib/widgets.php';

$xhtml = new Hop_node;
if (file_exists("views/{$sujet}_{$session->lang}.html")) $f_source = "views/{$sujet}_{$session->lang}.html";
else $f_source = "views/{$sujet}_fr.html";

$xhtml->add(new Hop_node_from_file($f_source));

$xhtml->add(div_masque('htaccess', htmlspecialchars(file_get_contents(file_exists(".htaccess") ? '.htaccess' : 'htaccess.fi')), ".htaccess"));
$xhtml->add(div_masque('index', htmlspecialchars(file_get_contents("index.php")), "index.php"));
$xhtml->add(div_masque('theme', htmlspecialchars(file_get_contents("views/theme.php")), 'views/theme.php'));
$xhtml->add(div_masque('sujet', htmlspecialchars(file_get_contents("cache_sujet.php")), 'cache_sujet.php'));
$xhtml->add(div_masque('mvc_', htmlspecialchars(file_get_contents("views/mvc.php")), "views/mvc.php"));
$xhtml->add(div_masque('html_', htmlspecialchars(file_get_contents("views/mvc_fr.html")), "views/mvc_fr.html"));
// $xhtml->add(div_masque('html_', htmlspecialchars(file_get_contents("views/mvc_{$session->lang}.html")), "views/mvc_{$session->lang}.html"));
$xhtml->add(div_masque('ajax', htmlspecialchars(file_get_contents("ajax_.php")), "ajax.php"));

return $xhtml;

?>
	

views/mvc_fr.html

	<p>Ce site est construit sur le modèle <abbr title="Modèle Vues Contrôleurs">MVC</abbr>.</p>
	<p>Il pourrait n'être qu'un ensemble de page statique <abbr title="HyperText Markup Language">HTML</abbr>,
		mais il est plus rapide, plus simple à faire évoluer et beaucoup plus ouvert en terme de possibilité
		de partir dès le début d'un tel modèle.</p>
	<p>Dans ce cas il est relativement simplifié par rapport à une grosse application,
		qui utiliserait le module MVC de Zend par exemple.
		La partie modèle (de données), en particulier, est réduite au plus simple : quelques variables de sessions.</p>
	<p class="clear">Cette page, comme toutes celles de ce site, utilise les fichiers suivants :</p>
	<ul>
		<li>Le fichier <a href="#htaccess" onclick="Element.show($('htaccess'))">.htacces</a>,
			qui aiguille toutes les pages vers les contrôleurs d'entrée. Global au site.</li>
		<li><a href="#index" onclick="Element.show($('index'))">index.php</a>, le contrôleur d'entrée.
			Il gère la session, le choix de langue, le cache en fonction de la page visée. Global au site.</li>
		<li><a href="#theme" onclick="Element.show($('theme'))">views/theme.php</a>,
			invoqué par le précédent il construit le modèle du contenu de la page. Global au site, domaine "Vues".</li>
		<li><a href="#sujet" onclick="Element.show($('sujet'))">cache_sujet.php</a>, le contrôleur secondaire de la partie évolutive de la page.
			Il est distinct du contrôleur principal, car il est utilisé par les requêtes Ajax qui ne modifient que cette partie.
			Global au site, domaine "Contrôleurs".</li>
		<li><a href="#mvc_" onclick="Element.show($('mvc_'))">Un fichier php</a>, spécifique de chaque page, qui complémente la page globale avec les éléments nécessaires.
			Spécifique à chaque page, domaine "Vues".</li>
		<li><a href="#html_" onclick="Element.show($('html_'))">Un fichier html</a>,
			contenant le texte et les éléments html qui sont plus faciles à écrire en <abbr title="HyperText Markup Language">HTML</abbr> qu'en <code>PHP</code>.
			Il existe autant de variantes de ce fichier que de traductions disponibles.
			Les éléments de texte des fichiers <code>PHP</code> sont traduits par le module "translate" du <span class="contrib">Zend Framework</span>.
			Invoqué par le précédent, spécifique à chaque page, domaine "Vues".</li>
	</ul>
	<p>Enfin, <a href="#ajax" onclick="Element.show($('ajax'))">le contrôleur ajax</a>,
		qui se substitue au contrôleur principal quand la page est modifiée par le menu « automatique ».</p>
		<p>Toute cette mécanique n'est invoquée que si la page n'est pas en cache, c'est à dire seulement suite à une modification dans notre cas.
			Quand le contenu est en cache, seul un contrôleur frontal est activé.</p>
	

ajax.php

<?php
if (isset($_SERVER["HTTP_ACCEPT"]) and stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) {
	header('Content-type: application/xhtml+xml');
} else
if (isset($_SERVER["HTTP_ACCEPT"]) and stristr($_SERVER["HTTP_ACCEPT"],"application/xml")) {
	header('Content-type: application/xml');
} else 
header ('content-type: text/html; charset="utf-8"');

set_include_path(get_include_path() . PATH_SEPARATOR . '..');
require_once 'lib/functions.php';
require_once 'hop/hop.php';

//session
require_once 'Zend/Session/Namespace.php';
$session = new Zend_Session_Namespace();

//langues
require_once("Zend/Translate.php");
$tr = new Zend_Translate('gettext', 'i18n/fr.mo', 'fr');
$tr->addTranslation('i18n/en.mo', 'en');
if (isset($session->lang) ) $tr->setLocale($session->lang);
else $tr->setLocale('en');

//page visée
$sujet = $request->get('sujet', 'accueil');
if ($sujet == 'hop') $sujet_lang = "views/{$sujet}_en.html";
else $sujet_lang = "views/{$sujet}_{$session->lang}.html";
include 'adm/compteurs.php';

// contenu page
echo include('cache_sujet.php');

?>
	

Valid XHTML 1.0 Strict