36
36
use Symfony \Component \DependencyInjection \ContainerInterface ;
37
37
use Symfony \Component \DependencyInjection \Exception \ServiceCircularReferenceException ;
38
38
use Symfony \Component \DependencyInjection \Exception \ServiceNotFoundException ;
39
+ use Symfony \Component \Filesystem \Filesystem as SfFileSystem ;
39
40
use Symfony \Component \Finder \Finder ;
40
41
41
42
abstract class ModuleCore implements ModuleInterface
@@ -2787,12 +2788,18 @@ public function addOverride($classname)
2787
2788
file_put_contents ($ path_override , preg_replace ('#(\r\n|\r)#ism ' , "\n" , file_get_contents ($ path_override )));
2788
2789
}
2789
2790
2791
+ $ psOverrideDir = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'override ' ;
2792
+
2790
2793
$ pattern_escape_com = '#(^\s*?\/\/.*?\n|\/\*(?!\n\s+\* module:.*?\* date:.*?\* version:.*?\*\/).*?\*\/)#ism ' ;
2791
2794
// Check if there is already an override file, if not, we just need to copy the file
2792
- if ($ file = PrestaShopAutoload::getInstance ()->getClassPath ($ classname )) {
2793
- // Check if override file is writable
2794
- $ override_path = _PS_ROOT_DIR_ . '/ ' . $ file ;
2795
+ $ file = PrestaShopAutoload::getInstance ()->getClassPath ($ classname );
2796
+ $ override_path = _PS_ROOT_DIR_ . '/ ' . $ file ;
2795
2797
2798
+ if ($ file && file_exists ($ override_path )) {
2799
+ // Create directory if not exists
2800
+ $ this ->createOverrideDirectory ($ psOverrideDir , dirname ($ override_path ));
2801
+
2802
+ // Check if override file is writable
2796
2803
if ((!file_exists ($ override_path ) && !is_writable (dirname ($ override_path ))) || (file_exists ($ override_path ) && !is_writable ($ override_path ))) {
2797
2804
throw new Exception (Context::getContext ()->getTranslator ()->trans ('file (%s) not writable ' , [$ override_path ], 'Admin.Notifications.Error ' ));
2798
2805
}
@@ -2866,6 +2873,7 @@ public function addOverride($classname)
2866
2873
}
2867
2874
}
2868
2875
2876
+ // Check if none of the constants already exists in the override class
2869
2877
foreach ($ module_class ->getConstants () as $ constant => $ value ) {
2870
2878
if ($ override_class ->hasConstant ($ constant )) {
2871
2879
throw new Exception (Context::getContext ()->getTranslator ()->trans ('The constant %1$s in the class %2$s is already defined. ' , [$ constant , $ classname ], 'Admin.Modules.Notification ' ));
@@ -2886,12 +2894,11 @@ public function addOverride($classname)
2886
2894
} else {
2887
2895
$ override_src = $ path_override ;
2888
2896
2889
- $ override_dest = _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . ' override ' . DIRECTORY_SEPARATOR . $ path ;
2897
+ $ override_dest = $ psOverrideDir . DIRECTORY_SEPARATOR . $ path ;
2890
2898
$ dir_name = dirname ($ override_dest );
2891
2899
2892
- if (!$ orig_path && !is_dir ($ dir_name )) {
2893
- @mkdir ($ dir_name , FileSystem::DEFAULT_MODE_FOLDER );
2894
- }
2900
+ // Create directory if not exists
2901
+ $ this ->createOverrideDirectory ($ psOverrideDir , $ dir_name );
2895
2902
2896
2903
if (!is_writable ($ dir_name )) {
2897
2904
throw new Exception (Context::getContext ()->getTranslator ()->trans ('directory (%s) not writable ' , [$ dir_name ], 'Admin.Notifications.Error ' ));
@@ -2952,6 +2959,38 @@ public function addOverride($classname)
2952
2959
return true ;
2953
2960
}
2954
2961
2962
+ /**
2963
+ * Create override directory and add index.php in all tree
2964
+ *
2965
+ * @param string $directoryOverride Absolute path of the override directory
2966
+ * @param string $directoryPath Absolute path of the overriden file directory
2967
+ *
2968
+ * @return void
2969
+ */
2970
+ private function createOverrideDirectory (string $ directoryOverride , string $ directoryPath ): void
2971
+ {
2972
+ if (is_dir ($ directoryPath )) {
2973
+ return ;
2974
+ }
2975
+ $ fs = new SfFileSystem ();
2976
+
2977
+ // Create directory (in recursive mode)
2978
+ $ fs ->mkdir ($ directoryPath , FileSystem::DEFAULT_MODE_FOLDER );
2979
+
2980
+ // Copy index.php to each directory
2981
+ $ splDir = new SplFileInfo ($ directoryPath . DIRECTORY_SEPARATOR . 'index.php ' );
2982
+ do {
2983
+ // Copy file
2984
+ $ fs ->copy (
2985
+ $ directoryOverride . DIRECTORY_SEPARATOR . 'index.php ' ,
2986
+ $ splDir ->getPath () . DIRECTORY_SEPARATOR . 'index.php '
2987
+ );
2988
+
2989
+ // Get Parent directory
2990
+ $ splDir = $ splDir ->getPathInfo ();
2991
+ } while ($ splDir ->getPath () !== $ directoryOverride );
2992
+ }
2993
+
2955
2994
/**
2956
2995
* Remove all methods in a module override from the override class.
2957
2996
*
@@ -3038,7 +3077,6 @@ public function removeOverride($classname)
3038
3077
$ length = $ method ->getEndLine () - $ method ->getStartLine () + 1 ;
3039
3078
3040
3079
$ module_method = $ module_class ->getMethod ($ method ->getName ());
3041
- $ module_length = $ module_method ->getEndLine () - $ module_method ->getStartLine () + 1 ;
3042
3080
3043
3081
$ override_file_orig = $ override_file ;
3044
3082
@@ -3121,10 +3159,42 @@ public function removeOverride($classname)
3121
3159
}
3122
3160
3123
3161
$ to_delete = preg_match ('/<\?(?:php)?\s+(?:abstract|interface)?\s*?class\s+ ' . $ classname . '\s+extends\s+ ' . $ classname . 'Core\s*?[{]\s*?[}]/ism ' , $ code );
3162
+
3163
+ if (!$ to_delete ) {
3164
+ // To detect if the class has remaining code, we dynamically create a class which contains the remaining code.
3165
+ eval (
3166
+ preg_replace (
3167
+ [
3168
+ '#^\s*<\?(?:php)?# ' ,
3169
+ '#class\s+ ' . $ classname . '\s+extends\s+([a-z0-9_]+)(\s+implements\s+([a-z0-9_]+))?#i ' ,
3170
+ ],
3171
+ [
3172
+ ' ' ,
3173
+ 'class ' . $ classname . 'OverrideOriginal_check ' . $ uniq . ' extends \stdClass ' ,
3174
+ ],
3175
+ $ code
3176
+ )
3177
+ );
3178
+
3179
+ // Then we use ReflectionClass to analyze what this code actually contains
3180
+ $ override_class = new ReflectionClass ($ classname . 'OverrideOriginal_check ' . $ uniq );
3181
+
3182
+ // If no valuable code remains then we can delete it
3183
+ $ to_delete = $ override_class ->getConstants () === []
3184
+ && $ override_class ->getProperties () === []
3185
+ && $ override_class ->getMethods () === [];
3186
+ }
3124
3187
}
3125
3188
3126
3189
if (!isset ($ to_delete ) || $ to_delete ) {
3190
+ // Remove file
3127
3191
unlink ($ override_path );
3192
+
3193
+ // Remove directory
3194
+ $ this ->removeOverrideDirectory (
3195
+ _PS_ROOT_DIR_ . DIRECTORY_SEPARATOR . 'override ' ,
3196
+ dirname ($ override_path )
3197
+ );
3128
3198
} else {
3129
3199
file_put_contents ($ override_path , $ code );
3130
3200
}
@@ -3135,6 +3205,45 @@ public function removeOverride($classname)
3135
3205
return true ;
3136
3206
}
3137
3207
3208
+ /**
3209
+ * Remove override directory tree if the tree is empty
3210
+ *
3211
+ * @param string $directoryOverride
3212
+ * @param string $directoryPath
3213
+ *
3214
+ * @return void
3215
+ */
3216
+ private function removeOverrideDirectory (string $ directoryOverride , string $ directoryPath ): void
3217
+ {
3218
+ if (!is_dir ($ directoryPath )) {
3219
+ return ;
3220
+ }
3221
+
3222
+ $ fs = new SfFileSystem ();
3223
+
3224
+ $ splDir = new SplFileInfo ($ directoryPath );
3225
+ do {
3226
+ // Check if there is only index.php in directory
3227
+ $ finder = new Finder ();
3228
+ $ finder
3229
+ ->files ()
3230
+ ->in ($ splDir ->getPathname ())
3231
+ ->notName ('index.php ' );
3232
+ if ($ finder ->hasResults ()) {
3233
+ break ;
3234
+ }
3235
+
3236
+ // Remove index.php
3237
+ $ fs ->remove ($ splDir ->getPathname () . DIRECTORY_SEPARATOR . 'index.php ' );
3238
+
3239
+ // Remove directory
3240
+ $ fs ->remove ($ splDir ->getPathname ());
3241
+
3242
+ // Get Parent directory
3243
+ $ splDir = $ splDir ->getPathInfo ();
3244
+ } while ($ splDir ->getPathname () !== $ directoryOverride );
3245
+ }
3246
+
3138
3247
private function getWidgetHooks ()
3139
3248
{
3140
3249
$ hooks = array_values (Hook::getHooks (false , true ));
0 commit comments