ViewComposer::compose()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 3
nc 4
nop 1
1
<?php
2
/**
3
 * @link https://github.com/vuongxuongminh/laravel-view-localization
4
 *
5
 * @copyright (c) Vuong Xuong Minh
6
 * @license [MIT](https://opensource.org/licenses/MIT)
7
 */
8
9
namespace VXM\ViewLocalization;
10
11
use Illuminate\View\View;
12
use InvalidArgumentException;
13
use Illuminate\Filesystem\Filesystem;
14
use Illuminate\Contracts\Foundation\Application;
15
16
/**
17
 * @author Vuong Minh <[email protected]>
18
 * @since  1.0.0
19
 */
20
class ViewComposer
21
{
22
    /**
23
     * Views compose locale by this app locale.
24
     *
25
     * @var Application
26
     */
27
    protected $app;
28
29
    /**
30
     * Application source locale.
31
     *
32
     * @var string
33
     */
34
    protected $sourceLocale;
35
36
    /**
37
     * File system use to searching view path.
38
     *
39
     * @var Filesystem
40
     */
41
    protected $files;
42
43
    /**
44
     * View path locale resolved.
45
     *
46
     * @var array|string[]
47
     */
48
    protected $resolvedPaths = [];
49
50
    /**
51
     * Create new ViewComposer instance.
52
     *
53
     * @param  Application  $app
54
     * @param  string  $sourceLocale
55
     * @param  Filesystem  $files
56
     */
57
    public function __construct(Application $app, string $sourceLocale, Filesystem $files)
58
    {
59
        $this->app = $app;
60
        $this->sourceLocale = $sourceLocale;
61
        $this->files = $files;
62
    }
63
64
    /**
65
     * Compose given View instance.
66
     *
67
     * @param  View  $view
68
     */
69
    public function compose(View $view): void
70
    {
71
        $path = $view->getPath();
72
        $appLocale = $this->app->getLocale();
73
74
        if (isset($this->resolvedPaths[$appLocale][$path])) {
75
            $resolvedPath = $this->resolvedPaths[$appLocale][$path];
76
        } else {
77
            $resolvedPath = $this->resolvePath($view);
78
        }
79
80
        if ($resolvedPath) {
81
            $view->setPath(
82
                $this->resolvedPaths[$appLocale][$path] = $resolvedPath
83
            );
84
        } else {
85
            $this->resolvedPaths[$appLocale][$path] = false;
86
        }
87
    }
88
89
    /**
90
     * Resolve path by user locale.
91
     *
92
     * The searching is based on the specified language code. In particular,
93
     * a file with the same name will be looked for under the subdirectory
94
     * whose name is the same as the language code. For example, given the file "path/to/view.php"
95
     * and language code "zh-CN", the localized file will be looked for as
96
     * "path/to/zh-CN/view.php". If the file is not found, it will try a fallback with just a language code that is
97
     * "zh" i.e. "path/to/zh/view.php". If it is not found as well the original file will be returned.
98
     *
99
     * The implementation of this method referenced FileHelper in Yii2 Framework.
100
     *
101
     * @param  View  $view
102
     * @return string|null
103
     */
104
    protected function resolvePath(View $view): ?string
105
    {
106
        $appLocale = $this->app->getLocale();
107
108
        if ($appLocale === $this->sourceLocale) {
109
            return null;
110
        }
111
112
        if ($path = $this->findSubPath($view, $appLocale)) {
113
            return $path;
114
        }
115
116
        $appLocale = substr($appLocale, 0, 2);
117
118
        if ($appLocale === $this->sourceLocale) {
119
            return null;
120
        }
121
122
        return $this->findSubPath($view, $appLocale);
123
    }
124
125
    /**
126
     * Find sub path.
127
     *
128
     * @param  View  $view
129
     * @param  string  $subDir
130
     * @return string|null
131
     */
132
    protected function findSubPath(View $view, string $subDir): ?string
133
    {
134
        if ($view->getName() !== $view->getPath()) {
135
            return $this->findSubViewPath($view, $subDir);
136
        } else {
137
            return $this->findSubNativePath($view, $subDir);
138
        }
139
    }
140
141
    /**
142
     * Find sub view path.
143
     *
144
     * @param  View  $view
145
     * @param  string  $subDir
146
     * @return string|null
147
     */
148
    protected function findSubViewPath(View $view, string $subDir): ?string
149
    {
150
        $rawPath = str_replace('.', '/', $view->getName());
151
        $base = $this->files->dirname($rawPath);
152
        $name = $this->files->name($rawPath);
153
        $path = ltrim($base.'.'.$subDir.'.'.$name, '.');
154
        $factory = $view->getFactory();
155
156
        try {
157
            $path = $factory->getFinder()->find($path);
158
        } catch (InvalidArgumentException $exception) {
159
            return null;
160
        }
161
162
        if ($view->getEngine() === $factory->getEngineFromPath($path)) {
163
            return $path;
164
        }
165
166
        return null;
167
    }
168
169
    /**
170
     * Find sub native path.
171
     *
172
     * @param  View  $view
173
     * @param  string  $subDir
174
     * @return string|null
175
     */
176
    protected function findSubNativePath(View $view, string $subDir): ?string
177
    {
178
        $path = $view->getPath();
179
        $dirname = $this->files->dirname($path);
180
        $basename = $this->files->basename($path);
181
182
        if ($this->files->exists($path = $dirname.'/'.$subDir.'/'.$basename)) {
183
            return $path;
184
        }
185
186
        return null;
187
    }
188
}
189