src/Products/NotificationsBundle/Subscriber/OneRoster/OneRosterUserFixSubscriber.php line 95

Open in your IDE?
  1. <?php
  2. namespace Products\NotificationsBundle\Subscriber\OneRoster;
  3. use Cms\CoreBundle\Entity\AbstractOneRosterEntity;
  4. use Cms\CoreBundle\Entity\OneRoster\OneRosterUser;
  5. use Cms\CoreBundle\Entity\OneRosterSync;
  6. use Cms\CoreBundle\Events\OneRosterFixEvent;
  7. use Doctrine\Common\Util\ClassUtils;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. /**
  10.  * Class OneRosterUserFixSubscriber
  11.  * @package Products\NotificationsBundle\Subscriber\OneRoster
  12.  */
  13. final class OneRosterUserFixSubscriber extends AbstractNotificationsOneRosterSubscriber implements EventSubscriberInterface
  14. {
  15.     /**
  16.      * {@inheritdoc}
  17.      */
  18.     static public function getSubscribedEvents(): array
  19.     {
  20.         return [
  21.             OneRosterFixEvent::EVENT__USER => [
  22.                 ['teacherGrades'0],
  23.                 ['parentOrgs'0],
  24.                 ['parentGrades'0],
  25.             ],
  26.         ];
  27.     }
  28.     /**
  29.      * @param OneRosterFixEvent $event
  30.      */
  31.     public function teacherGrades(OneRosterFixEvent $event): void
  32.     {
  33.         // ensure we are meant to process this
  34.         if ( ! $this->checkTypes($event->getJob(), [
  35.             OneRosterSync::STRATEGIES__NOTIFICATIONS__STAFF,
  36.         ])) {
  37.             return;
  38.         }
  39.         // get the user
  40.         $user $event->getEntity();
  41.         if ( ! $user instanceof OneRosterUser) {
  42.             throw new \Exception(sprintf(
  43.                 'User is not of proper type, got "%s".',
  44.                 ClassUtils::getClass($user)
  45.             ));
  46.         }
  47.         // branch on the role type
  48.         switch (true) {
  49.             case $user->getRole() === AbstractOneRosterEntity::ENUMS__ROLE_TYPE__TEACHER:
  50.                 // noop, code will continue after the switch statement
  51.                 break;
  52.             default:
  53.                 // DEBUGGING
  54.                 $event->getOutput()->writeln(sprintf(
  55.                     'User role for #%s is "%s", skipping...',
  56.                     $user->getSourcedId(),
  57.                     $user->getRole()
  58.                 ));
  59.                 // return to prevent further processing
  60.                 return;
  61.         }
  62.         // clear out the grades already there
  63.         $user->setGrades([]);
  64.         // get grades from api and loop over them
  65.         foreach ($this->oneroster->api($event->getJob())->getTeacherClasses($user->getSourcedId()) as $course) {
  66.             // set the grades for the teacher by reducing down the class data for them
  67.             $user->setGrades(array_values(array_filter(array_unique(array_merge(
  68.                 $user->getGrades(),
  69.                 $course['grades'] ?? []
  70.             )))));
  71.         }
  72.         // TODO: track dirty flags properly depending on whether or not this entity was changed
  73.         // save the changes
  74.         $this->em->save($user);
  75.     }
  76.     /**
  77.      * @param OneRosterFixEvent $event
  78.      */
  79.     public function parentOrgs(OneRosterFixEvent $event): void
  80.     {
  81.         // ensure we are meant to process this
  82.         if ( ! $this->checkTypes($event->getJob(), [
  83.             OneRosterSync::STRATEGIES__NOTIFICATIONS__FAMILY,
  84.         ])) {
  85.             return;
  86.         }
  87.         // get the user
  88.         $user $event->getEntity();
  89.         if ( ! $user instanceof OneRosterUser) {
  90.             throw new \Exception(sprintf(
  91.                 'User is not of proper type, got "%s".',
  92.                 ClassUtils::getClass($user)
  93.             ));
  94.         }
  95.         // branch on the role type
  96.         switch (true) {
  97.             case $user->isRoleFamily():
  98.                 // noop, code will continue after the switch statement
  99.                 break;
  100.             default:
  101.                 // DEBUGGING
  102.                 $event->getOutput()->writeln(sprintf(
  103.                     'User role for #%s is "%s", skipping...',
  104.                     $user->getSourcedId(),
  105.                     $user->getRole()
  106.                 ));
  107.                 // return to prevent further processing
  108.                 return;
  109.         }
  110.         // obtain the orgs already on the user
  111.         // TODO: should it be assumed that the core orgs reset on every stash so as orgs fall off, they are removed properly?
  112.         $orgs = [];
  113.         foreach ($user->getOrgs() as $org) {
  114.             $orgs[$org['sourcedId']] = $org;
  115.         }
  116.         // loop over the agent data from gg4l, this contains links back to applicable students
  117.         $studentSourcedIds = [];
  118.         foreach ($user->getAgents() as $agent) {
  119.             // make sure the agent association is that of a student
  120.             if (array_key_exists('type'$agent) && in_array($agent['type'], [AbstractOneRosterEntity::ENUMS__ROLE_TYPE__USERAbstractOneRosterEntity::ENUMS__ROLE_TYPE__STUDENT])) {
  121.                 // attach the current id to the array so that we can pull in one database query
  122.                 $studentSourcedIds[] = $agent['sourcedId'];
  123.             }
  124.         }
  125.         // query database for the student records we need
  126.         $students $studentSourcedIds $this->em->getRepository(OneRosterUser::class)->findBy([
  127.             'sourcedId' => $studentSourcedIds
  128.         ]) : [];
  129.         // if the count is off, that's a problem, but one we can get around
  130.         // just log the error but continue
  131.         if (count($students) != count($studentSourcedIds)) {
  132.             // TODO
  133.         }
  134.         // loop over the found students
  135.         $changed false;
  136.         foreach ($students as $student) {
  137.             // loop over the orgs the student is tied to
  138.             foreach ($student->getOrgs() as $org) {
  139.                 // if we are not already in the tracked orgs, add it
  140.                 if ( ! array_key_exists($org['sourcedId'], $orgs)) {
  141.                     // do the addition
  142.                     $orgs[$org['sourcedId']] = $org;
  143.                     // track the change
  144.                     $changed true;
  145.                 }
  146.             }
  147.         }
  148.         // TODO: track dirty flags properly depending on whether or not this entity was changed
  149.         // update the orgs on the user only if changes are tracked
  150.         if ($changed) {
  151.             $this->em->save(
  152.                 $user->setOrgs($orgs)
  153.             );
  154.         }
  155.     }
  156.     /**
  157.      * @param OneRosterFixEvent $event
  158.      */
  159.     public function parentGrades(OneRosterFixEvent $event): void
  160.     {
  161.         // ensure we are meant to process this
  162.         if ( ! $this->checkTypes($event->getJob(), [
  163.             OneRosterSync::STRATEGIES__NOTIFICATIONS__FAMILY,
  164.         ])) {
  165.             return;
  166.         }
  167.         // get the user
  168.         $user $event->getEntity();
  169.         if ( ! $user instanceof OneRosterUser) {
  170.             throw new \Exception(sprintf(
  171.                 'User is not of proper type, got "%s".',
  172.                 ClassUtils::getClass($user)
  173.             ));
  174.         }
  175.         // branch on the role type
  176.         switch (true) {
  177.             case $user->isRoleFamily():
  178.                 // noop, code will continue after the switch statement
  179.                 break;
  180.             default:
  181.                 // DEBUGGING
  182.                 $event->getOutput()->writeln(sprintf(
  183.                     'User role for #%s is "%s", skipping...',
  184.                     $user->getSourcedId(),
  185.                     $user->getRole()
  186.                 ));
  187.                 // return to prevent further processing
  188.                 return;
  189.         }
  190.         // reset the grades
  191.         $user->setGrades([]);
  192.         // loop over the agent data from gg4l, this contains links back to applicable students
  193.         $studentSourcedIds = [];
  194.         foreach ($user->getAgents() as $agent) {
  195.             // make sure the agent association is that of a student
  196.             if (array_key_exists('type'$agent) && in_array($agent['type'], [AbstractOneRosterEntity::ENUMS__ROLE_TYPE__STUDENT])) {
  197.                 // attach the current id to the array so that we can pull in one database query
  198.                 $studentSourcedIds[] = $agent['sourcedId'];
  199.             }
  200.         }
  201.         // query database for the student records we need
  202.         $students $studentSourcedIds $this->em->getRepository(OneRosterUser::class)->findBy([
  203.             'sourcedId' => $studentSourcedIds
  204.         ]) : [];
  205.         // if the count is off, that's a problem, but one we can get around
  206.         // just log the error but continue
  207.         if (count($students) != count($studentSourcedIds)) {
  208.             // TODO
  209.         }
  210.         // loop over the found students
  211.         foreach ($students as $student) {
  212.             // hack to use gg4l custom fields for grades if that exists
  213.             if (array_key_exists('gg4l.primaryGrade'$student->getMetadata()) && ! empty($student->getMetadata()['gg4l.primaryGrade'])) {
  214.                 $grades = [$student->getMetadata()['gg4l.primaryGrade']];
  215.             } else {
  216.                 $grades $student->getGrades() ?: [];
  217.             }
  218.             // update the grades array
  219.             $user->setGrades(array_values(array_filter(array_unique(array_merge(
  220.                 $user->getGrades(),
  221.                 $grades
  222.             )))));
  223.         }
  224.         // TODO: track dirty flags properly depending on whether or not this entity was changed
  225.         // save the changes
  226.         $this->em->save($user);
  227.     }
  228. }