diff --git a/src/Plugin.php b/src/Plugin.php index 01a0ab2..74e813e 100755 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -9,8 +9,9 @@ use craft\base\Plugin as BasePlugin; use craft\elements\Entry; use craft\events\DefineHtmlEvent; +use craft\events\RegisterUrlRulesEvent; use craft\helpers\UrlHelper; -use craft\web\Controller; +use craft\web\UrlManager; use craft\web\View; use fostercommerce\entrytyperules\assetbundles\entrytyperules\EntryTypeRulesAsset; use fostercommerce\entrytyperules\models\Settings; @@ -25,14 +26,22 @@ */ class Plugin extends BasePlugin { + public static ?Plugin $plugin = null; + public bool $hasCpSettings = true; + public static ?Settings $settings = null; + /** * @throws InvalidConfigException */ public function init(): void { parent::init(); + self::$plugin = $this; + + self::$plugin->getSettings(); + //self::$settings = $settings; $this->setComponents([ 'service' => Service::class, @@ -61,23 +70,34 @@ function (DefineHtmlEvent $event): void { } } ); + + + Event::on( + UrlManager::class, + UrlManager::EVENT_REGISTER_CP_URL_RULES, + function (RegisterUrlRulesEvent $event): void { + // Register Control Panel routes + $event->rules = array_merge( + $event->rules, + [ + 'entry-type-rules' => 'entry-type-rules/settings', + 'entry-type-rules/settings' => 'entry-type-rules/settings', + ], + ); + } + ); } public function getSettingsResponse(): mixed { - $overrides = Craft::$app->getConfig()->getConfigFromFile($this->handle); + /** @var \craft\web\Response $response */ + $response = Craft::$app->getResponse(); + return $response->redirect(UrlHelper::cpUrl('entry-type-rules/settings')); + } - /** @var Controller $controller */ - $controller = Craft::$app->controller; - return $controller->renderTemplate( - 'entry-type-rules/settings', - [ - 'settings' => $this->getSettings(), - 'overrides' => $overrides, - 'sectionsUrl' => UrlHelper::cpUrl('settings/sections'), - 'entriesUrl' => UrlHelper::cpUrl('entries'), - ] - ); + public function getPluginName(): ?string + { + return $this->name; } protected function createSettingsModel(): ?Model diff --git a/src/controllers/SettingsController.php b/src/controllers/SettingsController.php index af4f0c4..2bc95c2 100644 --- a/src/controllers/SettingsController.php +++ b/src/controllers/SettingsController.php @@ -5,10 +5,16 @@ use Craft; use craft\errors\MissingComponentException; +use craft\helpers\ArrayHelper; +use craft\helpers\ConfigHelper; +use craft\helpers\Cp; +use craft\helpers\UrlHelper; +use craft\models\Site; use craft\web\Controller; use craft\web\Request; use fostercommerce\entrytyperules\models\Settings; use fostercommerce\entrytyperules\Plugin; +use Illuminate\Support\Collection; use yii\base\InvalidConfigException; use yii\web\BadRequestHttpException; use yii\web\MethodNotAllowedHttpException; @@ -18,6 +24,49 @@ class SettingsController extends Controller { protected array|int|bool $allowAnonymous = []; + public function actionIndex(): Response + { + $site = Cp::requestedSite(); + $siteHandle = $site?->handle; + $siteId = $site?->id; + $sections = Craft::$app->getEntries()->getAllSections(); + + $enabledSections = array_filter($sections, fn ($section) => $section->getSiteSettings()[$siteId]->enabledByDefault ?? false); + $variables = []; + + $siteHandleUri = Craft::$app->isMultiSite ? '/' . $siteHandle : ''; + + $overrides = Craft::$app->getConfig()->getConfigFromFile('entry-type-rules'); + + // walk through overrides array, + // if the value set for 'limit' is not an array then replace it with an array of siteHandles all with same value + // if the value set for limit is an array and there is a key for '*' then replace it with an array of siteHandles all with same value + $this->_globalValues($overrides); + + $variables = [ + 'sections' => $enabledSections, + 'settings' => Plugin::$plugin?->getSettings()->toArray(), + 'overrides' => $overrides, + 'sectionsUrl' => ConfigHelper::localizedValue(UrlHelper::cpUrl('settings/sections', $siteHandle)), + 'siteHandle' => $siteHandle, + 'siteHandleUri' => $siteHandleUri, + 'siteId' => $siteId, + 'crumbs' => $this->_buildCrumbs(), + ]; + + + $this->_buildCrumbs(); + + + + /** @var Controller $controller */ + $controller = Craft::$app->controller; + return $controller->renderTemplate( + 'entry-type-rules/settings', + $variables + ); + } + /** * Handle a request going to our plugin's action URL for saving settings, * e.g.: actions/craft-entry-type-rules/save-settings @@ -30,17 +79,30 @@ class SettingsController extends Controller public function actionSaveSettings(): Response { $this->requirePostRequest(); - /** @var Request $request */ $request = Craft::$app->getRequest(); + $siteHandle = Craft::$app->getSites()->getSiteById($request->getBodyParam('siteId'))->handle; + /** @var Plugin $plugin */ $plugin = Plugin::getInstance(); + $newSettings = $request->getBodyParam('sections'); + + $oldSettings = $plugin->getSettings()->toArray(); + + $this->_removeUserGroupsForSite($oldSettings, $siteHandle); + + + $mergedSettings = ArrayHelper::merge($oldSettings['sections'] ?? [], $newSettings ?? []); + + $settings = new Settings([ - 'sections' => $request->getBodyParam('sections'), + 'sections' => $mergedSettings, ]); + + if (! $settings->validate() || ! Craft::$app->getPlugins()->savePluginSettings($plugin, $settings->toArray())) { Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t save plugin settings.')); } else { @@ -49,4 +111,128 @@ public function actionSaveSettings(): Response return $this->redirectToPostedUrl(); } + + public function _removeUserGroupsForSite(array &$array, string $targetSite, ?string $currentSite = null): void + { + foreach ($array as $key => &$value) { + // Track when we enter a site-specific branch + $nextSite = $currentSite; + if ($key === 'firstSite' || $key === 'secondSite') { + $nextSite = $key; + } + + // Remove userGroups only if we're inside the target site + if ($key === 'userGroups' && $currentSite === $targetSite) { + unset($array[$key]); + continue; + } + + if (is_array($value)) { + $this->_removeUserGroupsForSite($value, $targetSite, $nextSite); + } + } + } + + /** + * @return array>|string>|string|null>> + */ + private function _buildCrumbs(): array + { + $sites = Craft::$app->getSites(); + $requestedSite = Cp::requestedSite() ?? Craft::$app->getSites()->getPrimarySite(); + $requestedSiteId = $requestedSite->id; + $requestedSiteName = $requestedSite->name; + + $siteCrumbItems = []; + $siteGroups = Craft::$app->getSites()->getAllGroups(); + $crumbSites = Collection::make($sites->getAllSites()) + ->map(fn (Site $site): array => [ + 'site' => $site, + ]) + ->keyBy(fn (array $site): ?int => $site['site']->id) + ->all(); + + foreach ($siteGroups as $siteGroup) { + $groupSites = $siteGroup->getSites(); + + if (empty($groupSites)) { + continue; + } + + $groupSiteItems = array_map(fn (Site $site): array => [ + 'status' => $crumbSites[$site->id]['site']->status ?? null, + 'label' => Craft::t('site', $site->name), + 'url' => UrlHelper::cpUrl("entry-type-rules?site={$site->handle}"), + 'hidden' => ! isset($crumbSites[$site->id]), + 'selected' => $site->id === $requestedSiteId, + 'attributes' => [ + 'data' => [ + 'site-id' => $site->id, + ], + ], + ], $groupSites); + + if (count($siteGroups) > 1) { + $siteCrumbItems[] = [ + 'heading' => Craft::t('site', $siteGroup->name), + 'items' => $groupSiteItems, + 'hidden' => ! ArrayHelper::contains($groupSiteItems, fn (array $item): bool => ! $item['hidden']), + ]; + } else { + array_push($siteCrumbItems, ...$groupSiteItems); + } + } + + // Add in the breadcrumbs + $crumbs = [ + [ + 'id' => 'language-menu', + 'icon' => 'world', + 'label' => Craft::t( + 'site', + $requestedSiteName + ), + 'menu' => [ + 'items' => $siteCrumbItems, + 'label' => Craft::t('site', 'Select site'), + ], + ], + [ + 'label' => Plugin::$plugin?->getPluginName(), + ], + ]; + + return $crumbs; + } + + private function _globalValues(array &$array): void + { + // get all sitehandles + $sites = Craft::$app->getSites()->getAllSites(); + $siteHandles = array_map(fn ($site) => $site->handle, $sites); + + foreach ($array as $key => &$value) { + // if we only have an integer as a limit value, then set the value to be an array of site handles set to the value + if ($key === 'limit' && ! is_array($value)) { + $limitValue = $value; + $value = array_fill_keys($siteHandles, $limitValue); + } + + // if we have an array of limit values, but the array contains the key '*' + // or there is a '*' array in the userGroups + // then set any undefined sites to use the value for '*' + if (($key === 'limit' && is_array($value) || $key === 'userGroups') && array_key_exists('*', $value)) { + $defaultValue = $value['*']; + $missingSiteHandles = array_values(array_diff($siteHandles, array_keys($value))); + $defaultedSiteHandles = array_fill_keys($missingSiteHandles, $defaultValue); + $value = array_merge($value, $defaultedSiteHandles); + // unset the '*' + unset($value['*']); + } + + if (is_array($value)) { + $this->_globalValues($value); + } + } + } } diff --git a/src/services/Service.php b/src/services/Service.php index e2a9002..49a6e9a 100755 --- a/src/services/Service.php +++ b/src/services/Service.php @@ -6,6 +6,8 @@ use craft\base\Component; use craft\elements\Entry; +use craft\helpers\ConfigHelper; +use craft\helpers\Cp; use craft\web\User; use fostercommerce\entrytyperules\models\Settings; use fostercommerce\entrytyperules\Plugin; @@ -21,6 +23,8 @@ public function getLockedEntryTypes(int $sectionId, User $user): array // We will return an array of locked entry type IDs $lockedEntryTypes = []; + $site = Cp::requestedSite(); + // Get the plugins settings /** @var Settings $settings */ $settings = Plugin::getInstance()?->getSettings(); @@ -51,17 +55,18 @@ public function getLockedEntryTypes(int $sectionId, User $user): array // Loop through the locked entry type settings foreach ($lockedTypesSettings as $typeHandle => $setting) { // Get the count of each entry type and compare it to the limit value - $limit = $setting['limit'] ?? 0; + $limit = ConfigHelper::localizedValue($setting['limit'], $site->handle) ?? 0; if ($limit > 0) { $entryCount = Entry::find()->sectionId($sectionId)->type($typeHandle)->count(); - if ($entryCount >= $setting['limit']) { + if ($entryCount >= $limit) { $lockedEntryTypes[] = $entryTypesIdsMap[$typeHandle]; } } // Check the users groups against the userGroup setting - if (isset($setting['userGroups']) && is_array($setting['userGroups'])) { - $matchedGroups = array_intersect($setting['userGroups'], $userGroupArray); + $userGroups = ConfigHelper::localizedValue($setting['userGroups']); + if (is_array($userGroups)) { + $matchedGroups = array_intersect($userGroups, $userGroupArray); if ($matchedGroups === [] && ! $user->getIsAdmin()) { $lockedEntryTypes[] = $entryTypesIdsMap[$typeHandle]; diff --git a/src/templates/settings.twig b/src/templates/settings.twig index 8a675ae..87d7775 100755 --- a/src/templates/settings.twig +++ b/src/templates/settings.twig @@ -16,20 +16,19 @@ {% extends "_layouts/cp" %} {% import "_includes/forms" as forms %} +{% set siteHandle = siteHandle ?? craft.app.getSites().getPrimarySite().handle %} +{% set siteId = siteId ?? craft.app.getSites().getPrimarySite().id %} + + {% do view.registerAssetBundle("fostercommerce\\entrytyperules\\assetbundles\\entrytyperules\\EntryTypeRulesSettingsAsset") %} {% set title = "Entry Type Rules"|t('entry-type-rules') %} {% set fullPageForm = true %} -{% set crumbs = [ - { - label: 'Settings'|t('entry-type-rules'), - url: url('settings'), - } -] %} {% set configOverride = overrides.sections is defined %} -{% set sections = craft.app.entries.getAllSections() %} +{# If we are using overrides from a config file then use those values otherwise use the settings #} +{% set configSettings = configOverride ? overrides : (settings ?? []) %} {% set groupOptions = [] %} {% for group in craft.app.userGroups.allGroups %} @@ -66,8 +65,12 @@ value: 'entry-type-rules'}) }} - {% for section in sections | filter(section => section.type != 'single') %} + {{ forms.hidden({ + name: 'siteId', + value: siteId + })}} + {% for section in sections | filter(section => section.type != 'single') %} {% if not loop.first %}
{% endif %}
@@ -104,7 +107,7 @@ {% for entryType in section.entryTypes %} {% set entryTypeCount = craft.entries.section(section.handle).type(entryType.handle).count %} - {% set limitValue = settings.sections[section.handle][entryType.handle].limit|default('') %} + {% set limitValue = configSettings.sections[section.handle][entryType.handle].limit[siteHandle]|default('') %} {{ entryType.name }} {{ entryType.handle }}
@@ -120,7 +123,7 @@
{{ forms.textField({ id: (entryType.handle ~ '_limit'), - name: ('sections[' ~ section.handle ~ ']['~ entryType.handle ~ '][limit]'), + name: ('sections[' ~ section.handle ~ ']['~ entryType.handle ~ '][limit][' ~ siteHandle ~ ']'), type: 'number', size: 5, min: 0, @@ -133,11 +136,11 @@ {{ forms.checkboxSelectField({ id: (entryType.handle ~ '_userGroups'), - name: ('sections[' ~ section.handle ~ ']['~ entryType.handle ~ '][userGroups]'), + name: ('sections[' ~ section.handle ~ ']['~ entryType.handle ~ '][userGroups][' ~ siteHandle ~']'), options: groupOptions, showAllOption: true, allValue: '', - values: settings.sections[section.handle][entryType.handle].userGroups|default('') + values: configSettings.sections[section.handle][entryType.handle].userGroups[siteHandle]|default('') }) }}