CodeToDiagram.class.php

Go to the documentation of this file.
00001 <?php
00014 class CodeToDiagram
00015 {
00021         protected $arrFiles = array();
00022 
00028         protected $booStart = false;
00029 
00035         protected $strFileFrom = null;
00036 
00042         protected $strFileName = "diagram.html";
00043 
00050         protected $strOutputType = self::OUTPUT_TYPE_SCREEN;
00051 
00058         protected $strPrinterType = self::PRINTER_TYPE_HTML;
00059 
00065     protected $objPrinter;
00066 
00072         protected $strCallerPath;
00073 
00079         protected $strPublicPath;
00080         
00087         protected $booExternalAccess = false;
00093         protected static $objInstance;
00094 
00101         const RUN_IN_FILES = false;
00102 
00111         const REMOVE_FILES = true;
00112 
00117         const CODE_TO_DIAGRAM_CLASS_PREFIX = "CTD";
00118 
00125         const OUTPUT_TYPE_STRING = "string";
00126 
00134         const OUTPUT_TYPE_FILE = "file";
00135 
00140         const OUTPUT_TYPE_SCREEN = "screen";
00141 
00148         const PRINTER_TYPE_XML = "xml";
00149 
00156         const PRINTER_TYPE_HTML = "html";
00157 
00158     const MSG_NO_WRITE_PERMISSION = " The user of the system does not have permission to write the code to diagram files. Change the RUN_IN_FILES to false and save your files into a allowed folder.";
00159 
00165     protected static $arrDefaultStereotypes = array( 'user' , 'system' , 'user' , 'entity' , 'controller' , 'boundary' , 'database');
00166 
00173     public function __construct()
00174     {
00175         $this->loadDefaultsStereotypes();
00176         $this->setPrinterType( $this->getPrinterType() );
00177     }
00178 
00182     protected function loadDefaultsStereotypes()
00183     {
00184         foreach( self::$arrDefaultStereotypes as $strDefaultStereotype )
00185         {
00186             $objStereotype = new UmlSequenceDiagramStereotype();
00187             $objStereotype->setName( $strDefaultStereotype  )->setDefault( true );
00188             UmlSequenceDiagramStereotype::addStereotype( $objStereotype );
00189         }
00190 
00191     }
00192 
00199         public function getConfiguration()
00200         {
00201                 return CodeInstrumentationReceiver::getInstance()->getConfiguration();
00202         }
00203 
00210     public function setPrinter( UmlSequenceDiagramPrinterInterface $objPrinter )
00211     {
00212         $this->objPrinter = $objPrinter;
00213         return $this;
00214     }
00215 
00221     public function getPrinter()
00222     {
00223         return $this->objPrinter;
00224     }
00225 
00233     public function setPrinterConfiguration( UmlSequenceDiagramPrinterConfigurationInterface $objPrinterConfiguration )
00234     {
00235         if( get_class( $objPrinterConfiguration ) != get_class( $this->getPrinterConfiguration() ) )
00236         {
00237             throw new CodeToDiagramException( "Invalid Printer Configuration" );
00238         }
00239         $this->getPrinter()->setConfiguration( $objPrinterConfiguration );
00240         return $this;
00241     }
00242 
00248     public function getPrinterConfiguration()
00249     {
00250         return $this->getPrinter()->getConfiguration();
00251     }
00252 
00280         public function setOutputType( $strType )
00281         {
00282                 switch( $strType )
00283                 {
00284                         case CodeToDiagram::OUTPUT_TYPE_SCREEN:
00285                         case CodeToDiagram::OUTPUT_TYPE_STRING:
00286                         case CodeToDiagram::OUTPUT_TYPE_FILE :
00287                         {
00288                                 $this->strOutputType = $strType;
00289                                 break;
00290                         }
00291                         default:
00292                         {
00293                                 throw new CodeToDiagramException( "Invalid output type. ('" . $strType . "')" );
00294                                 break;
00295                         }
00296                 }
00297                 return $this;
00298         }
00299 
00322         public function getOutputType()
00323         {
00324                 return $this->strOutputType;
00325         }
00326 
00350         public function setPrinterType( $strType )
00351         {
00352                 switch( $strType )
00353                 {
00354                         case CodeToDiagram::PRINTER_TYPE_HTML:
00355             {
00356                 $this->setPrinter( UmlSequenceDiagramPrinterToHtml::getInstance() );
00357                                 $this->strPrinterType = $strType;
00358                                 break;
00359             }
00360                         case CodeToDiagram::PRINTER_TYPE_XML:
00361                         {
00362                 $this->setPrinter( UmlSequenceDiagramPrinterToXml::getInstance() );
00363                                 $this->strPrinterType = $strType;
00364                                 break;
00365                         }
00366                         default:
00367                         {
00368                                 throw new CodeToDiagramException( "Invalid printer type. ('" . $strType . "')" );
00369                                 break;
00370                         }
00371                 }
00372                 return $this;
00373         }
00374 
00393         public function getPrinterType()
00394         {
00395                 return $this->strPrinterType;
00396         }
00397 
00406         public function setExternalAcess( $booExternalAccess )
00407         {
00408                 $this->booExternalAccess = (boolean)$booExternalAccess;
00409                 return $this;
00410         }
00411 
00419         public function getExternalAcess()
00420         {
00421                 return $this->booExternalAccess;
00422         }
00423 
00439         public static function hasInstance()
00440         {
00441                 return ( self::$objInstance !== null );
00442         }
00443 
00454         public static function getInstance()
00455         {
00456                 if( self::$objInstance === null )
00457                 {
00458                         self::$objInstance = new CodeToDiagram();
00459                 }
00460                 return self::$objInstance;
00461         }
00462 
00479         public function setStarted( $booStarted )
00480         {
00481                 $this->booStart = $booStarted;
00482                 return $this;
00483         }
00484 
00498         public function getStarted()
00499         {
00500                 return $this->booStart;
00501         }
00502 
00515         public function setFileFrom( $strFileFrom )
00516         {
00517                 $this->strFileFrom = $strFileFrom;
00518                 return $this;
00519         }
00520 
00531         public function getFileFrom()
00532         {
00533                 return $this->strFileFrom;
00534         }
00535 
00546         public function setFileName( $strFileName )
00547         {
00548                 $this->strFileName = $strFileName;
00549                 return $this;
00550         }
00551 
00561         public function getFileName()
00562         {
00563                 return $this->strFileName;
00564         }
00565         
00572         public function setCallerPath( $strCallerPath )
00573         {
00574                 $this->strCallerPath = $strCallerPath;
00575                 return $this;
00576         }
00577         
00583         public function getCallerPath()
00584         {
00585                 return $this->strCallerPath;
00586         }
00587         
00594         public function setPublicPath( $strPublicPath )
00595         {
00596                 $this->strPublicPath = $strPublicPath;
00597                 return $this;
00598         }
00599         
00605         public function getPublicPath()
00606         {
00607                 return $this->strPublicPath;    
00608         }
00609         
00617         public function start()
00618         {
00619                 ob_start();
00620                 if( $this->getStarted() )
00621                 {
00622                         return $this;
00623                 }
00624                 else
00625                 {
00626                         CodeInstrumentationReceiver::getInstance()->restart();
00627                         $this->CodeToDiagramRequireOnce($this->getFileFrom() , $this->getFileFrom() );
00628                         exit();
00629 
00630                         // just to safety //
00631                         return $this;
00632                 }
00633         }
00634 
00642         public function restart()
00643         {
00644                 CodeInstrumentationReceiver::getInstance()->restart();
00645                 return $this;
00646         }
00647 
00655     private function checkPermissionToWrite( $strFileName )
00656     {
00657         $strPath = CorujaFileManipulation::getPathOfFile( $strFileName );
00658 
00659         if( $strPath == "" )
00660         {
00661             $strPath = $this->getPublicPath();
00662         }
00663 
00664         if( file_exists( $strFileName ) )
00665         {
00666             if( !is_writable( $strFileName ) )
00667             {
00668                 throw new CodeToDiagramException( 1 .  self::MSG_NO_WRITE_PERMISSION );
00669             }
00670             return TRUE;
00671         }
00672 
00673         if( is_dir( $strPath ) )
00674         {
00678             return true;
00679         }
00680 
00681         if( !mkdir( $strPath , 0777, TRUE ) )
00682         {
00683                 throw new CodeToDiagramException(3 . self::MSG_NO_WRITE_PERMISSION );
00684         }
00685         return TRUE;
00686     }
00687 
00708         public function save()
00709         {
00710                 $strReturn = "";
00711                 $strDiagram = "";
00712                 
00713                 if( $this->getStarted() )
00714                 {
00715             $strContent = ob_get_contents();
00716             ob_end_clean();
00717                         $objUmlSequenceDiagram = CodeInstrumentationReceiver::getInstance()->getUmlSequenceDiagram();
00718             $objUmlSequenceDiagram->setOutput( $strContent );
00719 
00720                         switch( $this->getPrinterType() )
00721                         {
00722                                 case self::PRINTER_TYPE_HTML:
00723                                 {
00724                                         $objPrinter = UmlSequenceDiagramPrinterToHtml::getInstance();
00725                     UmlSequenceDiagramPrinterToHtml::getInstance()->getConfiguration()->setPublicPath( $this->getPublicPath() );
00726                                         UmlSequenceDiagramPrinterToHtml::getInstance()->getConfiguration()->setCallerPath( $this->getCallerPath() );
00727                                         UmlSequenceDiagramPrinterToHtml::getInstance()->getConfiguration()->setExternalAccess( $this->getExternalAcess() );
00728                                         $strDiagram = UmlSequenceDiagramPrinterToHtml::getInstance()->perform( $objUmlSequenceDiagram );
00729                                         break;
00730                                 }
00731                                 case self::PRINTER_TYPE_XML:
00732                                 {
00733                                         $objPrinter = UmlSequenceDiagramPrinterToXml::getInstance();
00734                                         $strDiagram = UmlSequenceDiagramPrinterToXml::getInstance()->perform( $objUmlSequenceDiagram );
00735                                         break;
00736                                 }
00737                                 default:
00738                                 {
00739                                         throw new CodeToDiagramException( "Invalid printer type ({$this->getPrinterType()})" );
00740                                         break;
00741                                 }
00742                         }
00743                         switch( $this->getOutputType() )
00744                         {
00745                                 case self::OUTPUT_TYPE_SCREEN:
00746                                 {
00747                                         $objPrinter->getHeader();
00748                                         print $strDiagram;
00749                                         break;
00750                                 }
00751                                 case self::OUTPUT_TYPE_STRING:
00752                                 {
00753                                         $strReturn = $strDiagram;
00754                                         break;
00755                                 }
00756                                 case self::OUTPUT_TYPE_FILE:
00757                                 {
00758                     $this->checkPermissionToWrite( $this->getFileName() );
00759                                         file_put_contents( $this->getFileName() , $strDiagram );
00760                                         $strReturn = $strDiagram;
00761                                         break;
00762                                 }
00763                                 default:
00764                                 {
00765                                         throw new CodeToDiagramException( "Invalid output type ({$this->getOutputType()})" );
00766                                         break;
00767                                 }
00768                         }
00769                         CodeInstrumentationReceiver::getInstance()->restart();
00770                 }
00771                 return $strReturn;
00772         }
00773 
00777         public function  __destruct() {
00778 
00779                 $this->save();
00780         }
00781 
00788         public static function init( $strFile )
00789         {
00790                 if( self::getInstance()->getStarted() == false )
00791                 {
00792                         self::getInstance()->setFileFrom( $strFile );
00793                 }
00794                 return self::getInstance();
00795         }
00796 
00805         protected function fixFileName( $strFileFrom, $strFile )
00806         {
00807                 $strFileFrom = str_replace( '/', '\\', $strFileFrom );
00808                 $strFile = str_replace( '/', '\\', $strFile );
00809                 $strFilePath = substr( $strFileFrom ,  0 , -(strlen(basename($strFileFrom ) ) ) );
00810                 $strFile = $strFilePath . $strFile;
00811 
00812                 return $strFile;
00813         }
00814 
00822         public function addFile( $strFileFrom, $strFile )
00823         {
00824                 $strFile = $this->fixFileName( $strFileFrom, $strFile );
00825 
00826                 $this->arrFiles[] = $strFile;
00827 
00828                 return $this;
00829         }
00830 
00838         protected function hasFile( $strFileFrom , $strFile )
00839         {
00840                 return in_array( $strFile ,  $this->arrFiles );
00841         }
00842 
00851         public function CodeToDiagramRequireOnce( $strFileFrom, $strFile )
00852         {               
00853                 $arrCodeToDiagramBackTrace = debug_backtrace();
00854 
00855                 if( !$this->hasFile( $strFileFrom , $strFile ) )
00856                 {
00857                         $this->CodeToDiagramRequire( $strFileFrom, $strFile );
00858                 }
00859                 return $this;
00860         }
00861 
00870         public function CodeToDiagramIncludeOnce( $strFileFrom, $strFile )
00871         {
00872                 if( !$this->hasFile( $strFileFrom , $strFile ) )
00873                 {
00874                         $this->CodeToDiagramIncludeOnce( $strFileFrom , $strFile );
00875                 }
00876                 return $this;
00877         }
00878 
00887         public function CodeToDiagramRequire( $strFileFrom, $strFile )
00888         {
00889                 $this->loadFile( $strFileFrom , $strFile );
00890                 return $this;
00891         }
00892 
00901         public function CodeToDiagramInclude( $strFileFrom, $strFile )
00902         {
00903                 $this->loadFile( $strFileFrom , $strFile );
00904                 return $this;
00905         }
00906 
00915         public function CodeToDiagramExit( $strFileFrom = '', $strMessage = '')
00916         {
00917                 print "Exit called into $strFileFrom ($strMessage ) ";
00918         }
00919 
00928         protected function convertFileContent( $strContentFile , $strFile , $strFullFile )
00929         {
00930                 if( self::getInstance()->getStarted() == false )
00931                 {
00932                         self::getInstance()->setStarted( true );
00933                         $strContentFile = preg_replace('/require_once/', '//require_once', $strContentFile, 1);
00934                 }
00935 
00936                 $strContentFile = str_replace(
00937                         Array(
00938                                 'require_once(' ,
00939                                 'require(' ,
00940                                 'include(' ,
00941                                 'include_once(',
00942                                 'exit()',
00943                                 'exit(',
00944                                 '__FILE__',
00945                         ),
00946                         Array(
00947                                 'CodeToDiagram::getInstance()->CodeToDiagramRequireOnce("'. $strFile . '",' ,
00948                                 'CodeToDiagram::getInstance()->CodeToDiagramRequire("'. $strFile . '",' ,
00949                                 'CodeToDiagram::getInstance()->CodeToDiagramInclude("'. $strFile . '",' ,
00950                                 'CodeToDiagram::getInstance()->CodeToDiagramIncludeOnce("'. $strFile . '",',
00951                                 'CodeToDiagram::getInstance()->CodeToDiagramExit("'. $strFile . '")',
00952                                 'CodeToDiagram::getInstance()->CodeToDiagramExit("'. $strFile . '",',
00953                                 '"' . $this->getCallerPath() . $strFullFile . '"',
00954                         ),
00955                         $strContentFile
00956                 );
00957 
00958                 return $strContentFile;
00959         }
00960 
00968         public function codeInstrumentationLine( $strLine, $strTextSearch )
00969         {
00970                 $arrResult = array();
00971 
00972                 if(  substr( strtolower( trim( $strLine ) ) , 0 , strlen( $strTextSearch ) ) == $strTextSearch )
00973                 {
00974                         $strLine = trim( $strLine );
00975                         $strBefore = substr( $strLine , 0 , strlen( $strTextSearch ) );
00976                         $strAfter = substr( $strLine , strlen( $strTextSearch ) );
00977                         $arrWords = explode( " " , $strAfter );
00978 
00979                         $strOldClassName = $arrWords[0];
00980                         $strNewClassName = self::CODE_TO_DIAGRAM_CLASS_PREFIX . $strOldClassName;
00981 
00982                         $arrWords[0] = $strNewClassName;
00983                         $strAfter = implode( " " , $arrWords );
00984                         $strLine = $strBefore . $strAfter;
00985 
00986                         $arrResult[ "line" ] = $strLine;
00987                         $arrResult[ "class_old" ] = $strOldClassName;
00988                         $arrResult[ "class_new" ] = $strNewClassName;
00989 
00990                 }
00991                 return $arrResult;
00992         }
00993 
01002         protected function codeInstrumentationClass( $strTextSearch, array &$arrOldClasses , array &$arrNewClasses , array &$arrLines )
01003         {
01004                 foreach( $arrLines as $intLine => $strLine )
01005                 {
01006                         $arrResult = $this->codeInstrumentationLine( $strLine , $strTextSearch  );
01007 
01008                         if( sizeof( $arrResult ) !== 0 )
01009                         {
01010                                 $arrOldClasses[] = $arrResult[ "class_old" ];
01011                                 $arrNewClasses[] = $arrResult[ "class_new" ];
01012                                 $arrLines[ $intLine ] = $arrResult[ "line" ];
01013                         }
01014                 }
01015         }
01016 
01024         protected function preloadFile( $strFileName , $strContentFile )
01025         {
01026                 if( self::RUN_IN_FILES )
01027                 {
01028                         $strFileName = $strFileName . "(0).phps";
01029             print $strFileName;
01030             $this->checkPermissionToWrite( $strFileName );
01031                         file_put_contents( $strFileName , $strContentFile );
01032                         require_once( $strFileName );
01033                         if( self::REMOVE_FILES )
01034                         {
01035                                 unlink( $strFileName );
01036                         }
01037                 }
01038                 else
01039                 {
01040                         eval( '?' . '>' . $strContentFile );
01041                 }
01042                 return $this;
01043         }
01044         
01051         protected function codeInstrumentationFile( $strFileName , $strContentFile )
01052         {
01053                 $arrLines = explode( "\n"  , $strContentFile );
01054                 $arrOldClasses  = array();
01055                 $arrNewClasses  = array();
01056                 $arrOldInterface = array();
01057                 $arrNewInterface = array();
01058 
01059                 $this->codeInstrumentationClass( "class " , $arrOldClasses , $arrNewClasses, $arrLines );
01060                 $this->codeInstrumentationClass( "interface " , $arrOldInterface , $arrNewInterface, $arrLines );
01061 
01062                 $strContentFile = implode( "\n" , $arrLines );
01063 
01064                 $this->preloadFile( $strFileName , $strContentFile );
01065 
01066                 foreach( $arrNewClasses as $intKey => $strNewClassName )
01067                 {
01068                         $oReflectionCode = new CodeInstrumentationClass( $strNewClassName , $strContentFile );
01069                         $oReflectionCode->setClassName( $arrOldClasses[ $intKey ] );
01070                         $strNewCode = $oReflectionCode->getCode();
01071                         if( self::RUN_IN_FILES )
01072                         {
01073                                 $strFileName = trim( $strNewClassName ) . "(1).phps";
01074                 $this->checkPermissionToWrite( $strFileName );
01075                 file_put_contents( $strFileName , '<?' . 'php ' .  $strNewCode );
01076                                 require_once( $strFileName );
01077                                 if( self::REMOVE_FILES )
01078                                 {
01079                                         unlink( $strFileName );
01080                                 }
01081                         }
01082                         else
01083                         {
01084                                 eval( $strNewCode );
01085                         }
01086                 }
01087                 foreach( $arrNewInterface as $intKey => $strNewInterfaceName )
01088                 {
01089                         $strOldInterface = $arrOldInterface[ $intKey ];
01091                         $strNewCode = "interface $strOldInterface {} ";
01092                         if( self::RUN_IN_FILES )
01093                         {
01094                                 $strFileName = trim( $strNewInterfaceName ) . "(1).phps";
01095                 $this->checkPermissionToWrite( $strFileName );
01096                                 file_put_contents( $strFileName , '<?' . 'php ' .  $strNewCode );
01097                                 require_once( $strFileName );
01098                                 if( self::REMOVE_FILES )
01099                                 {
01100                                         unlink( $strFileName );
01101                                 }
01102                         }
01103                         else
01104                         {
01105                                 eval( $strNewCode );
01106                         }
01107                 }
01108         }
01109 
01117         protected function loadFile( $strFileFrom, $strFile )
01118         {
01119                 if( basename( $strFile ) == 'CodeToDiagram.class.php' )
01120                 {
01121                         return $this;
01122                 }
01123                 $this->addFile( $strFileFrom, $strFile );
01124 
01125                 if( CorujaFileManipulation::isRelativePath( $strFile ) )
01126                 {
01127                         $strFullFile = $this->fixFileName( $strFileFrom, $strFile );
01128                 }
01129                 else
01130                 {
01131                         $strFullFile = $strFile;
01132                 }
01133 
01134                 if( ! file_exists( $strFullFile ) )
01135                 {
01136                         throw new CodeToDiagramException( "Unable to find file: " . $strFullFile );
01137                 }
01138 
01139                 $strContentFile = file_get_contents( $strFullFile );
01140                 $strContentFile = $this->convertFileContent( $strContentFile , $strFile , $strFullFile );
01141                 $this->codeInstrumentationFile( $strFile, $strContentFile );
01142                 
01143                 return $this;
01144         }
01145 
01151         public function setCallerPathByFile( $strCallerFile )
01152         {
01153                 $this->setCallerPath( CorujaFileManipulation::getPathOfFile( $strCallerFile ) );
01154         }
01155 
01163         public function addNote( $strNoteContent , $booAfter = true )
01164         {
01165             $objNote = new UmlSequenceDiagramNote();
01166             $objNote->setContent( $strNoteContent );
01167             $objMessage = CodeInstrumentationReceiver::getInstance()->getActualMessage();
01168             $objActor =  CodeInstrumentationReceiver::getInstance()->getActualActor();
01169             $objNote->setActor( $objActor );
01170             
01171             if( $booAfter )
01172             {
01173                 $objMessage->addNoteAfter($objNote);
01174             }
01175             else
01176             {
01177                 $objMessage->addNoteBefore( $objNote );
01178             }
01179             return $objNote;
01180         }
01181 
01182         public function __call( $strMethod , $arrArguments )
01183         {
01184             throw new CodeToDiagramException( "unknow method " . $strMethod . " in " . get_class( $this ) );
01185         }
01186 }
01187 
01188 ?>

Generated on Thu Feb 3 03:54:59 2011 for CodeToDiagram by  doxygen 1.5.9