2010-02-15 23:39:13 +01:00
< ? php
require 'SegmentIterator.php' ;
class SegmentException extends Exception
2017-04-29 01:01:12 +02:00
{
}
2010-02-15 23:39:13 +01:00
/**
* Class for handling templating segments with odt files
* You need PHP 5.2 at least
* You need Zip Extension or PclZip library
*
2017-04-29 01:01:12 +02:00
* @ copyright 2008 - Julien Pauli - Cyril PIERRE de GEYER - Anaska ( http :// www . anaska . com )
* @ copyright 2012 - Stephen Larroque - lrq3000 @ gmail . com
2010-02-15 23:39:13 +01:00
* @ license http :// www . gnu . org / copyleft / gpl . html GPL License
2013-04-07 17:27:35 +02:00
* @ version 1.4 . 5 ( last update 2013 - 04 - 07 )
2010-02-15 23:39:13 +01:00
*/
class Segment implements IteratorAggregate , Countable
{
protected $xml ;
protected $xmlParsed = '' ;
protected $name ;
protected $children = array ();
protected $vars = array ();
protected $images = array ();
protected $odf ;
protected $file ;
2017-09-18 15:49:21 +02:00
2010-02-15 23:39:13 +01:00
/**
* Constructor
*
2017-04-29 01:01:12 +02:00
* @ param string $name name of the segment to construct
* @ param string $xml XML tree of the segment
* @ param string $odf odf
2010-02-15 23:39:13 +01:00
*/
public function __construct ( $name , $xml , $odf )
{
$this -> name = ( string ) $name ;
$this -> xml = ( string ) $xml ;
$this -> odf = $odf ;
$zipHandler = $this -> odf -> getConfig ( 'ZIP_PROXY' );
2012-12-29 01:25:56 +01:00
$this -> file = new $zipHandler ( $this -> odf -> getConfig ( 'PATH_TO_TMP' ));
2010-02-15 23:39:13 +01:00
$this -> _analyseChildren ( $this -> xml );
}
/**
* Returns the name of the segment
*
* @ return string
*/
public function getName ()
{
return $this -> name ;
}
/**
* Does the segment have children ?
*
* @ return bool
*/
public function hasChildren ()
{
return $this -> getIterator () -> hasChildren ();
}
/**
* Countable interface
*
* @ return int
*/
public function count ()
{
return count ( $this -> children );
}
/**
* IteratorAggregate interface
*
* @ return Iterator
*/
public function getIterator ()
{
return new RecursiveIteratorIterator ( new SegmentIterator ( $this -> children ), 1 );
}
/**
* Replace variables of the template in the XML code
* All the children are also called
2016-03-22 19:24:48 +01:00
* Complete the current segment with new line
2010-02-15 23:39:13 +01:00
*
* @ return string
*/
public function merge ()
{
2017-09-18 15:49:21 +02:00
// To provide debug information on line number processed
2016-03-22 22:01:07 +01:00
global $count ;
if ( empty ( $count )) $count = 1 ;
else $count ++ ;
2017-09-18 15:49:21 +02:00
2016-03-22 22:01:07 +01:00
if ( empty ( $this -> savxml )) $this -> savxml = $this -> xml ; // Sav content of line at first line merged, so we will reuse original for next steps
$this -> xml = $this -> savxml ;
$tmpvars = $this -> vars ; // Store into $tmpvars so we won't modify this->vars when completing data with empty values
2017-09-18 15:49:21 +02:00
2016-03-22 22:01:07 +01:00
// Search all tags fou into condition to complete $tmpvars, so we will proceed all tests even if not defined
$reg = '@\[!--\sIF\s([{}a-zA-Z0-9\.\,_]+)\s--\]@smU' ;
preg_match_all ( $reg , $this -> xml , $matches , PREG_SET_ORDER );
//var_dump($tmpvars);exit;
foreach ( $matches as $match ) // For each match, if there is no entry into this->vars, we add it
{
if ( ! empty ( $match [ 1 ]) && ! isset ( $tmpvars [ $match [ 1 ]]))
{
$tmpvars [ $match [ 1 ]] = '' ; // Not defined, so we set it to '', we just need entry into this->vars for next loop
}
}
2017-09-18 15:49:21 +02:00
2016-03-22 22:01:07 +01:00
// Conditionals substitution
// Note: must be done before static substitution, else the variable will be replaced by its value and the conditional won't work anymore
foreach ( $tmpvars as $key => $value )
{
// If value is true (not 0 nor false nor null nor empty string)
if ( $value )
{
// Remove the IF tag
$this -> xml = str_replace ( '[!-- IF ' . $key . ' --]' , '' , $this -> xml );
// Remove everything between the ELSE tag (if it exists) and the ENDIF tag
$reg = '@(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU' ; // U modifier = all quantifiers are non-greedy
$this -> xml = preg_replace ( $reg , '' , $this -> xml );
}
// Else the value is false, then two cases: no ELSE and we're done, or there is at least one place where there is an ELSE clause, then we replace it
else
{
// Find all conditional blocks for this variable: from IF to ELSE and to ENDIF
$reg = '@\[!--\sIF\s' . $key . '\s--\](.*)(\[!--\sELSE\s' . $key . '\s--\](.*))?\[!--\sENDIF\s' . $key . '\s--\]@smU' ; // U modifier = all quantifiers are non-greedy
preg_match_all ( $reg , $this -> xml , $matches , PREG_SET_ORDER );
foreach ( $matches as $match ) { // For each match, if there is an ELSE clause, we replace the whole block by the value in the ELSE clause
if ( ! empty ( $match [ 3 ])) $this -> xml = str_replace ( $match [ 0 ], $match [ 3 ], $this -> xml );
}
// Cleanup the other conditional blocks (all the others where there were no ELSE clause, we can just remove them altogether)
$this -> xml = preg_replace ( $reg , '' , $this -> xml );
}
}
2017-09-18 15:49:21 +02:00
2016-03-22 22:01:07 +01:00
$this -> xmlParsed .= str_replace ( array_keys ( $tmpvars ), array_values ( $tmpvars ), $this -> xml );
2010-02-15 23:39:13 +01:00
if ( $this -> hasChildren ()) {
foreach ( $this -> children as $child ) {
$this -> xmlParsed = str_replace ( $child -> xml , ( $child -> xmlParsed == " " ) ? $child -> merge () : $child -> xmlParsed , $this -> xmlParsed );
$child -> xmlParsed = '' ;
}
}
$reg = " / \ [!-- \ sBEGIN \ s $this->name\s -- \ ](.*) \ [!-- \ sEND \ s $this->name\s -- \ ]/sm " ;
$this -> xmlParsed = preg_replace ( $reg , '$1' , $this -> xmlParsed );
2017-09-18 15:49:21 +02:00
// Miguel Erill 09704/2017 - Add macro replacement to invoice lines
2017-04-09 21:39:15 +02:00
$this -> xmlParsed = $this -> macroReplace ( $this -> xmlParsed );
2010-02-15 23:39:13 +01:00
$this -> file -> open ( $this -> odf -> getTmpfile ());
foreach ( $this -> images as $imageKey => $imageValue ) {
if ( $this -> file -> getFromName ( 'Pictures/' . $imageValue ) === false ) {
2013-04-07 17:27:35 +02:00
// Add the image inside the ODT document
2010-02-15 23:39:13 +01:00
$this -> file -> addFile ( $imageKey , 'Pictures/' . $imageValue );
2013-04-07 17:27:35 +02:00
// Add the image to the Manifest (which maintains a list of images, necessary to avoid "Corrupt ODT file. Repair?" when opening the file with LibreOffice)
$this -> odf -> addImageToManifest ( $imageValue );
2010-02-15 23:39:13 +01:00
}
}
2012-12-29 01:25:56 +01:00
$this -> file -> close ();
2017-09-18 15:49:21 +02:00
2010-02-15 23:39:13 +01:00
return $this -> xmlParsed ;
}
2017-05-05 14:49:25 +02:00
2017-04-09 21:39:15 +02:00
/**
* Function to replace macros for invoice short and long month , invoice year
2017-09-18 15:49:21 +02:00
*
2017-04-09 21:39:15 +02:00
* Substitution occur when the invoice is generated , not considering the invoice date
* so do not ( re ) generate in a diferent date than the one that the invoice belongs to
* Perhaps it would be better to use the invoice issued date but I still do not know
* how to get it here
*
* Miguel Erill 09 / 04 / 2017
2017-09-18 15:49:21 +02:00
*
2017-04-09 21:39:15 +02:00
* @ param string $value String to convert
*/
public function macroReplace ( $text )
{
2017-12-12 16:11:40 +01:00
include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php' ;
2017-04-09 21:39:15 +02:00
global $langs ;
2017-06-14 12:53:29 +02:00
$hoy = dol_getdate ( dol_now ( 'tzuser' ));
2017-09-21 11:41:30 +02:00
$dateinonemontharray = dol_get_next_month ( $hoy [ 'mon' ], $hoy [ 'year' ]);
$nextMonth = $dateinonemontharray [ 'month' ];
2017-12-12 16:11:40 +01:00
2017-06-14 12:53:29 +02:00
$patterns = array ( '/__CURRENTDAY__/u' , '/__CURENTWEEKDAY__/u' ,
'/__CURRENTMONTH__/u' , '/__CURRENTMONTHLONG__/u' ,
'/__NEXTMONTH__/u' , '/__NEXTMONTHLONG__/u' ,
2017-05-06 10:49:37 +02:00
'/__CURRENTYEAR__/u' , '/__NEXTYEAR__/u' );
2017-12-12 16:11:40 +01:00
$values = array ( $hoy [ 'mday' ], $langs -> transnoentitiesnoconv ( $hoy [ 'weekday' ]),
$hoy [ 'mon' ], $langs -> transnoentitiesnoconv ( $hoy [ 'month' ]),
$nextMonth , monthArray ( $langs )[ $nextMonth ],
2017-06-14 12:53:29 +02:00
$hoy [ 'year' ], $hoy [ 'year' ] + 1 );
2017-04-09 21:39:15 +02:00
$text = preg_replace ( $patterns , $values , $text );
return $text ;
}
2017-05-05 14:49:25 +02:00
2010-02-15 23:39:13 +01:00
/**
* Analyse the XML code in order to find children
*
2017-04-29 01:01:12 +02:00
* @ param string $xml Xml
2010-02-15 23:39:13 +01:00
* @ return Segment
*/
protected function _analyseChildren ( $xml )
{
// $reg2 = "#\[!--\sBEGIN\s([\S]*)\s--\](?:<\/text:p>)?(.*)(?:<text:p\s.*>)?\[!--\sEND\s(\\1)\s--\]#sm";
$reg2 = " # \ [!-- \ sBEGIN \ s([ \ S]*) \ s-- \ ](.*) \ [!-- \ sEND \ s( \\ 1) \ s-- \ ]#sm " ;
preg_match_all ( $reg2 , $xml , $matches );
for ( $i = 0 , $size = count ( $matches [ 0 ]); $i < $size ; $i ++ ) {
if ( $matches [ 1 ][ $i ] != $this -> name ) {
$this -> children [ $matches [ 1 ][ $i ]] = new self ( $matches [ 1 ][ $i ], $matches [ 0 ][ $i ], $this -> odf );
} else {
$this -> _analyseChildren ( $matches [ 2 ][ $i ]);
}
}
return $this ;
}
2017-09-18 15:49:21 +02:00
2010-02-15 23:39:13 +01:00
/**
* Assign a template variable to replace
*
2017-04-29 01:01:12 +02:00
* @ param string $key Key
* @ param string $value Value
* @ param string $encode Encode
* @ param string $charset Charset
2010-02-15 23:39:13 +01:00
* @ throws SegmentException
* @ return Segment
*/
public function setVars ( $key , $value , $encode = true , $charset = 'ISO-8859' )
{
if ( strpos ( $this -> xml , $this -> odf -> getConfig ( 'DELIMITER_LEFT' ) . $key . $this -> odf -> getConfig ( 'DELIMITER_RIGHT' )) === false ) {
2016-03-22 22:01:07 +01:00
//throw new SegmentException("var $key not found in {$this->getName()}");
2010-02-15 23:39:13 +01:00
}
2014-05-07 19:13:02 +02:00
$value = $this -> odf -> htmlToUTFAndPreOdf ( $value );
2010-02-15 23:39:13 +01:00
$value = $encode ? htmlspecialchars ( $value ) : $value ;
$value = ( $charset == 'ISO-8859' ) ? utf8_encode ( $value ) : $value ;
2014-05-07 19:13:02 +02:00
$value = $this -> odf -> preOdfToOdf ( $value );
$this -> vars [ $this -> odf -> getConfig ( 'DELIMITER_LEFT' ) . $key . $this -> odf -> getConfig ( 'DELIMITER_RIGHT' )] = $value ;
2010-02-15 23:39:13 +01:00
return $this ;
}
/**
* Assign a template variable as a picture
*
* @ param string $key name of the variable within the template
* @ param string $value path to the picture
* @ throws OdfException
* @ return Segment
*/
public function setImage ( $key , $value )
{
$filename = strtok ( strrchr ( $value , '/' ), '/.' );
$file = substr ( strrchr ( $value , '/' ), 1 );
$size = @ getimagesize ( $value );
if ( $size === false ) {
throw new OdfException ( " Invalid image " );
}
2013-04-07 17:27:35 +02:00
// Set the width and height of the page
2010-02-15 23:39:13 +01:00
list ( $width , $height ) = $size ;
$width *= Odf :: PIXEL_TO_CM ;
$height *= Odf :: PIXEL_TO_CM ;
2013-04-07 17:27:35 +02:00
// Fix local-aware issues (eg: 12,10 -> 12.10)
$width = sprintf ( " %F " , $width );
$height = sprintf ( " %F " , $height );
2010-02-15 23:39:13 +01:00
$xml = <<< IMG
2013-04-07 17:27:35 +02:00
< draw : frame draw : style - name = " fr1 " draw : name = " $filename " text : anchor - type = " aschar " svg : width = " { $width } cm " svg : height = " { $height } cm " draw : z - index = " 3 " >< draw : image xlink : href = " Pictures/ $file " xlink : type = " simple " xlink : show = " embed " xlink : actuate = " onLoad " /></ draw : frame >
2010-02-15 23:39:13 +01:00
IMG ;
$this -> images [ $value ] = $file ;
$this -> setVars ( $key , $xml , false );
return $this ;
2012-12-29 01:25:56 +01:00
}
2010-02-15 23:39:13 +01:00
/**
* Shortcut to retrieve a child
*
2017-04-29 01:01:12 +02:00
* @ param string $prop Prop
2010-02-15 23:39:13 +01:00
* @ return Segment
* @ throws SegmentException
*/
public function __get ( $prop )
{
if ( array_key_exists ( $prop , $this -> children )) {
return $this -> children [ $prop ];
} else {
throw new SegmentException ( 'child ' . $prop . ' does not exist' );
}
}
/**
* Proxy for setVars
*
2017-04-29 01:01:12 +02:00
* @ param string $meth Meth
* @ param array $args Args
2010-02-15 23:39:13 +01:00
* @ return Segment
*/
public function __call ( $meth , $args )
{
try {
return $this -> setVars ( $meth , $args [ 0 ]);
} catch ( SegmentException $e ) {
throw new SegmentException ( " method $meth nor var $meth exist " );
}
}
/**
* Returns the parsed XML
*
* @ return string
*/
public function getXmlParsed ()
{
return $this -> xmlParsed ;
}
}