Мои объекты компании нуждаются в защите от программистов, нарушающих отношения, поэтому нам необходимо привязать имя пользователя к каждому объекту. Мы все еще хотели бы провести рефакторинг и очистку устаревшего кода и иметь структуру вокруг этого. Наш постоянный аргумент заключается в том, что некоторые CRUD-подобные действия над объектом должны вызываться пользователем, например.
$user = new User('usernameExample');
$profileData = $user->getProfile(12313);
echo json_encode($profileData);
$ID = $user->createProfile($_POST);
$user->updateProfile($_POST);
$user->refreshProfile(12321394);
$user->deleteProfile(234242);
$user = new User('usernameExample');
$batches = $user->getGroupList();
$user->updateGroup($_POST);
$user->deleteGroup(23242);
$newBatchID = $user->createGroup();
$user = new User('usernameExample');
$user->addSubuser($_POST);
$user->deleteSubuser('usernameExample');
$user->updateSubuser($_POST);
$user->getSubusers();
$user new User('usernameExample');
$user->updateSetting($_POST);
Значительно ли добавляется 50 или около того методов для объекта User или все должно быть разбито на основе и передано имя пользователя или неизменный объект пользователя? Пример ниже
$userProfiles = new UserProfile('usernameExample');
$profileData = $userProfile->getProfile(12313);
Встраивание большого количества функциональных возможностей в ваши бизнес-объекты для управления взаимодействием с другими объектами может быть ужасно быстрым, особенно если вы имеете дело со сложными отношениями и логикой.
Первым шагом за пределами архитектуры такого типа обычно является реализация классов обслуживания для облегчения взаимодействия между вашими объектами.
Учтите следующее:
<?php
/**
* Class UserBasedServiceAbstract
* Base class for our user based services. All services must be instantiated
* with a valid user
*/
abstract class UserBasedServiceAbstract
{
protected $user;
/**
* UserBasedServiceAbstract constructor.
* @param User $user
* @throws Exception
*/
public function __construct(User $user)
{
if($user->isNew())
{
throw new Exception('User must be persisted before doing anything useful with it');
}
$this->user = $user;
}
/**
* @param $message
*/
protected function logAction($message)
{
$formattedMessage = (is_array($message)) ? json_encode($message):$message;
echo 'User action for '.$this->user->getUsername().': '.$formattedMessage;
}
}
class GroupService extends UserBasedServiceAbstract
{
/**
* Get a list of groups that the current user belongs to
* @return array
*/
public function getGroupList()
{
// We always have a reference to our user
$userId = $this->user->getId();
$this->logAction('Getting group list');
//Fetch groups for user
$groupList = [];
return $groupList;
}
/**
* Update the specified group if the current user has permission to do so
* @param Group $group
* @param array $params
* @throws Exception
*/
public function updateGroup(Group $group, array $params)
{
if(!$this->_userCanUpdateGroup())
{
throw new Exception('User does not have permission to update this group');
}
$this->logAction('Updating group');
//update group
}
/**
* Delete the specified group if the current user has permission to do so
* @param Group $group
* @throws Exception
*/
public function deleteGroup(Group $group)
{
if(!$this->_userCanDeleteGroup($group))
{
throw new Exception('User does not have permission to delete this group');
}
$this->logAction('Deleting group');
//delete group
}
/**
* Determine whether or not the current user can delete the specified group
* @param Group $group
* @return bool
* @throws Exception
*/
private function _userCanDeleteGroup(Group $group)
{
//Maybe there is some logic we need to check on the group before we go further
if(!$group->isDeletable())
{
throw new Exception('This group cannot be deleted');
}
// Implement some user-specific logic
return ($this->user->hasPermission('group_admin') && $this->user->getKarma()>100);
}
/**
* Determine whether or not the current user can update the specified group
* @return bool
*/
private function _userCanUpdateGroup()
{
// Implement some user-specific logic
return ($this->user->hasPermission('group_moderator') && $this->user->getKarma()>50);
}
}
Вы создаете абстрактный класс с необходимыми вам общими функциями, а также для проверки и хранения ссылки на вашего пользователя. Все ваши сервисы, которые должны базироваться на пользовательском экземпляре, расширяют этот класс и облегчают взаимодействие между пользовательским объектом и связанными объектами. Вся ваша логика вокруг разрешений идет в эти классы обслуживания. Это намного проще в обслуживании, чем вставлять все это в бизнес-объекты.
Такой подход может увести вас далеко. ОО-космонавты могут посоветовать вам взглянуть на шаблоны проектирования, такие как шаблон посредника, для такого рода вещей, и это определенно может работать хорошо, но всегда есть компромисс между сложностью и простотой использования. Для большинства тяжелых приложений CRUD этот подход, основанный на сервисах, мне нравится.
Других решений пока нет …