<?php
namespace App\Subscriber\OneRoster;
use App\Entity\System\School;
use App\Util\Booleans;
use Cms\CoreBundle\Entity\OneRoster\OneRosterUser;
use Cms\CoreBundle\Entity\OneRosterSync;
use Cms\CoreBundle\Events\OneRosterProcessEvent;
use Cms\CoreBundle\Model\Interfaces\OneRosterable\AbstractOneRosterableSubscriber;
use Cms\CoreBundle\Service\Slugger;
use Cms\CoreBundle\Util\Doctrine\EntityManager;
use Cms\ModuleBundle\Service\DraftManager;
use Cms\Modules\PeopleBundle\Entity\Profile\ProfileProxy;
use Doctrine\Common\Util\ClassUtils;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
*/
final class OneRosterUserProcessSubscriber extends AbstractOneRosterableSubscriber
{
// DI
protected DraftManager $dm;
/**
* @param EntityManager $em
* @param TranslatorInterface $translator
* @param DraftManager $dm
*/
public function __construct(
EntityManager $em,
TranslatorInterface $translator,
DraftManager $dm
)
{
parent::__construct(
$em,
$translator
);
$this->dm = $dm;
}
/**
* {@inheritdoc}
*/
static public function getSubscribedEvents(): array
{
return array(
OneRosterProcessEvent::EVENT__USER => array(
array('peopleModuleSync', 0),
),
);
}
/**
* @param OneRosterProcessEvent $event
*/
public function peopleModuleSync(OneRosterProcessEvent $event): void
{
// ensure we are meant to process this
if ( ! $this->checkTypes($event->getSync(), array(
OneRosterSync::STRATEGIES__DIRECTORIES,
))) {
return;
}
// get the user
$user = $event->getEntity();
if ( ! $user instanceof OneRosterUser) {
throw new \Exception(sprintf(
'User is not of proper type, got "%s".',
ClassUtils::getClass($user)
));
}
// branch on the role type
switch (true) {
case $this->checkTypes($event->getSync(), [OneRosterSync::STRATEGIES__DIRECTORIES]) && $user->isRoleStaff():
break;
default:
// DEBUGGING
$event->getOutput()->writeln(sprintf(
'User role for #%s is "%s", skipping...',
$user->getSourcedId(),
$user->getRole()
));
return;
}
// get the org ids for the user
$sourcedIds = array_map(
function (array $org) {
return $org['sourcedId'];
},
$user->getOrgs()
);
// TODO: can't quit early as we may need to remove schools that don't belong...
// if no ids, need to quit
if ( ! $sourcedIds) {
return;
}
// find the schools tied to these orgs
// we may have missing schools, so that's not anything to worry about really
// maybe someday we will treat it as more of an error or something
$schools = $this->em->getRepository(School::class)->findBy([
'oneRosterOrg' => $sourcedIds,
]);
// we need to filter out schools that do not have web departments hooked up to them
$schools = array_values(array_filter(array_map(
function (School $school) {
return $school->getDepartment() ? $school : null;
},
$schools
)));
// if no schools, just quit, makes for easier debugging
if ( ! $schools) {
return;
}
// now we should have schools with web departments
// loop over each
/** @var School $school */
foreach ($schools as $school) {
// attempt to find a people entry in the given web department
// first try to match by oneroster id
$proxy = $this->em->getRepository(ProfileProxy::class)->findOneBy([
'container' => $school->getDepartment(),
'onerosterId' => $user->getSourcedId(),
]);
// if not found by oneroster id, try again by email
if ( ! $proxy) {
// user must have an email address to progress further
if ( ! $user->getEmail()) {
return;
}
// find by email match
$proxy = $this->em->getRepository(ProfileProxy::class)->findOneBy([
'container' => $school->getDepartment(),
'data_email' => $user->getEmail(),
]);
}
// if we have one, but we are flagged for deletion, we need to remove the proxy or something
if ($proxy && $user->isStatusToBeDeleted()) {
// TODO: should we discard so we don't lose other info, or just delete?
}
// if we still don't have one, we have to make one
if ( ! $proxy instanceof ProfileProxy) {
$proxy = new ProfileProxy();
}
// need to generate the slug
$slug = Slugger::slug(trim(implode(' ', [
$user->getGivenName(),
$user->getFamilyName(),
])));
// need to determine if we really need to update this thing or not to save db entries
$updated = [
($proxy->getOneRosterId() !== $user->getSourcedId()),
($proxy->getOneRosterArchived() !== $user->isStatusToBeDeleted()),
($proxy->getData()->getEmail() !== $user->getEmail()),
($proxy->getData()->getFirstName() !== $user->getGivenName()),
($proxy->getData()->getLastName() !== $user->getFamilyName()),
($proxy->getData()->getSlug() !== $slug),
($proxy->getData()->getTitle() !== $user->getRole()),
];
// if nothing to do, and we are not new, skip
if ($proxy->getId() && ! Booleans::orX(...$updated)) {
// DEBUGGING
$event->getOutput()->writeln(sprintf(
' %s %s (PEOPLE MODULE PROFILE %s | %s | %s)',
'Skipping',
ClassUtils::getClass($proxy),
$proxy->getData()->getEmail(),
$proxy->getOneRosterId(),
$proxy->getId() ?: '-'
));
continue;
}
// set things
$proxy
->setOneRosterId($user->getSourcedId())
->setOneRosterArchived($user->isStatusToBeDeleted())
->getData()
->setEmail($user->getEmail())
->setFirstName($user->getGivenName())
->setLastName($user->getFamilyName())
->setSlug($slug)
->setTitle($user->getRole())
;
// DEBUGGING
$event->getOutput()->writeln(sprintf(
' %s %s (PEOPLE MODULE PROFILE %s | %s | %s)',
(empty($proxy->getId())) ? 'Generating' : 'Updating',
ClassUtils::getClass($proxy),
$proxy->getData()->getEmail(),
$proxy->getOneRosterId(),
$proxy->getId() ?: '-'
));
// use the draft manager to save the object
if ( ! $proxy->getId()) {
$this->dm->createProxy($school->getDepartment(), $proxy->getData());
} else {
$this->dm->modifyProxy($proxy, $proxy->getData());
}
}
}
}