vendor/contao/core-bundle/src/Resources/contao/classes/BackendUser.php line 135

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. use Contao\CoreBundle\Exception\RedirectResponseException;
  11. use Contao\CoreBundle\Security\ContaoCorePermissions;
  12. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  13. use Symfony\Component\Security\Core\User\UserInterface;
  14. /**
  15.  * Provide methods to manage back end users.
  16.  *
  17.  * @property boolean $isAdmin
  18.  * @property array   $groups
  19.  * @property array   $elements
  20.  * @property array   $fields
  21.  * @property array   $pagemounts
  22.  * @property array   $filemounts
  23.  * @property array   $filemountIds
  24.  * @property string  $fop
  25.  * @property array   $alexf
  26.  * @property array   $imageSizes
  27.  */
  28. class BackendUser extends User
  29. {
  30.     /**
  31.      * Edit page flag
  32.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_EDIT_PAGE.
  33.      */
  34.     const CAN_EDIT_PAGE 1;
  35.     /**
  36.      * Edit page hierarchy flag
  37.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_EDIT_PAGE_HIERARCHY.
  38.      */
  39.     const CAN_EDIT_PAGE_HIERARCHY 2;
  40.     /**
  41.      * Delete page flag
  42.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_DELETE_PAGE.
  43.      */
  44.     const CAN_DELETE_PAGE 3;
  45.     /**
  46.      * Edit articles flag
  47.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_EDIT_ARTICLES.
  48.      */
  49.     const CAN_EDIT_ARTICLES 4;
  50.     /**
  51.      * Edit article hierarchy flag
  52.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_EDIT_ARTICLE_HIERARCHY.
  53.      */
  54.     const CAN_EDIT_ARTICLE_HIERARCHY 5;
  55.     /**
  56.      * Delete articles flag
  57.      * @deprecated Deprecated since Contao 4.13. Use Symfony security and ContaoCorePermissions::USER_CAN_DELETE_ARTICLES.
  58.      */
  59.     const CAN_DELETE_ARTICLES 6;
  60.     /**
  61.      * Symfony Security session key
  62.      * @deprecated Deprecated since Contao 4.8, to be removed in Contao 5.0
  63.      */
  64.     const SECURITY_SESSION_KEY '_security_contao_backend';
  65.     /**
  66.      * Current object instance (do not remove)
  67.      * @var BackendUser
  68.      */
  69.     protected static $objInstance;
  70.     /**
  71.      * Name of the corresponding table
  72.      * @var string
  73.      */
  74.     protected $strTable 'tl_user';
  75.     /**
  76.      * Name of the current cookie
  77.      * @var string
  78.      */
  79.     protected $strCookie 'BE_USER_AUTH';
  80.     /**
  81.      * Allowed excluded fields
  82.      * @var array
  83.      */
  84.     protected $alexf = array();
  85.     /**
  86.      * File mount IDs
  87.      * @var array
  88.      */
  89.     protected $arrFilemountIds;
  90.     /**
  91.      * Symfony security roles
  92.      * @var array
  93.      */
  94.     protected $roles = array('ROLE_USER');
  95.     /**
  96.      * Initialize the object
  97.      */
  98.     protected function __construct()
  99.     {
  100.         parent::__construct();
  101.         $this->strIp Environment::get('ip');
  102.         $this->strHash Input::cookie($this->strCookie);
  103.     }
  104.     /**
  105.      * Instantiate a new user object
  106.      *
  107.      * @return static|User The object instance
  108.      */
  109.     public static function getInstance()
  110.     {
  111.         if (static::$objInstance !== null)
  112.         {
  113.             return static::$objInstance;
  114.         }
  115.         $objToken System::getContainer()->get('security.token_storage')->getToken();
  116.         // Load the user from the security storage
  117.         if ($objToken !== null && is_a($objToken->getUser(), static::class))
  118.         {
  119.             return $objToken->getUser();
  120.         }
  121.         // Check for an authenticated user in the session
  122.         $strUser System::getContainer()->get('contao.security.token_checker')->getBackendUsername();
  123.         if ($strUser !== null)
  124.         {
  125.             static::$objInstance = static::loadUserByIdentifier($strUser);
  126.             return static::$objInstance;
  127.         }
  128.         return parent::getInstance();
  129.     }
  130.     /**
  131.      * Extend parent getter class and modify some parameters
  132.      *
  133.      * @param string $strKey
  134.      *
  135.      * @return mixed
  136.      */
  137.     public function __get($strKey)
  138.     {
  139.         switch ($strKey)
  140.         {
  141.             case 'isAdmin':
  142.                 return $this->arrData['admin'] ? true false;
  143.             case 'groups':
  144.                 return \is_array($this->arrData['groups']) ? $this->arrData['groups'] : ($this->arrData['groups'] ? array($this->arrData['groups']) : array());
  145.             case 'pagemounts':
  146.                 return \is_array($this->arrData['pagemounts']) ? $this->arrData['pagemounts'] : ($this->arrData['pagemounts'] ? array($this->arrData['pagemounts']) : false);
  147.             case 'filemounts':
  148.                 return \is_array($this->arrData['filemounts']) ? $this->arrData['filemounts'] : ($this->arrData['filemounts'] ? array($this->arrData['filemounts']) : false);
  149.             case 'filemountIds':
  150.                 return $this->arrFilemountIds;
  151.             case 'fop':
  152.                 return \is_array($this->arrData['fop']) ? $this->arrData['fop'] : ($this->arrData['fop'] ? array($this->arrData['fop']) : false);
  153.             case 'alexf':
  154.                 return $this->alexf;
  155.         }
  156.         return parent::__get($strKey);
  157.     }
  158.     /**
  159.      * Redirect to the login screen if authentication fails
  160.      *
  161.      * @return boolean True if the user could be authenticated
  162.      *
  163.      * @deprecated Deprecated since Contao 4.5, to be removed in Contao 5.0.
  164.      *             Use Symfony security instead.
  165.      */
  166.     public function authenticate()
  167.     {
  168.         trigger_deprecation('contao/core-bundle''4.5''Using "Contao\BackendUser::authenticate()" has been deprecated and will no longer work in Contao 5.0. Use Symfony security instead.');
  169.         // Do not redirect if authentication is successful
  170.         if (System::getContainer()->get('contao.security.token_checker')->hasBackendUser())
  171.         {
  172.             return true;
  173.         }
  174.         if (!$request System::getContainer()->get('request_stack')->getCurrentRequest())
  175.         {
  176.             return false;
  177.         }
  178.         $route $request->attributes->get('_route');
  179.         if ($route == 'contao_backend_login')
  180.         {
  181.             return false;
  182.         }
  183.         $url System::getContainer()->get('router')->generate('contao_backend_login', array('redirect' => $request->getUri()), UrlGeneratorInterface::ABSOLUTE_URL);
  184.         throw new RedirectResponseException(System::getContainer()->get('uri_signer')->sign($url));
  185.     }
  186.     /**
  187.      * Try to login the current user
  188.      *
  189.      * @return boolean True if the user could be logged in
  190.      *
  191.      * @deprecated Deprecated since Contao 4.5, to be removed in Contao 5.0.
  192.      *             Use Symfony security instead.
  193.      */
  194.     public function login()
  195.     {
  196.         trigger_deprecation('contao/core-bundle''4.5''Using "Contao\BackendUser::login()" has been deprecated and will no longer work in Contao 5.0. Use Symfony security instead.');
  197.         return System::getContainer()->get('contao.security.token_checker')->hasBackendUser();
  198.     }
  199.     /**
  200.      * Check whether the current user has a certain access right
  201.      *
  202.      * @param array|string $field
  203.      * @param string       $array
  204.      *
  205.      * @return boolean
  206.      */
  207.     public function hasAccess($field$array)
  208.     {
  209.         if ($this->isAdmin)
  210.         {
  211.             return true;
  212.         }
  213.         if (!\is_array($field))
  214.         {
  215.             $field = array($field);
  216.         }
  217.         if (\is_array($this->$array) && array_intersect($field$this->$array))
  218.         {
  219.             return true;
  220.         }
  221.         if ($array == 'filemounts')
  222.         {
  223.             // Check the subfolders (filemounts)
  224.             foreach ($this->filemounts as $folder)
  225.             {
  226.                 if (preg_match('/^' preg_quote($folder'/') . '(\/|$)/i'$field[0]))
  227.                 {
  228.                     return true;
  229.                 }
  230.             }
  231.         }
  232.         return false;
  233.     }
  234.     /**
  235.      * Return true if the current user is allowed to do the current operation on the current page
  236.      *
  237.      * @param integer $int
  238.      * @param array   $row
  239.      *
  240.      * @return boolean
  241.      *
  242.      * @deprecated Deprecated since Contao 4.13, to be removed in Contao 5.0.
  243.      *             Use the "security.helper" service with the ContaoCorePermissions
  244.      *             constants instead.
  245.      */
  246.     public function isAllowed($int$row)
  247.     {
  248.         trigger_deprecation('contao/core-bundle''4.13''Using "Contao\BackendUser::isAllowed()" has been deprecated and will no longer work in Contao 5. Use the "security.helper" service with the ContaoCorePermissions constants instead.');
  249.         if ($this->isAdmin)
  250.         {
  251.             return true;
  252.         }
  253.         // Inherit CHMOD settings
  254.         if (!$row['includeChmod'])
  255.         {
  256.             $pid $row['pid'];
  257.             $row['chmod'] = false;
  258.             $row['cuser'] = false;
  259.             $row['cgroup'] = false;
  260.             $objParentPage PageModel::findById($pid);
  261.             while ($objParentPage !== null && $row['chmod'] === false && $pid 0)
  262.             {
  263.                 $pid $objParentPage->pid;
  264.                 $row['chmod'] = $objParentPage->includeChmod $objParentPage->chmod false;
  265.                 $row['cuser'] = $objParentPage->includeChmod $objParentPage->cuser false;
  266.                 $row['cgroup'] = $objParentPage->includeChmod $objParentPage->cgroup false;
  267.                 $objParentPage PageModel::findById($pid);
  268.             }
  269.             // Set default values
  270.             if ($row['chmod'] === false)
  271.             {
  272.                 $row['chmod'] = Config::get('defaultChmod');
  273.             }
  274.             if ($row['cuser'] === false)
  275.             {
  276.                 $row['cuser'] = (int) Config::get('defaultUser');
  277.             }
  278.             if ($row['cgroup'] === false)
  279.             {
  280.                 $row['cgroup'] = (int) Config::get('defaultGroup');
  281.             }
  282.         }
  283.         // Set permissions
  284.         $chmod StringUtil::deserialize($row['chmod']);
  285.         $chmod = \is_array($chmod) ? $chmod : array($chmod);
  286.         $permission = array('w' $int);
  287.         if (\in_array($row['cgroup'], $this->groups))
  288.         {
  289.             $permission[] = 'g' $int;
  290.         }
  291.         if ($row['cuser'] == $this->id)
  292.         {
  293.             $permission[] = 'u' $int;
  294.         }
  295.         return \count(array_intersect($permission$chmod)) > 0;
  296.     }
  297.     /**
  298.      * Return true if there is at least one allowed excluded field
  299.      *
  300.      * @param string $table
  301.      *
  302.      * @return boolean
  303.      *
  304.      * @deprecated Deprecated since Contao 4.13, to be removed in Contao 5.0.
  305.      *             Use the "security.helper" service with the ContaoCorePermissions::USER_CAN_EDIT_FIELDS_OF_TABLE
  306.      *             constant instead.
  307.      */
  308.     public function canEditFieldsOf($table)
  309.     {
  310.         trigger_deprecation('contao/core-bundle''4.13''Using "Contao\BackendUser::canEditFieldsOfTable()" has been deprecated and will no longer work in Contao 5. Use the "security.helper" service with the ContaoCorePermissions::USER_CAN_EDIT_FIELDS_OF_TABLE constant instead.');
  311.         if ($this->isAdmin)
  312.         {
  313.             return true;
  314.         }
  315.         return \count(preg_grep('/^' preg_quote($table'/') . '::/'$this->alexf)) > 0;
  316.     }
  317.     /**
  318.      * Restore the original numeric file mounts (see #5083)
  319.      */
  320.     public function save()
  321.     {
  322.         $filemounts $this->filemounts;
  323.         if (!empty($this->arrFilemountIds))
  324.         {
  325.             $this->arrData['filemounts'] = $this->arrFilemountIds;
  326.         }
  327.         parent::save();
  328.         $this->filemounts $filemounts;
  329.     }
  330.     /**
  331.      * Set all user properties from a database record
  332.      */
  333.     protected function setUserFromDb()
  334.     {
  335.         $this->intId $this->id;
  336.         // Unserialize values
  337.         foreach ($this->arrData as $k=>$v)
  338.         {
  339.             if (!is_numeric($v))
  340.             {
  341.                 $this->$k StringUtil::deserialize($v);
  342.             }
  343.         }
  344.         $GLOBALS['TL_USERNAME'] = $this->username;
  345.         Config::set('showHelp'$this->showHelp);
  346.         Config::set('useRTE'$this->useRTE);
  347.         Config::set('useCE'$this->useCE);
  348.         Config::set('thumbnails'$this->thumbnails);
  349.         Config::set('backendTheme'$this->backendTheme);
  350.         Config::set('fullscreen'$this->fullscreen);
  351.         // Inherit permissions
  352.         $always = array('alexf');
  353.         $depends = array('modules''themes''elements''fields''pagemounts''alpty''filemounts''fop''forms''formp''imageSizes''amg');
  354.         // HOOK: Take custom permissions
  355.         if (!empty($GLOBALS['TL_PERMISSIONS']) && \is_array($GLOBALS['TL_PERMISSIONS']))
  356.         {
  357.             $depends array_merge($depends$GLOBALS['TL_PERMISSIONS']);
  358.         }
  359.         // Overwrite user permissions if only group permissions shall be inherited
  360.         if ($this->inherit == 'group')
  361.         {
  362.             foreach ($depends as $field)
  363.             {
  364.                 $this->$field = array();
  365.             }
  366.         }
  367.         // Merge permissions
  368.         $inherit = \in_array($this->inherit, array('group''extend')) ? array_merge($always$depends) : $always;
  369.         $time Date::floorToMinute();
  370.         foreach ((array) $this->groups as $id)
  371.         {
  372.             $objGroup $this->Database->prepare("SELECT * FROM tl_user_group WHERE id=? AND disable!='1' AND (start='' OR start<='$time') AND (stop='' OR stop>'$time')")
  373.                                        ->limit(1)
  374.                                        ->execute($id);
  375.             if ($objGroup->numRows 0)
  376.             {
  377.                 foreach ($inherit as $field)
  378.                 {
  379.                     $value StringUtil::deserialize($objGroup->$fieldtrue);
  380.                     // The new page/file picker can return integers instead of arrays, so use empty() instead of is_array() and StringUtil::deserialize(true) here
  381.                     if (!empty($value))
  382.                     {
  383.                         $this->$field array_merge((\is_array($this->$field) ? $this->$field : ($this->$field ? array($this->$field) : array())), $value);
  384.                         $this->$field array_unique($this->$field);
  385.                     }
  386.                 }
  387.             }
  388.         }
  389.         // Make sure pagemounts and filemounts are set!
  390.         if (!\is_array($this->pagemounts))
  391.         {
  392.             $this->pagemounts = array();
  393.         }
  394.         else
  395.         {
  396.             $this->pagemounts array_filter($this->pagemounts);
  397.         }
  398.         if (!\is_array($this->filemounts))
  399.         {
  400.             $this->filemounts = array();
  401.         }
  402.         else
  403.         {
  404.             $this->filemounts array_filter($this->filemounts);
  405.         }
  406.         // Store the numeric file mounts
  407.         $this->arrFilemountIds $this->filemounts;
  408.         // Convert the file mounts into paths
  409.         if (!$this->isAdmin && !empty($this->filemounts))
  410.         {
  411.             $objFiles FilesModel::findMultipleByUuids($this->filemounts);
  412.             if ($objFiles !== null)
  413.             {
  414.                 $this->filemounts $objFiles->fetchEach('path');
  415.             }
  416.         }
  417.         // Hide the "admin" field if the user is not an admin (see #184)
  418.         if (!$this->isAdmin && ($index array_search('tl_user::admin'$this->alexf)) !== false)
  419.         {
  420.             unset($this->alexf[$index]);
  421.         }
  422.     }
  423.     /**
  424.      * Generate the navigation menu and return it as array
  425.      *
  426.      * @param boolean $blnShowAll
  427.      *
  428.      * @return array
  429.      */
  430.     public function navigation($blnShowAll=false)
  431.     {
  432.         $arrModules = array();
  433.         $arrStatus System::getContainer()->get('session')->getBag('contao_backend')->get('backend_modules');
  434.         $strRefererId System::getContainer()->get('request_stack')->getCurrentRequest()->attributes->get('_contao_referer_id');
  435.         $router System::getContainer()->get('router');
  436.         $security System::getContainer()->get('security.helper');
  437.         foreach ($GLOBALS['BE_MOD'] as $strGroupName=>$arrGroupModules)
  438.         {
  439.             if (!empty($arrGroupModules) && ($strGroupName == 'system' || $this->hasAccess(array_keys($arrGroupModules), 'modules')))
  440.             {
  441.                 $arrModules[$strGroupName]['class'] = 'group-' $strGroupName ' node-expanded';
  442.                 $arrModules[$strGroupName]['title'] = StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['collapseNode']);
  443.                 $arrModules[$strGroupName]['label'] = ($label = \is_array($GLOBALS['TL_LANG']['MOD'][$strGroupName] ?? null) ? ($GLOBALS['TL_LANG']['MOD'][$strGroupName][0] ?? null) : ($GLOBALS['TL_LANG']['MOD'][$strGroupName] ?? null)) ? $label $strGroupName;
  444.                 $arrModules[$strGroupName]['href'] = $router->generate('contao_backend', array('do'=>Input::get('do'), 'mtg'=>$strGroupName'ref'=>$strRefererId));
  445.                 $arrModules[$strGroupName]['ajaxUrl'] = $router->generate('contao_backend');
  446.                 $arrModules[$strGroupName]['icon'] = 'modPlus.gif'// backwards compatibility with e.g. EasyThemes
  447.                 foreach ($arrGroupModules as $strModuleName=>$arrModuleConfig)
  448.                 {
  449.                     // Check access
  450.                     $blnAccess = (isset($arrModuleConfig['disablePermissionChecks']) && $arrModuleConfig['disablePermissionChecks'] === true) || $security->isGranted(ContaoCorePermissions::USER_CAN_ACCESS_MODULE$strModuleName);
  451.                     $blnHide = isset($arrModuleConfig['hideInNavigation']) && $arrModuleConfig['hideInNavigation'] === true;
  452.                     if ($blnAccess && !$blnHide)
  453.                     {
  454.                         $arrModules[$strGroupName]['modules'][$strModuleName] = $arrModuleConfig;
  455.                         $arrModules[$strGroupName]['modules'][$strModuleName]['title'] = StringUtil::specialchars($GLOBALS['TL_LANG']['MOD'][$strModuleName][1] ?? '');
  456.                         $arrModules[$strGroupName]['modules'][$strModuleName]['label'] = ($label = \is_array($GLOBALS['TL_LANG']['MOD'][$strModuleName] ?? null) ? ($GLOBALS['TL_LANG']['MOD'][$strModuleName][0] ?? null) : ($GLOBALS['TL_LANG']['MOD'][$strModuleName] ?? null)) ? $label $strModuleName;
  457.                         $arrModules[$strGroupName]['modules'][$strModuleName]['class'] = 'navigation ' $strModuleName;
  458.                         $arrModules[$strGroupName]['modules'][$strModuleName]['href'] = $router->generate('contao_backend', array('do'=>$strModuleName'ref'=>$strRefererId));
  459.                         $arrModules[$strGroupName]['modules'][$strModuleName]['isActive'] = false;
  460.                     }
  461.                 }
  462.             }
  463.         }
  464.         // HOOK: add custom logic
  465.         if (isset($GLOBALS['TL_HOOKS']['getUserNavigation']) && \is_array($GLOBALS['TL_HOOKS']['getUserNavigation']))
  466.         {
  467.             foreach ($GLOBALS['TL_HOOKS']['getUserNavigation'] as $callback)
  468.             {
  469.                 $this->import($callback[0]);
  470.                 $arrModules $this->{$callback[0]}->{$callback[1]}($arrModulestrue);
  471.             }
  472.         }
  473.         foreach ($arrModules as $strGroupName => $arrGroupModules)
  474.         {
  475.             $arrModules[$strGroupName]['isClosed'] = false;
  476.             // Do not show the modules if the group is closed
  477.             if (!$blnShowAll && isset($arrStatus[$strGroupName]) && $arrStatus[$strGroupName] < 1)
  478.             {
  479.                 $arrModules[$strGroupName]['class'] = str_replace('node-expanded'''$arrModules[$strGroupName]['class']) . ' node-collapsed';
  480.                 $arrModules[$strGroupName]['title'] = StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['expandNode']);
  481.                 $arrModules[$strGroupName]['isClosed'] = true;
  482.             }
  483.             if (isset($arrGroupModules['modules']) && \is_array($arrGroupModules['modules']))
  484.             {
  485.                 foreach ($arrGroupModules['modules'] as $strModuleName => $arrModuleConfig)
  486.                 {
  487.                     // Mark the active module and its group
  488.                     if (Input::get('do') == $strModuleName)
  489.                     {
  490.                         $arrModules[$strGroupName]['class'] .= ' trail';
  491.                         $arrModules[$strGroupName]['modules'][$strModuleName]['isActive'] = true;
  492.                     }
  493.                 }
  494.             }
  495.         }
  496.         return $arrModules;
  497.     }
  498.     /**
  499.      * {@inheritdoc}
  500.      */
  501.     public function getRoles()
  502.     {
  503.         if ($this->isAdmin)
  504.         {
  505.             return array('ROLE_USER''ROLE_ADMIN''ROLE_ALLOWED_TO_SWITCH''ROLE_ALLOWED_TO_SWITCH_MEMBER');
  506.         }
  507.         if (!empty($this->amg) && \is_array($this->amg))
  508.         {
  509.             return array('ROLE_USER''ROLE_ALLOWED_TO_SWITCH_MEMBER');
  510.         }
  511.         return $this->roles;
  512.     }
  513.     /**
  514.      * @deprecated Deprecated since Contao 4.9, to be removed in Contao 5.0.
  515.      */
  516.     public function serialize()
  517.     {
  518.         $data $this->__serialize();
  519.         $data['parent'] = serialize($data['parent']);
  520.         return serialize($data);
  521.     }
  522.     public function __serialize(): array
  523.     {
  524.         return array('admin' => $this->admin'amg' => $this->amg'parent' => parent::__serialize());
  525.     }
  526.     /**
  527.      * @deprecated Deprecated since Contao 4.9 to be removed in Contao 5.0.
  528.      */
  529.     public function unserialize($data)
  530.     {
  531.         $unserialized unserialize($data, array('allowed_classes'=>false));
  532.         if (!isset($unserialized['parent']))
  533.         {
  534.             return;
  535.         }
  536.         $unserialized['parent'] = unserialize($unserialized['parent'], array('allowed_classes'=>false));
  537.         $this->__unserialize($unserialized);
  538.     }
  539.     public function __unserialize(array $data): void
  540.     {
  541.         if (array_keys($data) != array('admin''amg''parent'))
  542.         {
  543.             return;
  544.         }
  545.         list($this->admin$this->amg$parent) = array_values($data);
  546.         parent::__unserialize($parent);
  547.     }
  548.     /**
  549.      * {@inheritdoc}
  550.      */
  551.     public function isEqualTo(UserInterface $user)
  552.     {
  553.         if (!$user instanceof self)
  554.         {
  555.             return false;
  556.         }
  557.         if ((bool) $this->admin !== (bool) $user->admin)
  558.         {
  559.             return false;
  560.         }
  561.         return parent::isEqualTo($user);
  562.     }
  563. }
  564. class_alias(BackendUser::class, 'BackendUser');