66use Doctrine \Common \Persistence \Mapping \Driver \MappingDriver ;
77use Doctrine \ORM \Mapping \Builder \ClassMetadataBuilder ;
88use Doctrine \ORM \Mapping \MappingException ;
9+ use FilesystemIterator ;
910use InvalidArgumentException ;
1011use LaravelDoctrine \Fluent \Builders \Builder ;
1112use LaravelDoctrine \Fluent \Mappers \MapperSet ;
13+ use RecursiveDirectoryIterator ;
14+ use RecursiveIteratorIterator ;
15+ use RecursiveRegexIterator ;
16+ use ReflectionClass ;
17+ use RegexIterator ;
1218
1319class FluentDriver implements MappingDriver
1420{
@@ -22,20 +28,37 @@ class FluentDriver implements MappingDriver
2228 */
2329 protected $ fluentFactory ;
2430
31+ /**
32+ * The file extension of mapping documents.
33+ *
34+ * @var string
35+ */
36+ protected $ fileExtension = '.php ' ;
37+
2538 /**
2639 * Initializes a new FileDriver that looks in the given path(s) for mapping
2740 * documents and operates in the specified operating mode.
2841 *
2942 * @param string[] $mappings
43+ * @param array $paths
44+ *
45+ * @throws MappingException
3046 */
31- public function __construct (array $ mappings = [])
47+ public function __construct (array $ mappings = [], array $ paths = [] )
3248 {
3349 $ this ->fluentFactory = function (ClassMetadata $ metadata ) {
3450 return new Builder (new ClassMetadataBuilder ($ metadata ));
3551 };
3652
3753 $ this ->mappers = new MapperSet ();
38- $ this ->addMappings ($ mappings );
54+
55+ if (!empty ($ paths )) {
56+ $ this ->loadPaths ($ paths );
57+ }
58+
59+ if (!empty ($ mappings )) {
60+ $ this ->addMappings ($ mappings );
61+ }
3962 }
4063
4164 /**
@@ -78,8 +101,75 @@ public function isTransient($className)
78101 $ this ->mappers ->getMapperFor ($ className )->isTransient ();
79102 }
80103
104+ /**
105+ * @param array $paths
106+ *
107+ * @throws MappingException
108+ */
109+ public function loadPaths (array $ paths )
110+ {
111+ $ classes = [];
112+ $ includedFiles = [];
113+
114+ foreach ($ paths as $ path ) {
115+ if (!is_dir ($ path )) {
116+ throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath ($ path );
117+ }
118+
119+ $ iterator = new RegexIterator (
120+ new RecursiveIteratorIterator (
121+ new RecursiveDirectoryIterator ($ path , FilesystemIterator::SKIP_DOTS ),
122+ RecursiveIteratorIterator::LEAVES_ONLY
123+ ),
124+ '/^.+ ' .preg_quote ($ this ->fileExtension ).'$/i ' ,
125+ RecursiveRegexIterator::GET_MATCH
126+ );
127+
128+ foreach ($ iterator as $ file ) {
129+ $ sourceFile = $ file [0 ];
130+
131+ if (!preg_match ('(^phar:)i ' , $ sourceFile )) {
132+ $ sourceFile = realpath ($ sourceFile );
133+ }
134+
135+ require_once $ sourceFile ;
136+
137+ $ includedFiles [] = $ sourceFile ;
138+ }
139+
140+ $ declared = get_declared_classes ();
141+
142+ foreach ($ declared as $ className ) {
143+ $ rc = new ReflectionClass ($ className );
144+ $ sourceFile = $ rc ->getFileName ();
145+
146+ if (!in_array ($ sourceFile , $ includedFiles )) {
147+ continue ;
148+ }
149+
150+ if ($ rc ->isAbstract () || $ rc ->isInterface ()) {
151+ continue ;
152+ }
153+
154+ if (!$ rc ->implementsInterface (Mapping::class)) {
155+ continue ;
156+ }
157+
158+ if ($ this ->isTransient ($ className )) {
159+
160+ /** @var Mapping $mapping */
161+ $ mapping = $ rc ->newInstanceWithoutConstructor ();
162+
163+ $ this ->addMapping ($ mapping );
164+ }
165+ }
166+ }
167+ }
168+
81169 /**
82170 * @param string[] $mappings
171+ *
172+ * @throws InvalidArgumentException
83173 */
84174 public function addMappings (array $ mappings = [])
85175 {
0 commit comments