Skip to content

Commit 9497e17

Browse files
committed
- Fixed a bug that class names starting with t could not be loaded properly due to escape characters.
- Refactored code. Implemented an interface. Implemented traits.
1 parent 28c89e1 commit 9497e17

File tree

11 files changed

+855
-708
lines changed

11 files changed

+855
-708
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Added some public methods.
99
- Changed the `exclude_file_names` search option to be a substring of a base name instead of the whole base name without file extension.
1010
- Supported no namespace classes.
11+
- Fixed a bug that class names starting with t could not properly load due to escape characters.
1112

1213
## 1.0.1 - 2020/01/20
1314
- Fixed a composer configuration error with a namespace.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
4+
namespace PHPClassMapGenerator\FileSystem;
5+
6+
use PHPClassMapGenerator\Utility\traitPath;
7+
8+
class FileListGenerator {
9+
10+
use traitFileSearch;
11+
use traitPath;
12+
13+
public $aDirPaths = '';
14+
public $aSearchOptions = [];
15+
16+
/**
17+
* FileListGenerator constructor.
18+
* @param array|string $asDirPaths
19+
* @param array $aSearchOptions
20+
*/
21+
public function __construct( $asDirPaths, array $aSearchOptions ) {
22+
$this->aDirPaths = is_array( $asDirPaths ) ? $asDirPaths : array( $asDirPaths );
23+
$this->aSearchOptions = $aSearchOptions;
24+
}
25+
26+
/**
27+
* @return array
28+
*/
29+
public function get() {
30+
$_aFiles = array();
31+
foreach( $this->aDirPaths as $_sDirPath ) {
32+
$_aFilesPerDir = $this->___getPerDir( $_sDirPath );
33+
$_aFiles = array_merge( $_aFilesPerDir, $_aFiles );
34+
}
35+
return array_unique( $_aFiles );
36+
}
37+
/**
38+
* Returns an array of scanned file path.
39+
*
40+
* The returning array structure looks like this:
41+
* array
42+
* 0 => string '.../class/MyClass.php'
43+
* 1 => string '.../class/MyClass2.php'
44+
* 2 => string '.../class/MyClass3.php'
45+
* ...
46+
* @param string
47+
* @return array
48+
*/
49+
private function ___getPerDir( $sDirPath ) {
50+
51+
$sDirPath = rtrim( $sDirPath, '\\/' ) . DIRECTORY_SEPARATOR; // ensures the trailing (back/)slash exists.
52+
$_aExcludingDirPaths = $this->_getPathsFormatted( $this->aSearchOptions[ 'exclude_dir_paths' ] );
53+
54+
if ( defined( 'GLOB_BRACE' ) ) { // in some OSes this flag constant is not available.
55+
$_sFileExtensionPattern = $this->_getGlobPatternExtensionPart( $this->aSearchOptions[ 'allowed_extensions' ] );
56+
$_aFilePaths = $this->aSearchOptions[ 'is_recursive' ]
57+
? $this->_doRecursiveGlob(
58+
$sDirPath . '*.' . $_sFileExtensionPattern,
59+
GLOB_BRACE,
60+
$_aExcludingDirPaths,
61+
( array ) $this->aSearchOptions[ 'exclude_dir_names' ],
62+
( array ) $this->aSearchOptions[ 'exclude_file_names' ],
63+
( array ) $this->aSearchOptions[ 'ignore_note_file_names' ],
64+
( array ) $this->aSearchOptions[ 'exclude_substrings' ]
65+
)
66+
: ( array ) glob( $sDirPath . '*.' . $_sFileExtensionPattern, GLOB_BRACE );
67+
return array_filter( $_aFilePaths ); // drop non-value elements.
68+
}
69+
70+
// For the Solaris operation system.
71+
$_aFilePaths = array();
72+
foreach( $this->aSearchOptions[ 'allowed_extensions' ] as $__sAllowedExtension ) {
73+
$__aFilePaths = $this->aSearchOptions[ 'is_recursive' ]
74+
? $this->_doRecursiveGlob(
75+
$sDirPath . '*.' . $__sAllowedExtension,
76+
0,
77+
$_aExcludingDirPaths,
78+
( array ) $this->aSearchOptions[ 'exclude_dir_names' ],
79+
( array ) $this->aSearchOptions[ 'exclude_file_names' ],
80+
( array ) $this->aSearchOptions[ 'ignore_note_file_names' ],
81+
( array ) $this->aSearchOptions[ 'exclude_substrings' ]
82+
)
83+
: ( array ) glob( $sDirPath . '*.' . $__sAllowedExtension );
84+
$_aFilePaths = array_merge( $__aFilePaths, $_aFilePaths );
85+
}
86+
return array_unique( array_filter( $_aFilePaths ) );
87+
88+
}
89+
90+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
4+
namespace PHPClassMapGenerator\FileSystem;
5+
6+
7+
trait traitFileSearch {
8+
9+
/**
10+
* The recursive version of the glob() function.
11+
*/
12+
protected function _doRecursiveGlob( $sPathPatten, $nFlags=0, array $aExcludeDirPaths=array(), array $aExcludeDirNames=array(), array $aExcludeFileNames=array(), array $aIgnoreNotes=array(), array $aExcludedSubstrings=array() ) {
13+
14+
if ( $this->___fileExists( $aIgnoreNotes, dirname( $sPathPatten ) . '/' ) ) {
15+
return array();
16+
}
17+
18+
$_aFiles = $this->___getFilesByGlob( $sPathPatten, $nFlags, $aExcludeFileNames, $aExcludedSubstrings );
19+
$_aDirs = glob(dirname( $sPathPatten ) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR|GLOB_NOSORT );
20+
$_aDirs = is_array( $_aDirs ) ? $_aDirs : array();
21+
foreach ( $_aDirs as $_sDirPath ) {
22+
$_sDirPath = $this->_getPathFormatted( $_sDirPath );
23+
if ( in_array( $_sDirPath, $aExcludeDirPaths ) ) {
24+
continue;
25+
}
26+
if ( in_array( pathinfo( $_sDirPath, PATHINFO_BASENAME ), $aExcludeDirNames ) ) {
27+
continue;
28+
}
29+
$_aFiles = array_merge(
30+
$_aFiles,
31+
$this->_doRecursiveGlob(
32+
$_sDirPath . DIRECTORY_SEPARATOR . basename( $sPathPatten ),
33+
$nFlags,
34+
$aExcludeDirPaths,
35+
$aExcludeDirNames,
36+
$aExcludeFileNames,
37+
$aIgnoreNotes,
38+
$aExcludedSubstrings
39+
)
40+
);
41+
42+
}
43+
return $_aFiles;
44+
45+
}
46+
/**
47+
* Checks whether a file exists.
48+
*
49+
* @remark Checks all the paths given as array members and at least one of them exists, the method returns true.
50+
* @param array $aFilePaths
51+
* @param string $sSuffix The path suffix to prepend to the path set in the array.
52+
* @return bool
53+
*/
54+
private function ___fileExists( array $aFilePaths, $sSuffix='' ) {
55+
foreach( $aFilePaths as $_sFilePath ) {
56+
if ( file_exists( $sSuffix . $_sFilePath ) ) {
57+
return true;
58+
}
59+
}
60+
return false;
61+
}
62+
63+
/**
64+
* @param $sPathPatten
65+
* @param $nFlags
66+
* @param array $aExcludeFileNames
67+
* @param array $aExcludedSubstrings
68+
* @return array
69+
*/
70+
private function ___getFilesByGlob( $sPathPatten, $nFlags, array $aExcludeFileNames, array $aExcludedSubstrings ) {
71+
72+
$_aFiles = glob( $sPathPatten, $nFlags );
73+
$_aFiles = is_array( $_aFiles ) ? $_aFiles : array(); // glob() can return false.
74+
$_aFiles = array_map( array( $this, '_getPathFormatted' ), $_aFiles );
75+
$_aFiles = $this->___dropExcludingFiles( $_aFiles, $aExcludeFileNames, $aExcludedSubstrings );
76+
return $_aFiles;
77+
78+
}
79+
/**
80+
* Removes files from the generated list that is set in the 'exclude_file_names' argument of the searh option array.
81+
* @since 1.0.6
82+
* @param array $aFiles
83+
* @param array $aExcludingFileNames
84+
* @param array $aExcludedSubstrings
85+
* @return array
86+
*/
87+
private function ___dropExcludingFiles( array $aFiles, array $aExcludingFileNames=array(), array $aExcludedSubstrings=array() ) {
88+
89+
if ( empty( $aExcludingFileNames ) && empty( $aExcludedSubstrings ) ) {
90+
return $aFiles;
91+
}
92+
foreach( $aFiles as $_iIndex => $_sPath ) {
93+
$_sBaseFileName = basename( $_sPath );
94+
if ( $this->___hasSubstring( $_sBaseFileName, $aExcludingFileNames ) ) {
95+
unset( $aFiles[ $_iIndex ] );
96+
continue;
97+
}
98+
if ( $this->___hasSubstring( $_sPath, $aExcludedSubstrings ) ) {
99+
unset( $aFiles[ $_iIndex ] );
100+
continue;
101+
}
102+
}
103+
return $aFiles;
104+
105+
}
106+
/**
107+
*
108+
* @param $sString
109+
* @param array $aNeedles
110+
* @return boolean `true` if at lease one match is found. `false` if none of the needles match.
111+
*/
112+
private function ___hasSubstring( $sString, array $aNeedles ) {
113+
foreach( $aNeedles as $_sNeedle ) {
114+
if ( false !== strpos( $sString, $_sNeedle ) ) {
115+
return true;
116+
}
117+
}
118+
return false;
119+
}
120+
121+
122+
123+
/**
124+
* Constructs the file pattern of the file extension part used for the glob() function with the given file extensions.
125+
* @param array $aExtensions
126+
* @return string
127+
*/
128+
protected function _getGlobPatternExtensionPart( array $aExtensions=array( 'php', 'inc' ) ) {
129+
return empty( $aExtensions )
130+
? '*'
131+
: '{' . implode( ',', $aExtensions ) . '}';
132+
}
133+
134+
135+
}

source/Header/HeaderGenerator.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
4+
namespace PHPClassMapGenerator\Header;
5+
6+
use PHPClassMapGenerator\Utility\traitCodeParser;
7+
8+
class HeaderGenerator {
9+
10+
use traitCodeParser;
11+
12+
public $aItems = array();
13+
public $aOptions = array();
14+
15+
/**
16+
* HeaderGenerator constructor.
17+
* @param array $aItems
18+
* @param array $aOptions
19+
*/
20+
public function __construct( array $aItems, array $aOptions ) {
21+
22+
$this->aItems = $aItems;
23+
$this->aOptions = $aOptions;
24+
25+
}
26+
27+
/**
28+
*
29+
* @return string
30+
* @throws \ReflectionException
31+
*/
32+
public function get() {
33+
return $this->___getProjectHeaderComment( $this->aItems, $this->aOptions );
34+
}
35+
/**
36+
* Generates the heading comment from the given path or class name.
37+
* @param array $aItems
38+
* @param array $aOptions
39+
* @throws \ReflectionException
40+
* @return string
41+
*/
42+
private function ___getProjectHeaderComment( array $aItems, array $aOptions ) {
43+
44+
if ( $aOptions[ 'header_class_path' ] && $aOptions[ 'header_class_name' ] ) {
45+
return $this->___getProjectHeaderCommentGenerated(
46+
$aOptions[ 'header_class_path' ],
47+
$aOptions[ 'header_class_name' ],
48+
$aOptions[ 'header_type' ]
49+
);
50+
}
51+
52+
if ( $aOptions[' header_class_name' ] ) {
53+
return $this->___getProjectHeaderCommentGenerated(
54+
isset( $aItems[ $aOptions[ 'header_class_name' ] ] )
55+
? $aItems[ $aOptions['header_class_name'] ][ 'path' ]
56+
: $aOptions[ 'header_class_path' ],
57+
$aOptions[ 'header_class_name' ],
58+
$aOptions[ 'header_type' ]
59+
);
60+
}
61+
62+
if ( $aOptions[ 'header_class_path' ] ) {
63+
$_aConstructs = $this->_getDefinedObjectConstructs( '<?php ' . $this->_getPHPCode( $aOptions[ 'header_class_path' ] ) );
64+
$_aDefinedClasses = $_aConstructs[ 'classes' ];
65+
$_sHeaderClassName = isset( $_aDefinedClasses[ 0 ] ) ? $_aDefinedClasses[ 0 ] : '';
66+
return $this->___getProjectHeaderCommentGenerated(
67+
$aOptions[ 'header_class_path' ],
68+
$_sHeaderClassName,
69+
$aOptions[ 'header_type' ]
70+
);
71+
}
72+
73+
return '';
74+
75+
}
76+
/**
77+
* Generates the script heading comment.
78+
* @throws \ReflectionException
79+
* @param string $sFilePath
80+
* @param string $sClassName
81+
* @param string $sHeaderType
82+
* @return string
83+
*/
84+
private function ___getProjectHeaderCommentGenerated( $sFilePath, $sClassName, $sHeaderType='DOCKBLOCK' ) {
85+
86+
if ( ! file_exists( $sFilePath ) ) {
87+
return '';
88+
}
89+
if ( ! $sClassName ) {
90+
return '';
91+
}
92+
93+
include_once( $sFilePath );
94+
$_aDeclaredClasses = ( array ) get_declared_classes();
95+
foreach( $_aDeclaredClasses as $_sClassName ) {
96+
if ( $sClassName !== $_sClassName ) {
97+
continue;
98+
}
99+
return 'DOCBLOCK' === $sHeaderType
100+
? $this->_getClassDocBlock( $_sClassName )
101+
: $this->___generateHeaderComment( $_sClassName );
102+
}
103+
return '';
104+
105+
}
106+
107+
/**
108+
* Generates the heading comments from the class constants.
109+
* @throws \ReflectionException
110+
* @param string $sClassName
111+
* @return string
112+
*/
113+
private function ___generateHeaderComment( $sClassName ) {
114+
115+
$_oRC = new \ReflectionClass( $sClassName );
116+
$_aConstants = $_oRC->getConstants();
117+
$_aConstants = array_change_key_case( $_aConstants, CASE_UPPER ) + array(
118+
'NAME' => '', 'VERSION' => '', 'DESCRIPTION' => '',
119+
'URI' => '', 'AUTHOR' => '', 'AUTHOR_URI' => '',
120+
'COPYRIGHT' => '', 'LICENSE' => '', 'CONTRIBUTORS' => '',
121+
);
122+
$_aOutputs = array();
123+
$_aOutputs[] = '/**';
124+
$_aOutputs[] = ( $_aConstants[ 'NAME' ] ? " " . $_aConstants[ 'NAME' ] . ' ' : '' )
125+
. ( $_aConstants[ 'VERSION' ] ? 'v' . $_aConstants[ 'VERSION' ] . ' ' : '' )
126+
. ( $_aConstants[ 'AUTHOR' ] ? 'by ' . $_aConstants[ 'AUTHOR' ] . ' ' : '' );
127+
$_aOutputs[] = $_aConstants[ 'DESCRIPTION' ] ? " ". $_aConstants[ 'DESCRIPTION' ] : '';
128+
$_aOutputs[] = $_aConstants[ 'URI' ] ? " ". '<' . $_aConstants[ 'URI' ] . '>' : '';
129+
$_aOutputs[] = ( $_aConstants[ 'COPYRIGHT' ] ? " " . $_aConstants[ 'COPYRIGHT' ] : '' )
130+
. ( $_aConstants[ 'LICENSE' ] ? '; Licensed under ' . $_aConstants[ 'LICENSE' ] : '' );
131+
$_aOutputs[] = ' */';
132+
return implode( PHP_EOL, array_filter( $_aOutputs ) ) . PHP_EOL;
133+
}
134+
135+
}

0 commit comments

Comments
 (0)