Newsgroup: it.comp.www.php
Titolo: Tag customizzati

Vorrei creare dei tag custom che vengono processati dal PHP ed esegue le 
varie funzioni, un pò come avviene per alcuni CMS tipo Joomla.
Come fare?
Thx



Ti devi costruire un motore di templating, piu` o meno complesso in base 
alle tue esigenze.
In pratica metterai il codice (prendendolo dal DB o da un file) in una 
stringa e lo processerai con str_replace o con preg_replace o funzioni 
simili, e alla fine genererai HTML.
La spiegazione e` un po' vaga, ma anche la domanda lo e`. :)
Bye.

 Bye.
E ti pareva :)
Non ci sono motori già realizzati che facciano cose del genere? Che tu 
sappia Joomla! lavora in questo modo?

 sappia Joomla! lavora in questo modo?
Bhè tu hai detto di voler realizzare, non di voler usare qualcosa di
già fatto ;)
Cmq di templating engine per php ce ne sono millemila, googla per "php
template engine"
Comunque, spiegheresti meglio la tua esigenza?
Gestire dei tag riguarda (imho) più la strutturazione del database che
il templating...

 il templating...
Tra i tag (x)html dovrebbero essere scritti dei tag custom che PHP 
interpreta per svolgere una qualsiasi funzione assegnata...
Ad es. in Joomla! ci sono tag proprietari come <jdoc:include 
type="modules" name="topmenu" /> che integra il "risultato" di quel 
modulo che non fa altro che scrivere html in base a ciò che hai editato 
nel CMS.



Un sistema poco estendibile, ma veloce e con pochi prerequisiti, e' dare
giu' dvrissimo con preg_replace:
	function tag($tag, $testo)
	{
		switch($tag)
		{
			case 'href':
				$testo = strtolower($testo); // Perché sì
				// vedi le funzioni di URL parsing per la
				// validazione... si sa mai... eh?
				return "<span
class=\"linchi\">$testo</span>";
				break;
			// Ecc ecc.
		}
		return $testo; // I tag sbagliati fanno "puf".
	}
        $text = preg_replace("#{([^'}]*)}([^{'}]*){/\\1}#mse",
                        "tag('\\1','\\2')", $text);
E qui gli passi un testo con, che so, {href}
www.google.it
{/href}. Per un
nuovo tag, aggiungi roba nello switch. Fine.
Per un hack quick'n'dirty, va. "Pel una pizzata, e' l'ideale" (cit.)[1].
Se vuoi una roba piu' articolata, e' un bagno di sangue comunque :-)
Un sistema pratico - che ha pregi e difetti, come tutto - e' caricare il
testo con il parser XML. Certo, se non gli dai in pasto XML ben formato,
l'hai un po' nel fiocco. Per contro, sei sicuro che l'output sia XML ben
formato (da cui (X)HTML a piacer tuo).
Qui per ogni tag che vuoi supportare devi creare una funzione (o anche -
se ci ciappini parecchio, ho la sensazione che ti servira' - due)... una
_open_NOMETAG e l'altra _close_NOMETAG. I tag dovrebbero potersi perfino
nidificare, non ho controllato granche'.
function XMLCreateParser()
{
	$xmlobj         = xml_parser_create();
	xml_set_element_handler         ($xmlobj, 'startElement',
'endElement');
	xml_set_character_data_handler  ($xmlobj, 'dataHandler');
	return $xmlobj;
}
A questo punto, quando termina un tag, viene chiamata la tua funzione; e
pero' devi mantenere uno stack dell'albero processato fino ad allora, se
uno vuole fare in fretta lo dichiara global e bella lì:
function startElement($xml, $rawtag, $attrs)
{
        GLOBAL $HTMLSTACK, $HTMLCURR;
        $HTMLSTACK[] = $HTMLCURR;
        // Mettiamo anche il namespace, non facciamoci mancare nulla
        $a      = explode(':', $rawtag);
        $tag    = strtolower(array_pop($a));
        $HTMLCURR = array( 'name' => $tag, 'data' => '' );
        if (!empty($attrs))
                $HTMLCURR['ppar'] = $attrs;
        if (function_exists($userfn = '_open_'.$tag))
                $userfn($HTMLCURR);
}
function endElement($xml, $rawtag)
{
        GLOBAL $HTMLSTACK, $HTMLCURR;
        $a      = explode(':', $rawtag);
        $tag    = strtolower(array_pop($a));
	// Qui ci vorrebbe un reupero per i tag come <br> e <hr>
        if ($tag != $HTMLCURR['name'])
                trigger_error("Tag mismatch: open $tag, closing
$HTMLCURR[name].", E_USER_ERROR);
        if (function_exists($userfn = '_close_'.$tag))
                $data = $userfn($HTMLCURR);
        else
        {
                $data   = "<$HTMLCURR[name]";
                if (isset($HTMLCURR['ppar']))
                        foreach($HTMLCURR['ppar'] as $key => $val)
                                $data .= ' ' . strtolower($key) . '="' .
str_replace('"','',$val) . '"';
                $data   .= '>' . $HTMLCURR['data'] . '</' .
$HTMLCURR['name'] . '>';
        }
        if (false === ($HTMLCURR = array_pop($HTMLSTACK)))
                trigger_error('Template stack underflow', E_USER_ERROR);
        $HTMLCURR['data'] .= $data;
}
function dataHandler($xml, $data)
{
        GLOBAL $HTMLCURR;
        if ('' == ($data = trim($data)))
                return;
        // Andrebbe fatto in modo meno urfido
        $HTMLCURR['data'] = (
                isset($HTMLCURR['data']) ?
                $HTMLCURR['data'] : ''
        ) . $data;
}
// Il parser poi dovro' pure levarlo
function XMLDestroyParser($xmlobj)
{
        GLOBAL  $HTMLCURR, $HTMLSTACK;
        xml_parse($xmlobj, '', true);
        xml_parser_free($xmlobj);
        unset($HTMLCURR);
        unset($HTMLSTACK);
}
// Modificarlo per gestire una stringa e' banale
// Meno banale e' gestire i tag singleton, come <img /> ]:-)
function processTemplate($file)
{
        GLOBAL  $HTMLCURR, $HTMLSTACK, $xmlobj;
        $HTMLCURR       = array('data' => '');
        $HTMLSTACK      = array();
        if (!($fp     = fopen($file, 'r')))
                trigger_error("Cannot open $magfile", E_USER_ERROR);
        $xmlobj = XMLCreateParser();
        while(!feof($fp))
        {
                $chunk  = fread($fp, 4096);
                xml_parse($xmlobj, $chunk);
        }
        XMLDestroyParser($xmlobj);
        return $HTMLCURR['data'];
}
---
<html>
        <head>
                <title>Questo e' test.xml</title>
        </head>
        <body>
                Questa e' una <b><i>prova</i></b>.
                <diritto>Sator arepo te</diritto>
                n
                <ribarta>Sator arepo te</ribarta>.
        </body>
</html>
---
<?php
	include 'pythetic.php';
	// Funzione che ribarta un testo
	function _close_ribarta($argv)
	{
        	return strrev($argv['data']);
	}
	// Funzione che non fa nulla
	function _close_diritto($argv)
	{
	        return $argv['data'];
	}
	function _close_i($argv)
	{
		return '<em>'.$argv['data'].'</em>';
	}
	function _close_b($argv)
	{
		return '<span class="strong">'.$argv['data'].'</span>';
	}
	print processTemplate("test.xml");
?>
Leonardo e parser a chicchi
[1] 
http://www.youtube.com/watch?v=cXs_bG7rKxs
-- 
Enough, enough!  But, stranger, ere we part,
Glancing farewell to each nefarious bier,
This warning would I beg you take to heart:
There is an end to e'en the worst career!

 giu' dvrissimo con preg_replace:
[CUT]
Mi sa che è la via giusta. Ovviamente pensavo ci fosse qualcosa di già 
fatto, una piccola libreria... Non sono il tipo che si reinventa la 
ruota, però se ce n'è bisogno... :)
Thx