Skip to content

Commit 53dce27

Browse files
committed
[ADD] scopeLang() and scopeWithTVs(). Deprecated scopeLangAndTvs().
1 parent 8a920a7 commit 53dce27

File tree

6 files changed

+196
-37
lines changed

6 files changed

+196
-37
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ Evolution CMS-powered websites.
3333

3434
![Multilingual tabs](https://github.com/Seiger/slang/releases/download/v1.0.0/sLang.png)
3535

36+
### Requirements
37+
38+
- Evolution CMS **3.3+**
39+
- PHP **8.3+**
40+
- Composer **2.2+**
41+
- One of: **MySQL 8.0+** / **MariaDB 10.5+** / **PostgreSQL 10+** / **SQLite 3.25+**
42+
3643
## Install by artisan package installer
3744

3845
Go to You /core/ folder:
@@ -99,4 +106,36 @@ Implementing a Language Switcher
99106
@endforeach
100107
```
101108

109+
## Working with localized content (Eloquent)
110+
111+
The `Seiger\sLang\Models\sLangContent` model now applies the current locale automatically.
112+
113+
- Fetch translated rows for the active locale:
114+
```php
115+
use Seiger\sLang\Models\sLangContent;
116+
117+
$items = sLangContent::active()->get(); // locale resolved via evo()->getLocale()
118+
```
119+
- Select a specific locale explicitly:
120+
```php
121+
$items = sLangContent::lang('en')->get();
122+
```
123+
- Include template variables while keeping the locale filtering:
124+
```php
125+
$items = sLangContent::withTVs(['color', 'price'])->get();
126+
```
127+
- Combine multiple helpers:
128+
```php
129+
$items = sLangContent::lang('uk')
130+
->withTVs(['color', 'price'])
131+
->whereParent($parentId)
132+
->active()
133+
->get();
134+
```
135+
- Legacy helper is preserved for backward compatibility:
136+
```php
137+
$items = sLangContent::langAndTvs('en', ['color', 'price'])->get();
138+
```
139+
> **Deprecated:** `langAndTvs()` is deprecated since `1.0.8` and is scheduled for removal in `v1.2`. Use `lang()->withTVs()` instead.
140+
102141
[See full documentation here](https://seiger.github.io/sLang/)

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
}
1818
],
1919
"require": {
20-
"php": "^8.3"
20+
"php": "^8.3",
21+
"evolutioncms/evolution": "^3.3"
2122
},
2223
"autoload": {
2324
"psr-4": {

docs/pages/getting-started.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ description: Getting started with sLang
55
permalink: /getting-started/
66
---
77

8-
## Minimum requirements
8+
### Requirements
99

10-
- Evolution CMS 3.2.0
11-
- PHP 8.1.0
12-
- Composer 2.2.0
13-
- PostgreSQL 10.23.0
14-
- MySQL 8.0.3
15-
- MariaDB 10.5.2
16-
- SQLite 3.25.0
10+
- Evolution CMS **3.3+**
11+
- PHP **8.3+**
12+
- Composer **2.2+**
13+
- One of: **MySQL 8.0+** / **MariaDB 10.5+** / **PostgreSQL 10+** / **SQLite 3.25+**
1714

1815
## Install by artisan package installer
1916

@@ -41,7 +38,7 @@ php artisan migrate
4138

4239
## Management
4340

44-
After installing the module, you can use it immediately. Path to the module in the
41+
After installing the module, you can use it immediately. Path to the module in the
4542
administrator panel **Admin Panel -> Modules -> Multilingual**.
4643

4744
The resource includes tabs for each language separately.
@@ -52,7 +49,7 @@ The resource includes tabs for each language separately.
5249

5350
## Extra
5451

55-
If you write your own code that can integrate with the sLang module,
52+
If you write your own code that can integrate with the sLang module,
5653
you can check the presence of this module in the system through a configuration variable.
5754

5855
```php
@@ -61,5 +58,18 @@ if (evo()->getConfig('check_sLang', false)) {
6158
}
6259
```
6360

64-
If the plugin is installed, the result of ```evo()->getConfig('check_sLang', false)```
61+
If the plugin is installed, the result of ```evo()->getConfig('check_sLang', false)```
6562
will always be ```true```. Otherwise, you will get an ```false```.
63+
64+
### Working with localized content
65+
66+
Use the `sLangContent` model to fetch translated resources:
67+
68+
```php
69+
use Seiger\sLang\Models\sLangContent;
70+
71+
$items = sLangContent::active()->get(); // locale resolved automatically
72+
$itemsEn = sLangContent::lang('en')->withTVs(['preview'])->get();
73+
```
74+
75+
> **Deprecated:** The `langAndTvs()` scope is deprecated since `1.0.8` and will be removed in `v1.2`. Replace it with `lang()` and `withTVs()`.

docs/pages/index.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ permalink: /
1919
admin panel. This dynamic package empowers users to seamlessly implement and manage
2020
multilingual tools within the Evolution CMS environment. By utilizing Evolution CMS
2121
as its platform, sLang offers a streamlined solution for users seeking efficient and
22-
intuitive ways to handle diverse language content, making it an indispensable asset
23-
for administrators and developers navigating the intricacies of multilingual website
22+
intuitive ways to handle diverse language content, making it an indispensable asset
23+
for administrators and developers navigating the intricacies of multilingual website
2424
management.
2525

2626
The work of the module is based on the use of the standard Laravel functionality for
@@ -40,11 +40,18 @@ Evolution CMS-powered websites.
4040
- [x] Unlimited Translation Language Support.
4141
- [x] Multilingual SEO Support.
4242

43-
## Minimum requirements
43+
## Locale-aware content model
4444

45-
- Evolution CMS >= 3.2.0
46-
- PHP >= 8.1.0
47-
- Composer >= 2.2.0
45+
- `Seiger\sLang\Models\sLangContent` now respects the current locale by default (via `evo()->getLocale()`).
46+
- Explicit locale selection is available through the `lang()` scope, and template variables can be appended with `withTVs()`.
47+
- `langAndTvs()` remains for backward compatibility but is **deprecated since `1.0.8`** and scheduled for removal in **`v1.2`**.
48+
49+
### Requirements
50+
51+
- Evolution CMS **3.3+**
52+
- PHP **8.3+**
53+
- Composer **2.2+**
54+
- One of: **MySQL 8.0+** / **MariaDB 10.5+** / **PostgreSQL 10+** / **SQLite 3.25+**
4855

4956
## Support
5057

docs/pages/use-in-blade.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,14 @@ use Seiger\sLang\Models\sLangContent;
8585

8686
public function globalElements()
8787
{
88-
$this->data['mainMenu'] = sLangContent::langAndTvs(evo()->getConfig('lang', 'uk'))
88+
$this->data['mainMenu'] = sLangContent::withTVs(['menu_main'])
8989
->whereTv('menu_main', 1)
9090
->where('hidemenu', 0)
9191
->orderBy('menuindex')
9292
->active()
9393
->get();
9494

95-
$this->data['footerMenu'] = sLangContent::langAndTvs(evo()->getConfig('lang', 'uk'))
95+
$this->data['footerMenu'] = sLangContent::withTVs(['menu_footer'])
9696
->whereTv('menu_footer', 1)
9797
->where('hidemenu', 0)
9898
->orderBy('menuindex')
@@ -122,23 +122,25 @@ Output in the Blade template
122122

123123
## TV variables
124124

125-
The ```langAndTvs()``` method makes it quite easy to get TV parameters associated with a resource. For example, the **tv_image** parameter.
125+
The `withTVs()` scope makes it easy to retrieve TV parameters associated with a resource. For example, the **tv_image** parameter.
126126

127127
Get in the controller.
128128
```php
129-
$resource = sLangContent::langAndTvs(evo()->getConfig('lang'), ['tv_image'])->active()->first();
129+
$resource = sLangContent::withTVs(['tv_image'])->active()->first();
130130
```
131131

132132
Display in the template.
133133
```php
134134
{% raw %}{{$resource->tv_image}}{% endraw %}
135135
```
136136

137-
The ```whereTv()``` method allows you to use a filter based on the value of the TV parameter if necessary.
137+
The `whereTv()` method allows you to use a filter based on the value of the TV parameter if necessary.
138138
```php
139-
$resource = sLangContent::langAndTvs(evo()->getConfig('lang'), ['tv_image'])->whereTv('tv_image', '!=', '')->get();
139+
$resource = sLangContent::withTVs(['tv_image'])->whereTv('tv_image', '!=', '')->get();
140140
```
141141

142+
> **Deprecated:** The `langAndTvs()` helper is deprecated since `1.0.8` and will be removed in `v1.2`. Replace it with the `lang()` and `withTVs()` scopes.
143+
142144
## Resource fields in Admin panel
143145

144146
You can control the display of resource fields on general tabs through an event ```sLangDocFormFieldRender```.

src/Models/sLangContent.php

Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,40 @@ class sLangContent extends Eloquent\Model
1111
protected $fillable = ['resource', 'lang', 'pagetitle', 'longtitle', 'description', 'introtext', 'content', 'menutitle', 'seotitle', 'seodescription'];
1212

1313
/**
14-
* Add the language and template variable fields to the query
14+
* Add the language and template variable fields to the query.
1515
*
1616
* @param Builder $query The query builder instance
1717
* @param string $locale The language locale
1818
* @param array $tvNames The array of template variable names
1919
* @return Builder The modified query builder instance
20+
*
21+
* @deprecated since 1.0.8
22+
* TODO: REMOVE IN v1.2
2023
*/
2124
public function scopeLangAndTvs($query, $locale, $tvNames = [])
2225
{
23-
$query->select('*', 's_lang_content.resource as id', 's_lang_content.pagetitle as pagetitle');
24-
$query->addSelect('s_lang_content.longtitle as longtitle', 's_lang_content.description as description');
25-
$query->addSelect('s_lang_content.introtext as introtext', 's_lang_content.content as content');
26-
$query->addSelect('s_lang_content.menutitle as menutitle');
27-
$query->selectTvs($tvNames);
28-
29-
return $query->addSelect('site_content.pagetitle as pagetitle_orig', 'site_content.longtitle as longtitle_orig')
30-
->addSelect('site_content.description as description_orig', 'site_content.introtext as introtext_orig')
31-
->addSelect('site_content.content as content_orig', 'site_content.menutitle as menutitle_orig')
32-
->leftJoin('site_content', 's_lang_content.resource', '=', 'site_content.id')
33-
->where('lang', '=', $locale);
26+
$query = $this->scopeLang($query, $locale);
27+
return $query->withTVs($tvNames);
28+
}
29+
30+
/**
31+
* Limit the query to a specific language. Falls back to evo()->getLocale() when locale is not provided.
32+
*/
33+
public function scopeLang($query, ?string $locale = null)
34+
{
35+
$query = $query->withoutGlobalScope('language');
36+
$locale = static::resolveLocale($locale);
37+
$this->applyContentSelects($query);
38+
return $query->where('lang', '=', $locale);
39+
}
40+
41+
/**
42+
* Append template variable fields while preserving base selects.
43+
*/
44+
public function scopeWithTVs($query, array $tvNames = [])
45+
{
46+
$this->applyContentSelects($query);
47+
return $this->scopeSelectTvs($query, $tvNames);
3448
}
3549

3650
/**
@@ -143,8 +157,94 @@ public function getFullLinkAttribute()
143157
{
144158
$base_url = UrlProcessor::makeUrl($this->resource);
145159
if (str_starts_with($base_url, '/')) {
146-
$base_url = MODX_SITE_URL . ltrim($base_url, '/');
160+
$base_url = EVO_SITE_URL . ltrim($base_url, '/');
147161
}
148162
return $base_url;
149163
}
164+
165+
/**
166+
* Applies base selects and joins required for language-aware scopes.
167+
*/
168+
protected function applyContentSelects(Builder $query): Builder
169+
{
170+
$eloquentQuery = $query->getQuery();
171+
172+
if (empty($eloquentQuery->columns)) {
173+
$query->select('s_lang_content.*');
174+
}
175+
176+
$query->addSelect(
177+
's_lang_content.resource as id',
178+
's_lang_content.pagetitle as pagetitle',
179+
's_lang_content.longtitle as longtitle',
180+
's_lang_content.description as description',
181+
's_lang_content.introtext as introtext',
182+
's_lang_content.content as content',
183+
's_lang_content.menutitle as menutitle'
184+
);
185+
186+
if (!$this->hasSiteContentJoin($eloquentQuery->joins ?? [])) {
187+
$query->leftJoin('site_content', 's_lang_content.resource', '=', 'site_content.id');
188+
}
189+
190+
return $query->addSelect(
191+
'site_content.pagetitle as pagetitle_orig',
192+
'site_content.longtitle as longtitle_orig',
193+
'site_content.description as description_orig',
194+
'site_content.introtext as introtext_orig',
195+
'site_content.content as content_orig',
196+
'site_content.menutitle as menutitle_orig'
197+
);
198+
}
199+
200+
/**
201+
* Detect whether site_content join has already been added.
202+
*/
203+
protected function hasSiteContentJoin(array $joins): bool
204+
{
205+
foreach ($joins as $join) {
206+
if (($join->table ?? null) === 'site_content') {
207+
return true;
208+
}
209+
}
210+
211+
return false;
212+
}
213+
214+
/**
215+
* Resolve the locale used by language-aware scopes.
216+
*/
217+
protected static function resolveLocale(?string $locale): string
218+
{
219+
$locale = $locale ?? (function_exists('evo') ? (string)evo()->getLocale() : '');
220+
221+
if ($locale === '' && function_exists('evo')) {
222+
$locale = (string)evo()->getConfig('lang', 'uk');
223+
}
224+
225+
if ($locale === '') {
226+
$locale = 'uk';
227+
}
228+
229+
$underscorePos = strpos($locale, '_');
230+
if ($underscorePos !== false) {
231+
$locale = substr($locale, 0, $underscorePos);
232+
}
233+
234+
return strtolower($locale);
235+
}
236+
237+
/**
238+
* Register the default language scope for the model.
239+
*/
240+
protected static function booted(): void
241+
{
242+
static::addGlobalScope('language', function (Builder $builder) {
243+
/** @var self $model */
244+
$model = new static;
245+
$locale = static::resolveLocale(null);
246+
$model->applyContentSelects($builder);
247+
$builder->where($model->getTable() . '.lang', '=', $locale);
248+
});
249+
}
150250
}

0 commit comments

Comments
 (0)