PluginProbe
The Innovative Form Builder – IvyForms / 1.4
The Innovative Form Builder – IvyForms v1.4
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / src / Services / Form / Style / FormStyleService.php

FormStyleService.php in The Innovative Form Builder – IvyForms 1.4, at backend/src/Services/Form/Style/FormStyleService.php

166 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @copyright © Melograno Venture Studio. All rights reserved.
5 * @licence See LICENCE.md for license details.
6 */
7
8 namespace IvyForms\Services\Form\Style;
9
10 // phpcs:disable PSR1.Files.SideEffects
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly
13 }
14
15 /**
16 * Class FormStyleService
17 *
18 * Generates scoped CSS from form style settings
19 *
20 * @package IvyForms\Services\Form
21 */
22 class FormStyleService
23 {
24 /**
25 * Generate scoped CSS for a form
26 *
27 * @param int $formId
28 * @param array<string, mixed>|null $styleSettings
29 * @param string|null $formType
30 * @return string
31 */
32 public static function generateFormCSS(int $formId, ?array $styleSettings, ?string $formType = null): string
33 {
34 $resolvedCss = self::resolveFormCssOutput($formId, $styleSettings, $formType);
35 if ($resolvedCss !== null) {
36 return $resolvedCss;
37 }
38
39 return self::buildClassicFormCss($formId, $styleSettings);
40 }
41
42 /**
43 * @param array<string, mixed>|null $styleSettings
44 */
45 private static function resolveFormCssOutput(int $formId, ?array $styleSettings, ?string $formType): ?string
46 {
47 if (empty($styleSettings)) {
48 return '';
49 }
50
51 if (isset($styleSettings['stylesEnabled']) && $styleSettings['stylesEnabled'] === false) {
52 return '';
53 }
54
55 $extensionCss = apply_filters(
56 'ivyforms/form/style/generate_css',
57 null,
58 $formId,
59 $styleSettings,
60 $formType
61 );
62
63 if (is_string($extensionCss)) {
64 return $extensionCss;
65 }
66
67 if (!empty($formType) && $formType !== 'classic') {
68 return '';
69 }
70
71 return null;
72 }
73
74 /**
75 * @param array<string, mixed> $styleSettings
76 */
77 private static function buildClassicFormCss(int $formId, array $styleSettings): string
78 {
79 $css = new CssBuilder();
80 $context = self::buildContext($formId, $styleSettings);
81
82 // Generate all CSS sections using factory
83 $generators = StyleGeneratorFactory::createGenerators();
84
85 foreach ($generators as $generator) {
86 $generator->generate($css, $context);
87 }
88
89 $extraRules = apply_filters('ivyforms/style/filter/css_rules', [], [
90 'baseSelector' => $context->getBaseSelector(),
91 'styleSettings' => $styleSettings,
92 'formPopperScopeClass' => 'ivyforms-form-popper-' . self::normalizeFormScopeToken((string) $formId),
93 ]);
94
95 if (is_array($extraRules) && $extraRules !== []) {
96 $css->addLines($extraRules);
97 }
98
99 return $css->build();
100 }
101
102 /**
103 * Normalize form ID for scoped CSS class names (mirrors frontend selectors helper).
104 */
105 private static function normalizeFormScopeToken(string $formId): string
106 {
107 $normalized = trim($formId);
108 $normalized = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $normalized) ?? '';
109 $normalized = preg_replace('/-+/', '-', $normalized) ?? '';
110 $normalized = trim($normalized, '-');
111
112 return $normalized !== '' ? $normalized : 'default';
113 }
114
115 /**
116 * Build the style context from form ID and settings
117 *
118 * @param int $formId
119 * @param array<string, mixed> $styleSettings
120 * @return StyleContext
121 */
122 private static function buildContext(int $formId, array $styleSettings): StyleContext
123 {
124 $selectors = self::buildSelectors($formId, $styleSettings);
125 $parser = new StyleSettingsParser($styleSettings);
126
127 return new StyleContext(
128 $selectors['base'],
129 $selectors['innerWrapper'],
130 $selectors['form'],
131 $formId,
132 $parser->getActiveColors(),
133 $parser->getActiveStyles(),
134 $styleSettings
135 );
136 }
137
138 /**
139 * Build CSS selectors for the form
140 *
141 * @param int $formId
142 * @param array<string, mixed> $styleSettings
143 * @return array<string, string>
144 */
145 private static function buildSelectors(int $formId, array $styleSettings): array
146 {
147 $formWrapperSelector = '.ivyforms-form-wrapper-' . $formId;
148 $innerWrapperSelector = '.ivyforms-form-wrapper.ivyforms-form-wrapper-' . $formId;
149 $formSelector = '.ivyforms-form-' . $formId;
150 $customClass = !empty($styleSettings['customCssClass'])
151 ? '.' . $styleSettings['customCssClass']
152 : '';
153
154 $baseSelector = $formWrapperSelector;
155 if ($customClass) {
156 $baseSelector .= $customClass;
157 }
158
159 return [
160 'base' => $baseSelector,
161 'innerWrapper' => $innerWrapperSelector,
162 'form' => $formSelector,
163 ];
164 }
165 }
166