module = $module; $this->setModuleTitle($title); } /** * Set module title * @param string|array $title * @return static */ public function setModuleTitle($title) { $this->moduleTitle = $title; return $this; } /** * Add scopes from array * [ * 'scope'|'module:scope' => [ * 'method1', * 'method2' => bool, # any method action * 'method3' => 'action', * 'method4' => ['action1', 'action2' => bool, 'action3' => function () { return bool; }], * 'method5' => function () { return bool; }, * 'method6' => function () { return 'action'; }, * 'method7' => function () { * return ['action1', 'action2' => bool, 'action3' => function () { return bool; }]; * }, * ], * @param array $scopes * @return static */ public function fromArray(array $scopes) { foreach ($scopes as $scope => $methods) { if (! is_string($scope) || ! is_array($methods)) { # wrong scope/methods declaration continue; } $this->scope($scope); foreach ($methods as $key => $value) { if (is_int($key) && is_string($value)) { $this->method($value); continue; } if (is_string($key)) { $this->method($key); if (is_array($value)) { $this->actions($value); } else { $this->action($value); } } } } return $this; } /** * Add scope * @param string $scope * @param string|array $title * @param int|null $order * @return static */ public function scope(string $scope, $title = [], ?int $order = null) { if ($scope === '') { return $this; } $this->activeScope = $scope; if (! array_key_exists($scope, $this->scopes)) { $this->scopes[$scope] = [ 'methods' => [], 'title' => $title, 'order' => $order, ]; } return $this; } /** * Add seo templates scope * @param string $scope * @param array|string|null $methods * @param string|array $title * @param int|null $order * @return static */ public function seoTemplates(string $scope = 'seo', $methods = null, $title = 'SEO', ?int $order = null) { $this->scope($scope, $title, $order); if (array_key_exists($scope, $this->scopes)) { $methods = $methods ?? 'seo_templates_edit'; if (! is_array($methods)) { $methods = [$methods]; } $this->methods($methods); } return $this; } /** * Add scope's method * @param string $method * @return static */ public function method(string $method) { if ($method === '') { return $this; } $method = mb_strtolower($method); $this->activeMethod = $method; if (! is_null($this->activeScope)) { $this->scopes[$this->activeScope]['methods'][$method] = []; } return $this; } /** * Add scope's methods * @param array $methods * @return static */ public function methods(array $methods) { foreach ($methods as $method) { if (is_string($method)) { $this->method($method); } } return $this; } /** * Add scope method's action * @param string|bool|\Closure $action * - true | function () { return true; } - any action * - false | function () { return false; } - no actions * - string - action name + conditions (optional) * @param \Closure|bool|null $conditions * @return static */ public function action($action, $conditions = null) { if ( is_null($this->activeScope) || is_null($this->activeMethod) || ! isset($this->scopes[$this->activeScope]['methods'][$this->activeMethod]) ) { return $this; } $actions = &$this->scopes[$this->activeScope]['methods'][$this->activeMethod]; # conditions if ($action instanceof Closure || is_bool($action)) { $actions = $action; return $this; } # add action (with/without coditions) if (is_string($action) && is_array($actions)) { $actions[mb_strtolower($action)] = $conditions ?? true; } return $this; } /** * Add scope method's actions * @param array $actions * @return static */ public function actions(array $actions) { foreach ($actions as $key => $value) { if (is_string($key)) { $this->action($key, $value); } elseif (is_int($key)) { $this->action($value); } } return $this; } /** * Mark method as public (not public) * @param string|string[] $method * @param bool|\Closure $public * @param string|null $context * @param \Module|string|null $module * @return static */ public function publicMethod($method, $public = true, ?string $context = null, $module = null) { Security::publicMethod($this->getModuleName($module), $method, $public, $context); return $this; } /** * Get method scopes * @param string $method * @param string|null $action * @return array */ public function getMethodScopes(string $method, ?string $action = null): array { $method = mb_strtolower($method); if (is_string($action)) { $action = mb_strtolower($action); } $list = []; # [[module, scope], ...] foreach ($this->scopes as $key => $scope) { if (! array_key_exists($method, $scope['methods'])) { # scope has no such method continue; } $actions = $scope['methods'][$method]; if ($actions instanceof Closure) { $actions = $actions(); } if (is_bool($actions)) { if ($actions) { # any action $list[] = $this->parseModuleScope($key); continue; } # no actions allowed continue; } if (! is_array($actions)) { $actions = [$actions]; } if (sizeof($actions) === 0) { # any action $list[] = $this->parseModuleScope($key); continue; } # action in list of allowed if (in_array($action, $actions, true)) { $list[] = $this->parseModuleScope($key); continue; } if (array_key_exists($action, $actions)) { $actionCondition = $actions[$action]; if ($actionCondition instanceof Closure) { $actionCondition = $actionCondition(); } if ($actionCondition) { # action matches conditions $list[] = $this->parseModuleScope($key); continue; } } } return $list; } /** * Prepare module scope * @param string $scope * @return array */ protected function parseModuleScope(string $scope) { # external module if (mb_stripos($scope, ':') !== false) { return explode(':', $scope, 2); } return [$this->getModuleName(), $scope]; } /** * Get module name * @param mixed $module * @return string */ public function getModuleName($module = null) { $module = $module ?? $this->module; if ($module instanceof Module) { return $module->module_name; } if (is_string($module)) { return $module; } return ''; } /** * Scopes listing * @param array $opts * @return array */ public function listing(array $opts = []) { $lang = $opts['lang'] ?? bff()->locale()->current(); $result = []; foreach ($this->scopes as $key => $scope) { $data = [ 'id' => $key, 'title' => '', ]; if (is_array($scope['title'])) { $data['title'] = bff()->locale()->value($scope['title'], $lang); } elseif (is_scalar($scope['title'])) { $data['title'] = $scope['title']; } $result[$key] = $data; } return $result; } }