Passed
Push — master ( a1bf27...3a2d72 )
by Jens
04:20
created

ComposerScripts::calculateRelativePath()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nc 4
nop 3
dl 0
loc 21
rs 9.0534
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by jensk on 27-3-2018.
4
 */
5
6
namespace CloudControl\Cms\cc;
7
8
use CloudControl\Cms\storage\Cache;
9
use CloudControl\Cms\storage\Repository;
10
use Composer\Script\Event;
11
12
class ComposerScripts
13
{
14
    /**
15
     * @param Event $event
16
     * @throws \Exception
17
     */
18
    public static function postInstall($event)
19
    {
20
        $event->getIO()->write("Post install");
21
        self::checkInstall($event);
22
    }
23
24
    /**
25
     * @param Event $event
26
     * @throws \Exception
27
     */
28
    public static function postUpdate($event)
29
    {
30
        $event->getIO()->write("Post update");
31
        self::checkInstall($event);
32
    }
33
34
    /**
35
     * @param Event $event
36
     * @throws \Exception
37
     */
38
    private static function checkInstall($event)
39
    {
40
        $event->getIO()->write('');
41
        $event->getIO()->write('********************************************************');
42
        $event->getIO()->write('*** Checking installation of Cloud Control framework ***');
43
        $event->getIO()->write('********************************************************');
44
        $event->getIO()->write('');
45
46
        $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
47
        $rootDir = realpath($vendorDir . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
48
49
        $baseConfigTargetPath = $rootDir . DIRECTORY_SEPARATOR . 'config.json';
50
        $configObject = self::getConfig($event, $baseConfigTargetPath);
51
52
        $configObject->{'templateDir'} = self::createDir($event, $rootDir, 'templates');
53
        $configObject->{'storageDir'} = self::createDir($event, $rootDir, $configObject->{'storageDir'});
54
        $configObject->{'publicDir'} = self::createDir($event, $rootDir, 'public');
55
        $configObject->{'jsDir'} = self::createDir($event, $rootDir, $configObject->{'publicDir'} . 'js');
56
        $configObject->{'cssDir'} = self::createDir($event, $rootDir, $configObject->{'publicDir'} . 'css');
57
        $configObject->{'imagesDir'} = self::createDir($event, $rootDir, $configObject->{'publicDir'} . 'images');
58
        $configObject->{'filesDir'} = self::createDir($event, $rootDir, $configObject->{'publicDir'} . 'files');
59
        $componentsDir = self::createDir($event, $rootDir, 'components');
60
61
        $baseStorageDefaultPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . '_storage.json';
62
        $baseStorageSqlPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . '_storage.sql';
63
        $baseCacheSqlPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . '_cache.sql';
64
65
        self::createStorage($configObject->{'storageDir'}, $baseStorageDefaultPath, $baseStorageSqlPath);
66
        self::createCacheStorage($rootDir . DIRECTORY_SEPARATOR . $configObject->{'storageDir'}, $baseCacheSqlPath);
67
        self::saveConfig($event, $baseConfigTargetPath, $configObject);
68
        self::copyInstallFile($event, 'public.htaccess', $configObject->{'publicDir'}, '.htaccess');
69
        self::copyInstallFile($event, 'root.htaccess', $rootDir, '.htaccess');
70
        self::copyInstallFile($event, 'base.php', $configObject->{'templateDir'});
71
        self::copyInstallFile($event, 'cms.css', $configObject->{'cssDir'});
72
        self::copyInstallFile($event, 'cms.js', $configObject->{'jsDir'});
73
        self::copyInstallFile($event, 'index.php', $configObject->{'publicDir'});
74
        self::copyInstallFile($event, 'CustomComponent.php', $componentsDir);
75
76
        $event->getIO()->write("");
77
        $event->getIO()->write("[SUCCESS] Installation is complete");
78
        $event->getIO()->write("");
79
    }
80
81
    /**
82
     * @param Event $event
83
     * @param $baseConfigTargetPath
84
     * @param $configObject
85
     */
86
    private static function saveConfig($event, $baseConfigTargetPath, $configObject)
87
    {
88
        file_put_contents($baseConfigTargetPath, json_encode($configObject));
89
        $event->getIO()->write("[INFO] Saved config to: " . $baseConfigTargetPath);
90
    }
91
92
    /**
93
     * @param Event $event
94
     * @param $sourceFileName
95
     * @param $destinationPath
96
     * @param string $destinationFileName
97
     */
98
    private static function copyInstallFile($event, $sourceFileName, $destinationPath, $destinationFileName = null)
99
    {
100
        $sourceFilePath = realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'install/_' . $sourceFileName);
101
102
103
        if ($destinationFileName === null) {
104
            $destinationFileName = $sourceFileName;
105
        }
106
107
        if (file_exists($sourceFilePath) && realpath($destinationPath) !== false) {
108
            $destinationFullPath = realpath($destinationPath) . DIRECTORY_SEPARATOR . $destinationFileName;
109
            if (file_exists($destinationFullPath)) {
110
                $event->getIO()->write("[INFO] File already exists: " . $destinationFullPath);
111
            } else {
112
                copy($sourceFilePath, $destinationFullPath);
113
                $event->getIO()->write("[INSTALL] Copied file: " . $sourceFileName . ' to ' . $destinationPath);
114
            }
115
        } else {
116
            $event->getIO()->write("[ERROR] Couldnt copy file: " . $sourceFileName . ' to ' . $destinationPath);
117
        }
118
    }
119
120
    /**
121
     * @param $storageDir
122
     * @param $baseStorageDefaultPath
123
     * @param $baseStorageSqlPath
124
     * @throws \Exception
125
     */
126
    private static function createStorage($storageDir, $baseStorageDefaultPath, $baseStorageSqlPath)
127
    {
128
        $repository = new Repository($storageDir);
129
        $repository->init($baseStorageDefaultPath, $baseStorageSqlPath);
130
    }
131
132
    /**
133
     * @param Event $event
134
     * @param $rootDir
135
     * @param $dirName
136
     * @return string
137
     */
138
    private static function createDir($event, $rootDir, $dirName)
139
    {
140
        $dir = $rootDir . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR;
141
        if (!is_dir($dir)) {
142
            if (!mkdir($dir) && !is_dir($dir)) {
143
                throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir));
144
            }
145
            $event->getIO()->write("[INSTALL] Created dir: " . $dir);
146
        } else {
147
            $event->getIO()->write("[INFO] Dir already exists: " . $dir);
148
        }
149
        return self::getRelativePath($rootDir, $dir);
150
    }
151
152
    /**
153
     * @param Event $event
154
     * @param $configTargetPath
155
     * @return mixed
156
     */
157
    private static function getConfig($event, $configTargetPath)
158
    {
159
        $baseConfigDefaultPath = realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . '_config.json');
160
161
        if (file_exists($configTargetPath)) {
162
            $config = json_decode(file_get_contents($configTargetPath));
163
            $event->getIO()->write("[INFO] Using existing config");
164
        } else {
165
            $config = json_decode(file_get_contents($baseConfigDefaultPath));
166
            $event->getIO()->write("[INSTALL] Created default config");
167
        }
168
        return $config;
169
    }
170
171
    /**
172
     * @param $storageDir
173
     * @param $baseCacheSqlPath
174
     */
175
    private static function createCacheStorage($storageDir, $baseCacheSqlPath)
176
    {
177
        Cache::getInstance()->setStoragePath($storageDir);
178
        Cache::getInstance()->init($baseCacheSqlPath);
179
    }
180
181
    /**
182
     * Calculate the relative path from $from to $to
183
     * Derived from https://stackoverflow.com/a/2638272/
184
     *
185
     * @param $from
186
     * @param $to
187
     * @return string
188
     */
189
    private static function getRelativePath($from, $to)
190
    {
191
        // some compatibility fixes for Windows paths
192
        $from = is_dir($from) ? rtrim($from, '\/') . DIRECTORY_SEPARATOR : $from;
193
        $to = is_dir($to) ? rtrim($to, '\/') . DIRECTORY_SEPARATOR : $to;
194
        $from = str_replace('\\', DIRECTORY_SEPARATOR, $from);
195
        $to = str_replace('\\', DIRECTORY_SEPARATOR, $to);
196
197
        $from = explode(DIRECTORY_SEPARATOR, $from);
198
        $to = explode(DIRECTORY_SEPARATOR, $to);
199
        $relPath = $to;
200
201
        $relPath = self::calculateRelativePath($from, $to, $relPath);
202
        $relPath = implode(DIRECTORY_SEPARATOR, $relPath);
203
        $relPath = self::removePointerToCurrentDir($relPath);
204
        return $relPath;
205
    }
206
207
    /**
208
     * @param $relPath
209
     * @return mixed
210
     */
211
    private static function removePointerToCurrentDir($relPath)
212
    {
213
        while (strpos($relPath, '.' . DIRECTORY_SEPARATOR . '.' . DIRECTORY_SEPARATOR) !== false) {
214
            $relPath = str_replace('.' . DIRECTORY_SEPARATOR . '.' . DIRECTORY_SEPARATOR, '.' . DIRECTORY_SEPARATOR,
215
                $relPath);
216
        }
217
        return $relPath;
218
    }
219
220
    /**
221
     * @param $from
222
     * @param $to
223
     * @param $relPath
224
     * @return array
225
     */
226
    private static function calculateRelativePath($from, $to, $relPath)
227
    {
228
        foreach ($from as $depth => $dir) {
229
            // find first non-matching dir
230
            if ($dir === $to[$depth]) {
231
                // ignore this directory
232
                array_shift($relPath);
233
            } else {
234
                // get number of remaining dirs to $from
235
                $remaining = count($from) - $depth;
236
                if ($remaining > 1) {
237
                    // add traversals up to first matching dir
238
                    $padLength = (count($relPath) + $remaining - 1) * -1;
239
                    $relPath = array_pad($relPath, $padLength, '..');
240
                    break;
241
                } else {
242
                    $relPath[0] = '.' . DIRECTORY_SEPARATOR . $relPath[0];
243
                }
244
            }
245
        }
246
        return $relPath;
247
    }
248
}