silverstripe-framework/src/Security/Member_Validator.php

179 lines
5.3 KiB
PHP

<?php
namespace SilverStripe\Security;
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
use SilverStripe\Forms\RequiredFields;
/**
* Member Validator
*
* Custom validation for the Member object can be achieved either through an
* {@link DataExtension} on the Member_Validator object or, by specifying a subclass of
* {@link Member_Validator} through the {@link Injector} API.
* The Validator can also be modified by adding an Extension to Member and implement the
* <code>updateValidator</code> hook.
* {@see Member::getValidator()}
*
* Additional required fields can also be set via config API, eg.
* <code>
* Member_Validator:
* customRequired:
* - Surname
* </code>
*/
class Member_Validator extends RequiredFields
{
/**
* Fields that are required by this validator
* @config
* @var array
* @skipUpgrade
*/
protected $customRequired = [
'FirstName',
'Email'
];
/**
* Determine what member this validator is meant for
* @var Member
*/
protected $forMember = null;
/**
* Constructor
*/
public function __construct()
{
$required = func_get_args();
if (isset($required[0]) && is_array($required[0])) {
$required = $required[0];
}
$required = array_merge($required, $this->customRequired);
// check for config API values and merge them in
$config = $this->config()->customRequired;
if (is_array($config)) {
$required = array_merge($required, $config);
}
parent::__construct(array_unique($required ?? []));
}
/**
* Get the member this validator applies to.
* @return Member
*/
public function getForMember()
{
return $this->forMember;
}
/**
* Set the Member this validator applies to.
* @param Member $value
* @return $this
*/
public function setForMember(Member $value)
{
$this->forMember = $value;
return $this;
}
/**
* Check if the submitted member data is valid (server-side)
*
* Check if a member with that email doesn't already exist, or if it does
* that it is this member.
*
* @param array $data Submitted data
* @return bool Returns TRUE if the submitted data is valid, otherwise
* FALSE.
*/
public function php($data)
{
$valid = parent::php($data);
$identifierField = (string)Member::config()->unique_identifier_field;
// Only validate identifier field if it's actually set. This could be the case if
// somebody removes `Email` from the list of required fields.
$id = isset($data['ID']) ? (int)$data['ID'] : 0;
if (isset($data[$identifierField])) {
if (!$id && ($ctrl = $this->form->getController())) {
// get the record when within GridField (Member editing page in CMS)
if ($ctrl instanceof GridFieldDetailForm_ItemRequest && $record = $ctrl->getRecord()) {
$id = $record->ID;
}
}
// If there's no ID passed via controller or form-data, use the assigned member (if available)
if (!$id && ($member = $this->getForMember())) {
$id = $member->exists() ? $member->ID : 0;
}
// set the found ID to the data array, so that extensions can also use it
$data['ID'] = $id;
$members = Member::get()->filter($identifierField, $data[$identifierField]);
if ($id) {
$members = $members->exclude('ID', $id);
}
if ($members->count() > 0) {
$this->validationError(
$identifierField,
_t(
'SilverStripe\\Security\\Member.VALIDATIONMEMBEREXISTS',
'A member already exists with the same {identifier}',
['identifier' => Member::singleton()->fieldLabel($identifierField)]
),
'required'
);
$valid = false;
}
}
$currentUser = Security::getCurrentUser();
if ($currentUser
&& $id
&& $id === (int)$currentUser->ID
&& Permission::checkMember($currentUser, 'ADMIN')
) {
$stillAdmin = true;
if (!isset($data['DirectGroups'])) {
$stillAdmin = false;
} else {
$adminGroups = array_intersect(
$data['DirectGroups'] ?? [],
Permission::get_groups_by_permission('ADMIN')->column()
);
if (count($adminGroups ?? []) === 0) {
$stillAdmin = false;
}
}
if (!$stillAdmin) {
$this->validationError(
'DirectGroups',
_t(
'SilverStripe\\Security\\Member.VALIDATIONADMINLOSTACCESS',
'Cannot remove all admin groups from your profile'
),
'required'
);
}
}
// Execute the validators on the extensions
$results = $this->extend('updatePHP', $data, $this->form);
$results[] = $valid;
return min($results);
}
}