@@ -132,13 +132,48 @@ public function getModuleFilePath()
132132 }
133133
134134 /**
135- * Check whether this module is configurable
135+ * Check whether this module is configurable.
136136 *
137- * @return bool
137+ * When the key "configurable" is set in module.ini, its value is used.
138+ * Otherwise, auto-detection checks the form ConfigForm or the content of
139+ * method getConfigForm() via reflection.
138140 */
139- public function isConfigurable ()
141+ public function isConfigurable (): bool
140142 {
141- return (bool ) $ this ->getIni ('configurable ' );
143+ $ configurable = $ this ->getIni ('configurable ' );
144+ if ($ configurable !== null ) {
145+ return (bool ) $ configurable ;
146+ }
147+
148+ $ moduleFilePath = $ this ->getModuleFilePath ();
149+ if (!$ moduleFilePath ) {
150+ return false ;
151+ }
152+
153+ // Check ConfigForm.
154+ $ moduleDir = dirname ($ moduleFilePath );
155+ if (file_exists ($ moduleDir . '/src/Form/ConfigForm.php ' )) {
156+ return true ;
157+ }
158+
159+ // Check method in module via Reflection.
160+ $ moduleClass = $ this ->getId () . '\Module ' ;
161+ if (class_exists ($ moduleClass , false )) {
162+ try {
163+ $ ref = new \ReflectionMethod ($ moduleClass , 'getConfigForm ' );
164+ return $ ref ->getFileName () === realpath ($ moduleFilePath );
165+ } catch (\ReflectionException $ e ) {
166+ return false ;
167+ }
168+ }
169+
170+ // Check method in module via file when not active.
171+ if (file_exists ($ moduleFilePath )) {
172+ $ source = file_get_contents ($ moduleFilePath );
173+ return (bool ) preg_match ('/function\s+getConfigForm\s*\(/ ' , $ source );
174+ }
175+
176+ return false ;
142177 }
143178
144179 /**
0 commit comments