Chain of Responsibility (Sorumluluk zinciri) tasarım deseni, gelen isteği liste içindeki classlara verir ve alakalı olan tarafından işlenmesini sağlar. "İstek bana geldi bende gerekeni yaptım. Şimdi sıradaki onu işleyebilir ve işini bitirebilir" demeye benzer. Zincir sıralaması önemlidir. Örnek: Sistemi kullanmak isteyen kullanıcının önce kullanıcı adı ve şifresi kontrol edilir. Doğru ise kullanıcının aktif olup olmadığına bakılır. Aktif ise gerekli izini olup olmadığı kontrol edilir. Eğer varsa sistem kullanılabilir. Aşağıdaki örnek bunu yapar. Daha fazla bilgi için Chain-of-responsibility pattern sayfasını okuyun.




Zincir classları


AbstractChain


declare(strict_types=1);

abstract class AbstractChain
{
/** @var self */
private $next;

public function linkNext(self $next): self
{
$this->next = $next;

return $next;
}

public function check(User $user): bool
{
return $this->next ? $this->next->check($user) : true;
}
}

CredentialChain


declare(strict_types=1);

class CredentialChain extends AbstractChain
{
private $validCredentials = [
['username' => 'hello', 'password' => '123123'],
['username' => 'inanzzz', 'password' => '321321'],
['username' => 'inanzzz', 'password' => '123123']
];

public function check(User $user): bool
{
foreach ($this->validCredentials as $validCredential) {
if (
$user->getUsername() === $validCredential['username'] &&
$user->getPassword() === $validCredential['password']
) {
return parent::check($user);
}
}

throw new Exception('Invalid credentials.');
}
}

StatusChain


declare(strict_types=1);

class StatusChain extends AbstractChain
{
public function check(User $user): bool
{
if ($user->isActive()) {
return parent::check($user);
}

throw new Exception('Invalid status.');
}
}

RoleChain


declare(strict_types=1);

class RoleChain extends AbstractChain
{
private $validRoles = [
'STUDENT',
'LECTURER',
'ADMIN',
];

public function check(User $user): bool
{
foreach ($this->validRoles as $validRole) {
if ($user->getRole() === $validRole) {
return parent::check($user);
}
}

throw new Exception('Invalid role.');
}
}

Diğer classlar


User


declare(strict_types=1);

class User
{
private $username;
private $password;
private $role;
private $isActive;

public function __construct(string $username, string $password, string $role, bool $isActive)
{
$this->username = $username;
$this->password = $password;
$this->role = $role;
$this->isActive = $isActive;
}

public function getUsername(): string
{
return $this->username;
}

public function getPassword(): string
{
return $this->password;
}

public function getRole(): string
{
return $this->role;
}

public function isActive(): bool
{
return $this->isActive;
}
}

Authenticate


declare(strict_types=1);

class Authenticate
{
private $chain;

public function __construct(AbstractChain $chain)
{
$this->chain = $chain;
}

public function login(User $user): bool
{
return $this->chain->check($user);
}
}

Test


declare(strict_types=1);

require_once 'AbstractChain.php';
require_once 'CredentialChain.php';
require_once 'StatusChain.php';
require_once 'RoleChain.php';
require_once 'User.php';
require_once 'Authenticate.php';

$chain = new CredentialChain();
$chain
->linkNext(new StatusChain())
->linkNext(new RoleChain());

try {
(new Authenticate($chain))
->login(
new User('inanzzz', '123123', 'ADMIN', true)
);

echo 'Success'.PHP_EOL;
} catch (Exception $e) {
echo $e->getMessage().PHP_EOL;
}

Sonuç


# Success
new User('inanzzz', '123123', 'ADMIN', true)

# Invalid credentials.
new User('inanzzzA', '123123', 'ADMIN', true)
new User('inanzzz', '1231230', 'ADMIN', true)

# Invalid status.
new User('inanzzz', '123123', 'ADMIN', false)

# Invalid role.
new User('inanzzz', '123123', 'UUU', true)