Refactor Template Processing and Update Setting Model: Enhanced the ImportHtmlTemplates command to improve header processing with dynamic logo handling based on navbar type. Updated the Setting model to include new accessors for various field types, ensuring better data retrieval. Adjusted the SettingSeeder to clear logo paths for better management.
This commit is contained in:
@@ -143,40 +143,81 @@ class ImportHtmlTemplates extends Command
|
||||
|
||||
// A. Header Özel Alanları
|
||||
if ($templateType === 'header') {
|
||||
// Navbar sınıfını kontrol et
|
||||
$navbar = $xpath->query('.//*[contains(@class, "navbar")]', $node)->item(0);
|
||||
$isNavbarLight = $navbar && str_contains($navbar->getAttribute('class'), 'navbar-light');
|
||||
$isNavbarDark = $navbar && str_contains($navbar->getAttribute('class'), 'navbar-dark');
|
||||
|
||||
// Logo
|
||||
$brands = $xpath->query('.//*[contains(@class, "navbar-brand")]//img', $node);
|
||||
foreach ($brands as $img) {
|
||||
$src = $this->fixAssetPath($img->getAttribute('src'));
|
||||
$class = $img->getAttribute('class');
|
||||
|
||||
$settingKey = 'setting.logo';
|
||||
|
||||
if (str_contains($class, 'logo-dark')) {
|
||||
$data['setting.logo_dark'] = $src;
|
||||
$img->setAttribute('src', '{setting.logo_dark}');
|
||||
$settingKey = 'setting.logo_dark';
|
||||
} elseif (str_contains($class, 'logo-light')) {
|
||||
$data['setting.logo_light'] = $src;
|
||||
$img->setAttribute('src', '{setting.logo_light}');
|
||||
} else {
|
||||
$data['setting.logo'] = $src;
|
||||
$img->setAttribute('src', '{setting.logo}');
|
||||
}
|
||||
$settingKey = 'setting.logo_light';
|
||||
} elseif ($isNavbarLight) {
|
||||
// Navbar light ise (açık zemin), koyu logo gerekir
|
||||
$settingKey = 'setting.logo_dark';
|
||||
} elseif ($isNavbarDark) {
|
||||
// Navbar dark ise (koyu zemin), açık logo gerekir
|
||||
$settingKey = 'setting.logo_light';
|
||||
}
|
||||
|
||||
// Menu
|
||||
$data[$settingKey] = $src;
|
||||
$img->setAttribute('src', '{' . $settingKey . '}');
|
||||
}
|
||||
|
||||
// Menu ({custom.menu})
|
||||
$navs = $xpath->query('.//*[contains(@class, "navbar-nav")]', $node);
|
||||
foreach ($navs as $nav) {
|
||||
if (!$nav->parentNode) continue;
|
||||
// İçini temizle
|
||||
while ($nav->hasChildNodes()) {
|
||||
$nav->removeChild($nav->firstChild);
|
||||
// Sadece ana menüyü hedefle (genellikle navbar-collapse içinde olur)
|
||||
// İçeriği tamamen temizle ve yerine placeholder koy
|
||||
$parent = $nav->parentNode;
|
||||
if ($parent) {
|
||||
// Eğer parent offcanvas-body veya navbar-collapse ise
|
||||
$textNode = $node->ownerDocument->createTextNode('___CUSTOM_MENU___');
|
||||
$parent->replaceChild($textNode, $nav);
|
||||
}
|
||||
// Placeholder metni ekle - Token olarak
|
||||
$nav->nodeValue = '___SPECIAL_MENU___';
|
||||
}
|
||||
|
||||
// Dil Seçici
|
||||
$langs = $xpath->query('.//*[contains(@class, "language")]', $node);
|
||||
// Navbar Other ({custom.navbar})
|
||||
$others = $xpath->query('.//*[contains(@class, "navbar-other")]', $node);
|
||||
foreach ($others as $other) {
|
||||
$parent = $other->parentNode;
|
||||
if ($parent) {
|
||||
// Navbar other genellikle butonları içerir, bunu custom.navbar ile değiştiriyoruz
|
||||
// Ancak dil seçici de bunun içinde olabilir.
|
||||
// Kullanıcı örneğinde {custom.navbar} ve {custom.language-selector} yan yana.
|
||||
// Biz şimdilik navbar-other'ı komple custom.navbar yapalım.
|
||||
// Dil seçici için ayrıca bir mantık kuralım.
|
||||
|
||||
// Dil seçiciyi kontrol et, eğer varsa onu çıkarıp yanına ekleyebiliriz ama
|
||||
// genellikle navbar-other kapsayıcıdır.
|
||||
|
||||
$textNode = $node->ownerDocument->createTextNode('___CUSTOM_NAVBAR___');
|
||||
$parent->replaceChild($textNode, $other);
|
||||
|
||||
// Hemen sonrasına language selector ekleyelim (varsayım)
|
||||
// Veya kullanıcı manuel eklesin.
|
||||
// Kullanıcının isteği: {custom.navbar} {custom.language-selector}
|
||||
$langNode = $node->ownerDocument->createTextNode('___CUSTOM_LANGUAGE___');
|
||||
$parent->appendChild($langNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Dil Seçici ({custom.language-selector}) - Eğer navbar-other dışında varsa
|
||||
$langs = $xpath->query('.//*[contains(@class, "language-select") or contains(@class, "dropdown-language")]', $node);
|
||||
foreach ($langs as $lang) {
|
||||
$lang->nodeValue = '___SETTING_LANGUAGES___';
|
||||
$parent = $lang->parentNode;
|
||||
if ($parent) {
|
||||
$textNode = $node->ownerDocument->createTextNode('___CUSTOM_LANGUAGE___');
|
||||
$parent->replaceChild($textNode, $lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +291,11 @@ class ImportHtmlTemplates extends Command
|
||||
|
||||
// SPECIAL TOKENS FIX
|
||||
if ($templateType === 'header') {
|
||||
$html = str_replace('___SPECIAL_MENU___', '{special.menu}', $html);
|
||||
$html = str_replace('___SETTING_LANGUAGES___', '{setting.available_languages}', $html);
|
||||
$html = str_replace('___SPECIAL_MENU___', '{custom.menu}', $html); // Geriye dönük uyumluluk
|
||||
$html = str_replace('___CUSTOM_MENU___', '{custom.menu}', $html);
|
||||
$html = str_replace('___CUSTOM_NAVBAR___', '{custom.navbar}', $html);
|
||||
$html = str_replace('___CUSTOM_LANGUAGE___', '{custom.language-selector}', $html);
|
||||
$html = str_replace('___SETTING_LANGUAGES___', '{custom.language-selector}', $html);
|
||||
}
|
||||
|
||||
return ['html' => $html, 'data' => $data];
|
||||
|
||||
@@ -51,7 +51,7 @@ class EditSetting extends EditRecord
|
||||
|
||||
protected function getRedirectUrl(): string
|
||||
{
|
||||
return $this->getResource()::getUrl('index');
|
||||
return $this->getResource()::getUrl('edit', ['record' => $this->getRecord()]);
|
||||
}
|
||||
|
||||
protected function getSavedNotificationTitle(): ?string
|
||||
|
||||
@@ -116,12 +116,6 @@ class SettingForm
|
||||
->required()
|
||||
->visible(fn (Get $get) => in_array($get('type'), ['string', 'text', 'json']))
|
||||
->rows(fn (Get $get) => $get('type') === 'text' ? 5 : 3)
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && in_array($record->type, ['string', 'text', 'json'])) {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('value_boolean')
|
||||
@@ -129,12 +123,6 @@ class SettingForm
|
||||
->helperText(__('settings.value_helper'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'boolean')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'boolean') {
|
||||
return filter_var($record->value, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
FileUpload::make('value_file')
|
||||
@@ -146,12 +134,6 @@ class SettingForm
|
||||
->directory('settings')
|
||||
->acceptedFileTypes(['image/*', 'application/pdf', 'text/*'])
|
||||
->maxSize(10240) // 10MB
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'file') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
DatePicker::make('value_date')
|
||||
@@ -161,12 +143,6 @@ class SettingForm
|
||||
->visible(fn (Get $get) => $get('type') === 'date')
|
||||
->displayFormat('d/m/Y')
|
||||
->format('Y-m-d')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'date') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
DateTimePicker::make('value_datetime')
|
||||
@@ -177,12 +153,6 @@ class SettingForm
|
||||
->displayFormat('d/m/Y H:i')
|
||||
->format('Y-m-d H:i:s')
|
||||
->seconds(false)
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'datetime') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Repeater::make('value_array')
|
||||
@@ -213,13 +183,6 @@ class SettingForm
|
||||
->reorderable()
|
||||
->collapsible()
|
||||
->itemLabel(fn (array $state): ?string => $state['key'] ?? null)
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'array') {
|
||||
$decoded = json_decode($record->value, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
return is_array($state) ? $state : [];
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
ColorPicker::make('value_color_picker')
|
||||
@@ -227,12 +190,6 @@ class SettingForm
|
||||
->helperText(__('settings.value_helper'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'color_picker')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'color_picker') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
CodeEditor::make('value_code_editor')
|
||||
@@ -241,12 +198,6 @@ class SettingForm
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'code_editor')
|
||||
->language(CodeEditorLanguage::Php)
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'code_editor') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
RichEditor::make('value_rich_editor')
|
||||
@@ -272,12 +223,6 @@ class SettingForm
|
||||
'underline',
|
||||
'undo',
|
||||
])
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'rich_editor') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
MarkdownEditor::make('value_markdown_editor')
|
||||
@@ -285,12 +230,6 @@ class SettingForm
|
||||
->helperText(__('settings.value_helper'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'markdown_editor')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'markdown_editor') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
TagsInput::make('value_tags_input')
|
||||
@@ -299,13 +238,6 @@ class SettingForm
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'tags_input')
|
||||
->separator(',')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'tags_input') {
|
||||
$decoded = json_decode($record->value, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
return is_array($state) ? $state : [];
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
CheckboxList::make('value_checkbox_list')
|
||||
@@ -318,13 +250,6 @@ class SettingForm
|
||||
'option2' => __('settings.checkbox_option_2'),
|
||||
'option3' => __('settings.checkbox_option_3'),
|
||||
])
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'checkbox_list') {
|
||||
$decoded = json_decode($record->value, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
return is_array($state) ? $state : [];
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Radio::make('value_radio')
|
||||
@@ -337,12 +262,6 @@ class SettingForm
|
||||
'option2' => __('settings.radio_option_2'),
|
||||
'option3' => __('settings.radio_option_3'),
|
||||
])
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'radio') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
ToggleButtons::make('value_toggle_buttons')
|
||||
@@ -355,12 +274,6 @@ class SettingForm
|
||||
'option2' => __('settings.toggle_option_2'),
|
||||
'option3' => __('settings.toggle_option_3'),
|
||||
])
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'toggle_buttons') {
|
||||
return $record->value;
|
||||
}
|
||||
return $state;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Slider::make('value_slider')
|
||||
@@ -370,12 +283,6 @@ class SettingForm
|
||||
->visible(fn (Get $get) => $get('type') === 'slider')
|
||||
->range(minValue: 0, maxValue: 100)
|
||||
->step(1)
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'slider') {
|
||||
return (int) $record->value;
|
||||
}
|
||||
return $state ?? 0;
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
KeyValue::make('value_key_value')
|
||||
@@ -383,13 +290,6 @@ class SettingForm
|
||||
->helperText(__('settings.value_helper'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('type') === 'key_value')
|
||||
->formatStateUsing(function ($state, $record) {
|
||||
if ($record && $record->type === 'key_value') {
|
||||
$decoded = json_decode($record->value, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
return is_array($state) ? $state : [];
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('is_active')
|
||||
|
||||
@@ -69,8 +69,13 @@ class Setting extends Model
|
||||
*/
|
||||
public function setValueFileAttribute($value)
|
||||
{
|
||||
// Filament bazen dosya yolunu array olarak döndürebilir, bu durumda ilk elemanı alıyoruz
|
||||
if (is_array($value)) {
|
||||
$this->attributes['value'] = array_values($value)[0] ?? null;
|
||||
} else {
|
||||
$this->attributes['value'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value from different field names
|
||||
@@ -176,6 +181,134 @@ class Setting extends Model
|
||||
$this->attributes['value'] = is_array($value) ? json_encode($value) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for text field
|
||||
*/
|
||||
public function getValueTextAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for boolean field
|
||||
*/
|
||||
public function getValueBooleanAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? filter_var($this->attributes['value'], FILTER_VALIDATE_BOOLEAN) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for file field
|
||||
*/
|
||||
public function getValueFileAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for date field
|
||||
*/
|
||||
public function getValueDateAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for datetime field
|
||||
*/
|
||||
public function getValueDatetimeAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for array field
|
||||
*/
|
||||
public function getValueArrayAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for color picker field
|
||||
*/
|
||||
public function getValueColorPickerAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for code editor field
|
||||
*/
|
||||
public function getValueCodeEditorAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for rich editor field
|
||||
*/
|
||||
public function getValueRichEditorAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for markdown editor field
|
||||
*/
|
||||
public function getValueMarkdownEditorAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for tags input field
|
||||
*/
|
||||
public function getValueTagsInputAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for checkbox list field
|
||||
*/
|
||||
public function getValueCheckboxListAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for radio field
|
||||
*/
|
||||
public function getValueRadioAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for toggle buttons field
|
||||
*/
|
||||
public function getValueToggleButtonsAttribute()
|
||||
{
|
||||
return $this->attributes['value'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for slider field
|
||||
*/
|
||||
public function getValueSliderAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? (int) $this->attributes['value'] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value for key value field
|
||||
*/
|
||||
public function getValueKeyValueAttribute()
|
||||
{
|
||||
return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setting by key
|
||||
*/
|
||||
|
||||
@@ -51,6 +51,11 @@ class TemplateService
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip setting.* placeholders - they are global settings managed via Settings module
|
||||
if ($type === 'setting') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip custom.* placeholders - they are blade components, not form fields
|
||||
if ($type === 'custom') {
|
||||
continue;
|
||||
@@ -282,7 +287,7 @@ class TemplateService
|
||||
public static function parsePlaceholders(string $html): array
|
||||
{
|
||||
// Pattern: {type.field} or {special.type.field} or {type.field.field2} etc.
|
||||
preg_match_all('/\{([a-z]+(?:\.[a-z][a-z_-]*)+)\}/i', $html, $matches);
|
||||
preg_match_all('/\{([a-z]+(?:\.[a-z][a-z0-9_-]*)+)\}/i', $html, $matches);
|
||||
return array_unique($matches[1] ?? []);
|
||||
}
|
||||
|
||||
@@ -410,7 +415,7 @@ class TemplateService
|
||||
// Also supports {special.page.title} format (special.* prefix)
|
||||
// Exclude custom.* from this regex to avoid double processing
|
||||
// Pattern: {type.field} or {special.type.field} or {type.field.field2} etc.
|
||||
preg_match_all('/\{([a-z]+(?:\.[a-z][a-z_-]*)+)\}/i', $html, $matches);
|
||||
preg_match_all('/\{([a-z]+(?:\.[a-z][a-z0-9_-]*)+)\}/i', $html, $matches);
|
||||
$placeholders = array_unique($matches[1] ?? []);
|
||||
|
||||
// Filter out custom.* placeholders as they're already handled above
|
||||
|
||||
@@ -587,7 +587,7 @@ class SettingSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'key' => 'logo_light',
|
||||
'value' => 'assets/img/logo-light.png',
|
||||
'value' => '',
|
||||
'type' => 'file',
|
||||
'group' => 'theme',
|
||||
'label' => 'Light Logo',
|
||||
@@ -597,7 +597,7 @@ class SettingSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'key' => 'logo_dark',
|
||||
'value' => 'assets/img/logo-dark.png',
|
||||
'value' => '',
|
||||
'type' => 'file',
|
||||
'group' => 'theme',
|
||||
'label' => 'Dark Logo',
|
||||
|
||||
Reference in New Issue
Block a user