Last active
January 3, 2019 01:19
-
-
Save mooror/ea2137356ffd392ea0c455d6d5bb1919 to your computer and use it in GitHub Desktop.
My Silverstripe 4 code for auto-generating access permissions for DataObjects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Sitelease\Core\Traits; | |
use ReflectionClass; | |
use SilverStripe\Security\Permission; | |
/** | |
* Adds functionality to automatically create model level access permissions | |
* for a DataObject | |
* | |
* The code requires a boolean configuration property called | |
* "auto_create_permissions" to function. We recommend that | |
* you add this property to a DataExtension applied to the base | |
* "DataObject" class if you want to all models to have permissions | |
* defined be default | |
* | |
* Note: This trait is made to be used in classes that | |
* extend the PermissionsProvider interface. | |
*/ | |
trait AccessPermissionsProvider | |
{ | |
/** | |
* Will attempt to get the suffix from the configuration | |
* property, but if that is empty it will generate one using the | |
* class name. | |
* | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @return string | |
*/ | |
public function getPermissionsSuffix() | |
{ | |
$suffix = $this->config()->get("permissions_suffix"); | |
if (!$suffix) { | |
$namespace = get_called_class(); | |
$reflect = new ReflectionClass($namespace); | |
$className = $reflect->getShortName(); | |
if (substr($className, 0, strlen("SL")) == "SL") { | |
$suffix = strtoupper($className); | |
} else { | |
$suffix = "SL".strtoupper($className); | |
} | |
} | |
$this->extend('updatePermissionsSuffix', $suffix); | |
return $suffix; | |
} | |
/** | |
* Will attempt to get the descriptor from the configuration | |
* property, but if that is empty it will generate one using the | |
* singular_name() method | |
* | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @return string | |
*/ | |
public function getPermissionsDescriptor() | |
{ | |
$descriptor = $this->config()->get("permissions_descriptor"); | |
if (!$descriptor) { | |
$readableClass = $this->singular_name(); | |
$descriptor = strtolower($readableClass); | |
} | |
$this->extend('updatePermissionsDescriptor', $descriptor); | |
return $descriptor; | |
} | |
/** | |
* Will attempt to get the category from the configuration | |
* property, but if that is empty it will generate one using the | |
* plural_name() method | |
* | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @return string | |
*/ | |
public function getPermissionsCategory() | |
{ | |
$category = $this->config()->get("permissions_category"); | |
if (!$category) { | |
$readableClass = $this->plural_name(); | |
$category = ucfirst($readableClass." (Sitelease)"); | |
} | |
$this->extend('updatePermissionsCategory', $category); | |
return $category; | |
} | |
/** | |
* Used to let classes provide new permission codes. | |
* Every implementor of PermissionProvider is accessed and providePermissions() | |
* called to get the full list of permission codes. | |
* | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @return array | |
*/ | |
public function providePermissions() | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
$permissionsArray = $this->permissionsArray; | |
$suffix = $this->getPermissionsSuffix(); | |
$category = $this->getPermissionsCategory(); | |
$descriptor = $this->getPermissionsDescriptor(); | |
$actions = $this->config()->get("permissions_config_array"); | |
if ($actions) { | |
$iterations = 0; | |
foreach ($actions as $actionName => $actionTitle) { | |
// If the title is empty or falsey, create one | |
if (empty($actionTitle) || !$actionTitle) { | |
$actionTitle = ucfirst($actionName); | |
$actionTitle .= " - Allow user to $actionName $descriptor objects"; | |
} | |
$codeActionName = str_replace("-", "_", $actionName); | |
$codeActionName = str_replace(" ", "_", $codeActionName); | |
$permissionCode = strtoupper($codeActionName) . '_' . $suffix; | |
$permissionsArray[$permissionCode] = array( | |
'name' => $actionTitle, | |
'help' => 'Permission Code: '.$permissionCode, | |
'category' => $category, | |
'sort' => 99-$iterations | |
); | |
$iterations++; | |
} | |
} | |
$this->extend('updateProvidePermissions', $permissionsArray); | |
return $permissionsArray; | |
} else { | |
return false; | |
} | |
} | |
/** | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @param Member $member | |
* @return boolean | |
*/ | |
public function canView($member = null) | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
return array(Permission::check('VIEW_' . $this->getPermissionsSuffix(), 'any', $member)); | |
} else { | |
$accessGranted = Permission::check('ADMIN', 'any', $member); | |
$this->extend('updateCanView', $accessGranted); | |
return $accessGranted; | |
} | |
} | |
/** | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @param Member $member | |
* @return boolean | |
*/ | |
public function canEdit($member = null) | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
return array(Permission::check('EDIT_' . $this->getPermissionsSuffix(), 'any', $member)); | |
} else { | |
$accessGranted = Permission::check('ADMIN', 'any', $member); | |
$this->extend('updateCanEdit', $accessGranted); | |
return $accessGranted; | |
} | |
} | |
/** | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @param Member $member | |
* @return boolean | |
*/ | |
public function canDelete($member = null) | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
return array(Permission::check('DELETE_' . $this->getPermissionsSuffix(), 'any', $member)); | |
} else { | |
$accessGranted = Permission::check('ADMIN', 'any', $member); | |
$this->extend('updateCanDelete', $accessGranted); | |
return $accessGranted; | |
} | |
} | |
/** | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @param Member $member | |
* @param array $context Additional context-specific data which might | |
* affect whether (or where) this object could be created. | |
* @return boolean | |
*/ | |
public function canCreate($member = null, $context = array()) | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
return array(Permission::check('CREATE_' . $this->getPermissionsSuffix(), 'any', $member)); | |
} else { | |
$accessGranted = Permission::check('ADMIN', 'any', $member); | |
$this->extend('updateCanCreate', $accessGranted); | |
return $accessGranted; | |
} | |
} | |
/** | |
* @author Benjamin Blake (sitelease.ca) | |
* | |
* @param Member $member | |
* @return boolean | |
*/ | |
public function canAccessExperimental($member = null) | |
{ | |
$autoCreatePermissions = $this->config()->get("auto_create_permissions"); | |
if ($autoCreatePermissions) { | |
return array(Permission::check('EXPERIMENTAL_ACCESS_' . $this->getPermissionsSuffix(), 'any', $member)); | |
} else { | |
$accessGranted = Permission::check('ADMIN', 'any', $member); | |
$this->extend('updateCanAccessExperimental', $accessGranted); | |
return $accessGranted; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Sitelease\Core\Extensions; | |
use SilverStripe\ORM\DataExtension; | |
class AccessPermissionsProviderExtension extends DataExtension | |
{ | |
/** | |
* @var boolean | |
* @config | |
*/ | |
private static $auto_create_permissions = true; | |
/** | |
* A string that will be appended to the action name | |
* for the permission code. | |
* | |
* Should start with "SL", be uppercase, and contain | |
* the model (DataObject) name | |
* | |
* @var boolean|string | |
* @config | |
*/ | |
private static $permissions_suffix = false; | |
/** | |
* A string that will be used in the generation of the permission | |
* description for items that don't have the discription explicitly set | |
* | |
* Usually will be set to a fully lowercase version of your object name. | |
* | |
* Example: A DataObject called "Products" you might use "products" | |
* | |
* @var boolean|string | |
* @config | |
*/ | |
private static $permissions_descriptor = false; | |
/** | |
* A string that will be used as the heading that all of the | |
* permission checkboxes will be displayed under (on permissions tabs) | |
* | |
* Usually set to a human readable version of the DataObject name, | |
* followed by the name of the composer vendor in brackets. | |
* | |
* Example: For a DataObject called "Products" in a module | |
* created by the "Sitelease" vendor you would use "Products (Sitelease)" | |
* | |
* @var boolean|string | |
* @config | |
*/ | |
private static $permissions_category = false; | |
/** | |
* An array that contains a key value pair for each action that you | |
* want the providePermissions() method to auto create for this DataObject | |
* | |
* The item key must contain the action/permission name while the key can | |
* either contain a custom description (that will be displayed on permission | |
* tabs) or false. | |
* | |
* If you leave the item value empty (or set it to false) a description will be | |
* generated for you. | |
* | |
* @var boolean|array | |
* @config | |
*/ | |
private static $permissions_config_array = array( | |
'view' => "", | |
'edit' => "", | |
'delete' => "", | |
'create' => "", | |
"experimental-access" => "Access Experimental Features - Allow user to use experimental fields and settings" | |
); | |
/** | |
* A variable that will be updated and ultimatly returned | |
* by the providePermissions() method | |
* | |
* You can manually add extra action permissions to this | |
* DataObject by adding items to this array using the following syntax: | |
* ``` | |
* "ACTIONNAME_SLSUFFIX" => array( | |
* "name" => "Action Name - Permission description", | |
* "help" => "Permission Code: ACTIONNAME_SLSUFFIX", | |
* "category" => "Category Title (Sitelease)", | |
* "sort" => 99 | |
* ) | |
*``` | |
* @var array | |
*/ | |
public $permissionsArray = array(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
Name: coreconfig | |
--- | |
# Add relationship abstraction methods to the DataObject via a extension | |
SilverStripe\ORM\DataObject: | |
extensions: | |
- Sitelease\Core\Extensions\AccessPermissionsProviderExtension |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use SilverStripe\ORM\DataObject; | |
use SilverStripe\Security\PermissionProvider; | |
use Sitelease\Core\Traits\AccessPermissionsProvider; | |
class ExampleModel extends DataObject implements PermissionProvider | |
{ | |
// Create model level permissions for this class | |
use AccessPermissionsProvider; | |
private static $table_name = 'ExampleModel'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment