vendor/contao/core-bundle/src/Resources/contao/models/PageModel.php line 724

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\NoRootPageFoundException;
  11. use Contao\Model\Collection;
  12. use Contao\Model\Registry;
  13. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  14. /**
  15.  * Reads and writes pages
  16.  *
  17.  * @property integer $id
  18.  * @property integer $pid
  19.  * @property integer $sorting
  20.  * @property integer $tstamp
  21.  * @property string  $title
  22.  * @property string  $alias
  23.  * @property string  $type
  24.  * @property string  $pageTitle
  25.  * @property string  $language
  26.  * @property string  $robots
  27.  * @property string  $description
  28.  * @property string  $redirect
  29.  * @property integer $jumpTo
  30.  * @property string  $redirectBack
  31.  * @property string  $url
  32.  * @property string  $target
  33.  * @property string  $dns
  34.  * @property string  $staticFiles
  35.  * @property string  $staticPlugins
  36.  * @property string  $fallback
  37.  * @property string  $favicon
  38.  * @property string  $robotsTxt
  39.  * @property string  $adminEmail
  40.  * @property string  $dateFormat
  41.  * @property string  $timeFormat
  42.  * @property string  $datimFormat
  43.  * @property string  $validAliasCharacters
  44.  * @property string  $createSitemap
  45.  * @property string  $sitemapName
  46.  * @property string  $useSSL
  47.  * @property string  $autoforward
  48.  * @property string  $protected
  49.  * @property string  $groups
  50.  * @property string  $includeLayout
  51.  * @property integer $layout
  52.  * @property string  $includeCache
  53.  * @property integer $cache
  54.  * @property string  $alwaysLoadFromCache
  55.  * @property integer $clientCache
  56.  * @property string  $includeChmod
  57.  * @property integer $cuser
  58.  * @property integer $cgroup
  59.  * @property string  $chmod
  60.  * @property string  $noSearch
  61.  * @property string  $requireItem
  62.  * @property string  $cssClass
  63.  * @property string  $sitemap
  64.  * @property string  $hide
  65.  * @property string  $guests
  66.  * @property integer $tabindex
  67.  * @property string  $accesskey
  68.  * @property string  $published
  69.  * @property string  $start
  70.  * @property string  $stop
  71.  * @property array   $trail
  72.  * @property string  $mainAlias
  73.  * @property string  $mainTitle
  74.  * @property string  $mainPageTitle
  75.  * @property string  $parentAlias
  76.  * @property string  $parentTitle
  77.  * @property string  $parentPageTitle
  78.  * @property string  $folderUrl
  79.  * @property boolean $isPublic
  80.  * @property integer $rootId
  81.  * @property string  $rootAlias
  82.  * @property string  $rootTitle
  83.  * @property string  $rootPageTitle
  84.  * @property integer $rootSorting
  85.  * @property string  $domain
  86.  * @property string  $rootLanguage
  87.  * @property boolean $rootIsPublic
  88.  * @property boolean $rootIsFallback
  89.  * @property boolean $rootUseSSL
  90.  * @property string  $rootFallbackLanguage
  91.  * @property array   $subpages
  92.  * @property boolean $minifyMarkup
  93.  * @property integer $layoutId
  94.  * @property boolean $hasJQuery
  95.  * @property boolean $hasMooTools
  96.  * @property string  $template
  97.  * @property string  $templateGroup
  98.  * @property string  $enforceTwoFactor
  99.  * @property integer $twoFactorJumpTo
  100.  *
  101.  * @method static PageModel|null findById($id, array $opt=array())
  102.  * @method static PageModel|null findByPk($id, array $opt=array())
  103.  * @method static PageModel|null findByIdOrAlias($val, array $opt=array())
  104.  * @method static PageModel|null findOneBy($col, $val, array $opt=array())
  105.  * @method static PageModel|null findOneByPid($val, array $opt=array())
  106.  * @method static PageModel|null findOneBySorting($val, array $opt=array())
  107.  * @method static PageModel|null findOneByTstamp($val, array $opt=array())
  108.  * @method static PageModel|null findOneByTitle($val, array $opt=array())
  109.  * @method static PageModel|null findOneByAlias($val, array $opt=array())
  110.  * @method static PageModel|null findOneByType($val, array $opt=array())
  111.  * @method static PageModel|null findOneByPageTitle($val, array $opt=array())
  112.  * @method static PageModel|null findOneByLanguage($val, array $opt=array())
  113.  * @method static PageModel|null findOneByRobots($val, array $opt=array())
  114.  * @method static PageModel|null findOneByDescription($val, array $opt=array())
  115.  * @method static PageModel|null findOneByRedirect($val, array $opt=array())
  116.  * @method static PageModel|null findOneByJumpTo($val, array $opt=array())
  117.  * @method static PageModel|null findOneByRedirectBack($val, array $opt=array())
  118.  * @method static PageModel|null findOneByUrl($val, array $opt=array())
  119.  * @method static PageModel|null findOneByTarget($val, array $opt=array())
  120.  * @method static PageModel|null findOneByDns($val, array $opt=array())
  121.  * @method static PageModel|null findOneByStaticFiles($val, array $opt=array())
  122.  * @method static PageModel|null findOneByStaticPlugins($val, array $opt=array())
  123.  * @method static PageModel|null findOneByFallback($val, array $opt=array())
  124.  * @method static PageModel|null findOneByFavicon($val, array $opt=array())
  125.  * @method static PageModel|null findOneByRobotsTxt($val, array $opt=array())
  126.  * @method static PageModel|null findOneByAdminEmail($val, array $opt=array())
  127.  * @method static PageModel|null findOneByDateFormat($val, array $opt=array())
  128.  * @method static PageModel|null findOneByTimeFormat($val, array $opt=array())
  129.  * @method static PageModel|null findOneByDatimFormat($val, array $opt=array())
  130.  * @method static PageModel|null findOneByCreateSitemap($val, array $opt=array())
  131.  * @method static PageModel|null findOneBySitemapName($val, array $opt=array())
  132.  * @method static PageModel|null findOneByUseSSL($val, array $opt=array())
  133.  * @method static PageModel|null findOneByAutoforward($val, array $opt=array())
  134.  * @method static PageModel|null findOneByProtected($val, array $opt=array())
  135.  * @method static PageModel|null findOneByGroups($val, array $opt=array())
  136.  * @method static PageModel|null findOneByIncludeLayout($val, array $opt=array())
  137.  * @method static PageModel|null findOneByLayout($val, array $opt=array())
  138.  * @method static PageModel|null findOneByIncludeCache($val, array $opt=array())
  139.  * @method static PageModel|null findOneByCache($val, array $opt=array())
  140.  * @method static PageModel|null findOneByIncludeChmod($val, array $opt=array())
  141.  * @method static PageModel|null findOneByCuser($val, array $opt=array())
  142.  * @method static PageModel|null findOneByCgroup($val, array $opt=array())
  143.  * @method static PageModel|null findOneByChmod($val, array $opt=array())
  144.  * @method static PageModel|null findOneByNoSearch($val, array $opt=array())
  145.  * @method static PageModel|null findOneByCssClass($val, array $opt=array())
  146.  * @method static PageModel|null findOneBySitemap($val, array $opt=array())
  147.  * @method static PageModel|null findOneByHide($val, array $opt=array())
  148.  * @method static PageModel|null findOneByGuests($val, array $opt=array())
  149.  * @method static PageModel|null findOneByTabindex($val, array $opt=array())
  150.  * @method static PageModel|null findOneByAccesskey($val, array $opt=array())
  151.  * @method static PageModel|null findOneByPublished($val, array $opt=array())
  152.  * @method static PageModel|null findOneByStart($val, array $opt=array())
  153.  * @method static PageModel|null findOneByStop($val, array $opt=array())
  154.  * @method static PageModel|null findOneByEnforceTwoFactor($val, array $opt=array())
  155.  * @method static PageModel|null findOneByTwoFactorJumpTo($val, array $opt=array())
  156.  *
  157.  * @method static Collection|PageModel[]|PageModel|null findByPid($val, array $opt=array())
  158.  * @method static Collection|PageModel[]|PageModel|null findBySorting($val, array $opt=array())
  159.  * @method static Collection|PageModel[]|PageModel|null findByTstamp($val, array $opt=array())
  160.  * @method static Collection|PageModel[]|PageModel|null findByTitle($val, array $opt=array())
  161.  * @method static Collection|PageModel[]|PageModel|null findByAlias($val, array $opt=array())
  162.  * @method static Collection|PageModel[]|PageModel|null findByType($val, array $opt=array())
  163.  * @method static Collection|PageModel[]|PageModel|null findByPageTitle($val, array $opt=array())
  164.  * @method static Collection|PageModel[]|PageModel|null findByLanguage($val, array $opt=array())
  165.  * @method static Collection|PageModel[]|PageModel|null findByRobots($val, array $opt=array())
  166.  * @method static Collection|PageModel[]|PageModel|null findByDescription($val, array $opt=array())
  167.  * @method static Collection|PageModel[]|PageModel|null findByRedirect($val, array $opt=array())
  168.  * @method static Collection|PageModel[]|PageModel|null findByJumpTo($val, array $opt=array())
  169.  * @method static Collection|PageModel[]|PageModel|null findByRedirectBack($val, array $opt=array())
  170.  * @method static Collection|PageModel[]|PageModel|null findByUrl($val, array $opt=array())
  171.  * @method static Collection|PageModel[]|PageModel|null findByTarget($val, array $opt=array())
  172.  * @method static Collection|PageModel[]|PageModel|null findByDns($val, array $opt=array())
  173.  * @method static Collection|PageModel[]|PageModel|null findByStaticFiles($val, array $opt=array())
  174.  * @method static Collection|PageModel[]|PageModel|null findByStaticPlugins($val, array $opt=array())
  175.  * @method static Collection|PageModel[]|PageModel|null findByFallback($val, array $opt=array())
  176.  * @method static Collection|PageModel[]|PageModel|null findByFavicon($val, array $opt=array())
  177.  * @method static Collection|PageModel[]|PageModel|null findByRobotsTxt($val, array $opt=array())
  178.  * @method static Collection|PageModel[]|PageModel|null findByAdminEmail($val, array $opt=array())
  179.  * @method static Collection|PageModel[]|PageModel|null findByDateFormat($val, array $opt=array())
  180.  * @method static Collection|PageModel[]|PageModel|null findByTimeFormat($val, array $opt=array())
  181.  * @method static Collection|PageModel[]|PageModel|null findByDatimFormat($val, array $opt=array())
  182.  * @method static Collection|PageModel[]|PageModel|null findByCreateSitemap($val, array $opt=array())
  183.  * @method static Collection|PageModel[]|PageModel|null findBySitemapName($val, array $opt=array())
  184.  * @method static Collection|PageModel[]|PageModel|null findByUseSSL($val, array $opt=array())
  185.  * @method static Collection|PageModel[]|PageModel|null findByAutoforward($val, array $opt=array())
  186.  * @method static Collection|PageModel[]|PageModel|null findByProtected($val, array $opt=array())
  187.  * @method static Collection|PageModel[]|PageModel|null findByGroups($val, array $opt=array())
  188.  * @method static Collection|PageModel[]|PageModel|null findByIncludeLayout($val, array $opt=array())
  189.  * @method static Collection|PageModel[]|PageModel|null findByLayout($val, array $opt=array())
  190.  * @method static Collection|PageModel[]|PageModel|null findByIncludeCache($val, array $opt=array())
  191.  * @method static Collection|PageModel[]|PageModel|null findByCache($val, array $opt=array())
  192.  * @method static Collection|PageModel[]|PageModel|null findByIncludeChmod($val, array $opt=array())
  193.  * @method static Collection|PageModel[]|PageModel|null findByCuser($val, array $opt=array())
  194.  * @method static Collection|PageModel[]|PageModel|null findByCgroup($val, array $opt=array())
  195.  * @method static Collection|PageModel[]|PageModel|null findByChmod($val, array $opt=array())
  196.  * @method static Collection|PageModel[]|PageModel|null findByNoSearch($val, array $opt=array())
  197.  * @method static Collection|PageModel[]|PageModel|null findByCssClass($val, array $opt=array())
  198.  * @method static Collection|PageModel[]|PageModel|null findBySitemap($val, array $opt=array())
  199.  * @method static Collection|PageModel[]|PageModel|null findByHide($val, array $opt=array())
  200.  * @method static Collection|PageModel[]|PageModel|null findByGuests($val, array $opt=array())
  201.  * @method static Collection|PageModel[]|PageModel|null findByTabindex($val, array $opt=array())
  202.  * @method static Collection|PageModel[]|PageModel|null findByAccesskey($val, array $opt=array())
  203.  * @method static Collection|PageModel[]|PageModel|null findByPublished($val, array $opt=array())
  204.  * @method static Collection|PageModel[]|PageModel|null findByStart($val, array $opt=array())
  205.  * @method static Collection|PageModel[]|PageModel|null findByStop($val, array $opt=array())
  206.  * @method static Collection|PageModel[]|PageModel|null findByEnforceTwoFactor($val, array $opt=array())
  207.  * @method static Collection|PageModel[]|PageModel|null findByTwoFactorJumpTo($val, array $opt=array())
  208.  * @method static Collection|PageModel[]|PageModel|null findMultipleByIds($val, array $opt=array())
  209.  * @method static Collection|PageModel[]|PageModel|null findBy($col, $val, array $opt=array())
  210.  * @method static Collection|PageModel[]|PageModel|null findAll(array $opt=array())
  211.  *
  212.  * @method static integer countById($id, array $opt=array())
  213.  * @method static integer countByPid($val, array $opt=array())
  214.  * @method static integer countBySorting($val, array $opt=array())
  215.  * @method static integer countByTstamp($val, array $opt=array())
  216.  * @method static integer countByTitle($val, array $opt=array())
  217.  * @method static integer countByAlias($val, array $opt=array())
  218.  * @method static integer countByType($val, array $opt=array())
  219.  * @method static integer countByPageTitle($val, array $opt=array())
  220.  * @method static integer countByLanguage($val, array $opt=array())
  221.  * @method static integer countByRobots($val, array $opt=array())
  222.  * @method static integer countByDescription($val, array $opt=array())
  223.  * @method static integer countByRedirect($val, array $opt=array())
  224.  * @method static integer countByJumpTo($val, array $opt=array())
  225.  * @method static integer countByRedirectBack($val, array $opt=array())
  226.  * @method static integer countByUrl($val, array $opt=array())
  227.  * @method static integer countByTarget($val, array $opt=array())
  228.  * @method static integer countByDns($val, array $opt=array())
  229.  * @method static integer countByStaticFiles($val, array $opt=array())
  230.  * @method static integer countByStaticPlugins($val, array $opt=array())
  231.  * @method static integer countByFallback($val, array $opt=array())
  232.  * @method static integer countByFavicon($val, array $opt=array())
  233.  * @method static integer countByRobotsTxt($val, array $opt=array())
  234.  * @method static integer countByAdminEmail($val, array $opt=array())
  235.  * @method static integer countByDateFormat($val, array $opt=array())
  236.  * @method static integer countByTimeFormat($val, array $opt=array())
  237.  * @method static integer countByDatimFormat($val, array $opt=array())
  238.  * @method static integer countByCreateSitemap($val, array $opt=array())
  239.  * @method static integer countBySitemapName($val, array $opt=array())
  240.  * @method static integer countByUseSSL($val, array $opt=array())
  241.  * @method static integer countByAutoforward($val, array $opt=array())
  242.  * @method static integer countByProtected($val, array $opt=array())
  243.  * @method static integer countByGroups($val, array $opt=array())
  244.  * @method static integer countByIncludeLayout($val, array $opt=array())
  245.  * @method static integer countByLayout($val, array $opt=array())
  246.  * @method static integer countByIncludeCache($val, array $opt=array())
  247.  * @method static integer countByCache($val, array $opt=array())
  248.  * @method static integer countByIncludeChmod($val, array $opt=array())
  249.  * @method static integer countByCuser($val, array $opt=array())
  250.  * @method static integer countByCgroup($val, array $opt=array())
  251.  * @method static integer countByChmod($val, array $opt=array())
  252.  * @method static integer countByNoSearch($val, array $opt=array())
  253.  * @method static integer countByCssClass($val, array $opt=array())
  254.  * @method static integer countBySitemap($val, array $opt=array())
  255.  * @method static integer countByHide($val, array $opt=array())
  256.  * @method static integer countByGuests($val, array $opt=array())
  257.  * @method static integer countByTabindex($val, array $opt=array())
  258.  * @method static integer countByAccesskey($val, array $opt=array())
  259.  * @method static integer countByPublished($val, array $opt=array())
  260.  * @method static integer countByStart($val, array $opt=array())
  261.  * @method static integer countByStop($val, array $opt=array())
  262.  * @method static integer countByEnforceTwoFactor($val, array $opt=array())
  263.  * @method static integer countByTwoFactorJumpTo($val, array $opt=array())
  264.  *
  265.  * @author Leo Feyer <https://github.com/leofeyer>
  266.  */
  267. class PageModel extends Model
  268. {
  269.     /**
  270.      * Table name
  271.      * @var string
  272.      */
  273.     protected static $strTable 'tl_page';
  274.     /**
  275.      * Details loaded
  276.      * @var boolean
  277.      */
  278.     protected $blnDetailsLoaded false;
  279.     /**
  280.      * Find a published page by its ID
  281.      *
  282.      * @param integer $intId      The page ID
  283.      * @param array   $arrOptions An optional options array
  284.      *
  285.      * @return PageModel|null The model or null if there is no published page
  286.      */
  287.     public static function findPublishedById($intId, array $arrOptions=array())
  288.     {
  289.         $t = static::$strTable;
  290.         $arrColumns = array("$t.id=?");
  291.         if (!static::isPreviewMode($arrOptions))
  292.         {
  293.             $time Date::floorToMinute();
  294.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  295.         }
  296.         return static::findOneBy($arrColumns$intId$arrOptions);
  297.     }
  298.     /**
  299.      * Find published pages by their PID
  300.      *
  301.      * @param integer $intPid     The parent ID
  302.      * @param array   $arrOptions An optional options array
  303.      *
  304.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  305.      */
  306.     public static function findPublishedByPid($intPid, array $arrOptions=array())
  307.     {
  308.         $t = static::$strTable;
  309.         $arrColumns = array("$t.pid=?");
  310.         if (!static::isPreviewMode($arrOptions))
  311.         {
  312.             $time Date::floorToMinute();
  313.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  314.         }
  315.         return static::findBy($arrColumns$intPid$arrOptions);
  316.     }
  317.     /**
  318.      * Find the first published root page by its host name and language
  319.      *
  320.      * @param string $strHost     The host name
  321.      * @param mixed  $varLanguage An ISO language code or an array of ISO language codes
  322.      * @param array  $arrOptions  An optional options array
  323.      *
  324.      * @return PageModel|null The model or null if there is no matching root page
  325.      *
  326.      * @deprecated Deprecated since Contao 4.7, to be removed in Contao 5.0.
  327.      */
  328.     public static function findFirstPublishedRootByHostAndLanguage($strHost$varLanguage, array $arrOptions=array())
  329.     {
  330.         @trigger_error('Using PageModel::findFirstPublishedRootByHostAndLanguage() has been deprecated and will no longer work Contao 5.0.'E_USER_DEPRECATED);
  331.         $t = static::$strTable;
  332.         $objDatabase Database::getInstance();
  333.         if (\is_array($varLanguage))
  334.         {
  335.             $arrColumns = array("$t.type='root' AND ($t.dns=? OR $t.dns='')");
  336.             if (!empty($varLanguage))
  337.             {
  338.                 $arrColumns[] = "($t.language IN('" implode("','"$varLanguage) . "') OR $t.fallback='1')";
  339.             }
  340.             else
  341.             {
  342.                 $arrColumns[] = "$t.fallback='1'";
  343.             }
  344.             if (!isset($arrOptions['order']))
  345.             {
  346.                 $arrOptions['order'] = "$t.dns DESC" . (!empty($varLanguage) ? ", " $objDatabase->findInSet("$t.language"array_reverse($varLanguage)) . " DESC" "") . ", $t.sorting";
  347.             }
  348.             if (!static::isPreviewMode($arrOptions))
  349.             {
  350.                 $time Date::floorToMinute();
  351.                 $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  352.             }
  353.             return static::findOneBy($arrColumns$strHost$arrOptions);
  354.         }
  355.         $arrColumns = array("$t.type='root' AND ($t.dns=? OR $t.dns='') AND ($t.language=? OR $t.fallback='1')");
  356.         $arrValues = array($strHost$varLanguage);
  357.         if (!isset($arrOptions['order']))
  358.         {
  359.             $arrOptions['order'] = "$t.dns DESC, $t.fallback";
  360.         }
  361.         if (!static::isPreviewMode($arrOptions))
  362.         {
  363.             $time Date::floorToMinute();
  364.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  365.         }
  366.         return static::findOneBy($arrColumns$arrValues$arrOptions);
  367.     }
  368.     /**
  369.      * Find the first published page by its parent ID
  370.      *
  371.      * @param integer $intPid     The parent page's ID
  372.      * @param array   $arrOptions An optional options array
  373.      *
  374.      * @return PageModel|null The model or null if there is no published page
  375.      */
  376.     public static function findFirstPublishedByPid($intPid, array $arrOptions=array())
  377.     {
  378.         $t = static::$strTable;
  379.         $arrColumns = array("$t.pid=? AND $t.type!='root' AND $t.type!='error_401' AND $t.type!='error_403' AND $t.type!='error_404'");
  380.         if (!static::isPreviewMode($arrOptions))
  381.         {
  382.             $time Date::floorToMinute();
  383.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  384.         }
  385.         if (!isset($arrOptions['order']))
  386.         {
  387.             $arrOptions['order'] = "$t.sorting";
  388.         }
  389.         return static::findOneBy($arrColumns$intPid$arrOptions);
  390.     }
  391.     /**
  392.      * Find the first published regular page by its parent ID
  393.      *
  394.      * @param integer $intPid     The parent page's ID
  395.      * @param array   $arrOptions An optional options array
  396.      *
  397.      * @return PageModel|null The model or null if there is no published regular page
  398.      */
  399.     public static function findFirstPublishedRegularByPid($intPid, array $arrOptions=array())
  400.     {
  401.         $t = static::$strTable;
  402.         $arrColumns = array("$t.pid=? AND $t.type='regular'");
  403.         if (!static::isPreviewMode($arrOptions))
  404.         {
  405.             $time Date::floorToMinute();
  406.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  407.         }
  408.         if (!isset($arrOptions['order']))
  409.         {
  410.             $arrOptions['order'] = "$t.sorting";
  411.         }
  412.         return static::findOneBy($arrColumns$intPid$arrOptions);
  413.     }
  414.     /**
  415.      * Find an error 401 page by its parent ID
  416.      *
  417.      * @param integer $intPid     The parent page's ID
  418.      * @param array   $arrOptions An optional options array
  419.      *
  420.      * @return PageModel|null The model or null if there is no 401 page
  421.      */
  422.     public static function find401ByPid($intPid, array $arrOptions=array())
  423.     {
  424.         $t = static::$strTable;
  425.         $arrColumns = array("$t.pid=? AND $t.type='error_401'");
  426.         if (!static::isPreviewMode($arrOptions))
  427.         {
  428.             $time Date::floorToMinute();
  429.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  430.         }
  431.         if (!isset($arrOptions['order']))
  432.         {
  433.             $arrOptions['order'] = "$t.sorting";
  434.         }
  435.         return static::findOneBy($arrColumns$intPid$arrOptions);
  436.     }
  437.     /**
  438.      * Find an error 403 page by its parent ID
  439.      *
  440.      * @param integer $intPid     The parent page's ID
  441.      * @param array   $arrOptions An optional options array
  442.      *
  443.      * @return PageModel|null The model or null if there is no 403 page
  444.      */
  445.     public static function find403ByPid($intPid, array $arrOptions=array())
  446.     {
  447.         $t = static::$strTable;
  448.         $arrColumns = array("$t.pid=? AND $t.type='error_403'");
  449.         if (!static::isPreviewMode($arrOptions))
  450.         {
  451.             $time Date::floorToMinute();
  452.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  453.         }
  454.         if (!isset($arrOptions['order']))
  455.         {
  456.             $arrOptions['order'] = "$t.sorting";
  457.         }
  458.         return static::findOneBy($arrColumns$intPid$arrOptions);
  459.     }
  460.     /**
  461.      * Find an error 404 page by its parent ID
  462.      *
  463.      * @param integer $intPid     The parent page's ID
  464.      * @param array   $arrOptions An optional options array
  465.      *
  466.      * @return PageModel|null The model or null if there is no 404 page
  467.      */
  468.     public static function find404ByPid($intPid, array $arrOptions=array())
  469.     {
  470.         $t = static::$strTable;
  471.         $arrColumns = array("$t.pid=? AND $t.type='error_404'");
  472.         if (!static::isPreviewMode($arrOptions))
  473.         {
  474.             $time Date::floorToMinute();
  475.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  476.         }
  477.         if (!isset($arrOptions['order']))
  478.         {
  479.             $arrOptions['order'] = "$t.sorting";
  480.         }
  481.         return static::findOneBy($arrColumns$intPid$arrOptions);
  482.     }
  483.     /**
  484.      * Find pages matching a list of possible alias names
  485.      *
  486.      * @param array $arrAliases An array of possible alias names
  487.      * @param array $arrOptions An optional options array
  488.      *
  489.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  490.      */
  491.     public static function findByAliases($arrAliases, array $arrOptions=array())
  492.     {
  493.         if (empty($arrAliases) || !\is_array($arrAliases))
  494.         {
  495.             return null;
  496.         }
  497.         // Remove everything that is not an alias
  498.         $arrAliases array_filter(array_map(static function ($v) { return preg_match('/^[\w\/.-]+$/u'$v) ? $v null; }, $arrAliases));
  499.         // Return if nothing is left
  500.         if (empty($arrAliases))
  501.         {
  502.             return null;
  503.         }
  504.         $t = static::$strTable;
  505.         $arrColumns = array("$t.alias IN('" implode("','"array_filter($arrAliases)) . "')");
  506.         // Check the publication status (see #4652)
  507.         if (!static::isPreviewMode($arrOptions))
  508.         {
  509.             $time Date::floorToMinute();
  510.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  511.         }
  512.         if (!isset($arrOptions['order']))
  513.         {
  514.             $arrOptions['order'] = Database::getInstance()->findInSet("$t.alias"$arrAliases);
  515.         }
  516.         return static::findBy($arrColumnsnull$arrOptions);
  517.     }
  518.     /**
  519.      * Find published pages by their ID or aliases
  520.      *
  521.      * @param mixed $varId      The numeric ID or the alias name
  522.      * @param array $arrOptions An optional options array
  523.      *
  524.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  525.      */
  526.     public static function findPublishedByIdOrAlias($varId, array $arrOptions=array())
  527.     {
  528.         $t = static::$strTable;
  529.         $arrColumns = !preg_match('/^[1-9]\d*$/'$varId) ? array("BINARY $t.alias=?") : array("$t.id=?");
  530.         if (!static::isPreviewMode($arrOptions))
  531.         {
  532.             $time Date::floorToMinute();
  533.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  534.         }
  535.         return static::findBy($arrColumns$varId$arrOptions);
  536.     }
  537.     /**
  538.      * Find all published subpages by their parent ID and exclude pages only visible for guests
  539.      *
  540.      * @param integer $intPid        The parent page's ID
  541.      * @param boolean $blnShowHidden If true, hidden pages will be included
  542.      * @param boolean $blnIsSitemap  If true, the sitemap settings apply
  543.      *
  544.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  545.      */
  546.     public static function findPublishedSubpagesWithoutGuestsByPid($intPid$blnShowHidden=false$blnIsSitemap=false)
  547.     {
  548.         $time Date::floorToMinute();
  549.         $blnFeUserLoggedIn System::getContainer()->get('contao.security.token_checker')->hasFrontendUser();
  550.         $objSubpages Database::getInstance()->prepare("SELECT p1.*, (SELECT COUNT(*) FROM tl_page p2 WHERE p2.pid=p1.id AND p2.type!='root' AND p2.type!='error_401' AND p2.type!='error_403' AND p2.type!='error_404'" . (!$blnShowHidden ? ($blnIsSitemap " AND (p2.hide='' OR sitemap='map_always')" " AND p2.hide=''") : "") . ($blnFeUserLoggedIn " AND p2.guests=''" "") . (!BE_USER_LOGGED_IN " AND p2.published='1' AND (p2.start='' OR p2.start<='$time') AND (p2.stop='' OR p2.stop>'$time')" "") . ") AS subpages FROM tl_page p1 WHERE p1.pid=? AND p1.type!='root' AND p1.type!='error_401' AND p1.type!='error_403' AND p1.type!='error_404'" . (!$blnShowHidden ? ($blnIsSitemap " AND (p1.hide='' OR sitemap='map_always')" " AND p1.hide=''") : "") . ($blnFeUserLoggedIn " AND p1.guests=''" "") . (!BE_USER_LOGGED_IN " AND p1.published='1' AND (p1.start='' OR p1.start<='$time') AND (p1.stop='' OR p1.stop>'$time')" "") . " ORDER BY p1.sorting")
  551.                                               ->execute($intPid);
  552.         if ($objSubpages->numRows 1)
  553.         {
  554.             return null;
  555.         }
  556.         return static::createCollectionFromDbResult($objSubpages'tl_page');
  557.     }
  558.     /**
  559.      * Find all published regular pages by their IDs and exclude pages only visible for guests
  560.      *
  561.      * @param array $arrIds     An array of page IDs
  562.      * @param array $arrOptions An optional options array
  563.      *
  564.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  565.      */
  566.     public static function findPublishedRegularWithoutGuestsByIds($arrIds, array $arrOptions=array())
  567.     {
  568.         if (empty($arrIds) || !\is_array($arrIds))
  569.         {
  570.             return null;
  571.         }
  572.         $t = static::$strTable;
  573.         $arrColumns = array("$t.id IN(" implode(','array_map('\intval'$arrIds)) . ") AND $t.type!='error_401' AND $t.type!='error_403' AND $t.type!='error_404'");
  574.         if (empty($arrOptions['includeRoot']))
  575.         {
  576.             $arrColumns[] = "$t.type!='root'";
  577.         }
  578.         if (System::getContainer()->get('contao.security.token_checker')->hasFrontendUser())
  579.         {
  580.             $arrColumns[] = "$t.guests=''";
  581.         }
  582.         if (!static::isPreviewMode($arrOptions))
  583.         {
  584.             $time Date::floorToMinute();
  585.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  586.         }
  587.         if (!isset($arrOptions['order']))
  588.         {
  589.             $arrOptions['order'] = Database::getInstance()->findInSet("$t.id"$arrIds);
  590.         }
  591.         return static::findBy($arrColumnsnull$arrOptions);
  592.     }
  593.     /**
  594.      * Find all published regular pages by their parent IDs and exclude pages only visible for guests
  595.      *
  596.      * @param integer $intPid     The parent page's ID
  597.      * @param array   $arrOptions An optional options array
  598.      *
  599.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no pages
  600.      */
  601.     public static function findPublishedRegularWithoutGuestsByPid($intPid, array $arrOptions=array())
  602.     {
  603.         $t = static::$strTable;
  604.         $arrColumns = array("$t.pid=? AND $t.type!='root' AND $t.type!='error_401' AND $t.type!='error_403' AND $t.type!='error_404'");
  605.         if (System::getContainer()->get('contao.security.token_checker')->hasFrontendUser())
  606.         {
  607.             $arrColumns[] = "$t.guests=''";
  608.         }
  609.         if (!static::isPreviewMode($arrOptions))
  610.         {
  611.             $time Date::floorToMinute();
  612.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  613.         }
  614.         if (!isset($arrOptions['order']))
  615.         {
  616.             $arrOptions['order'] = "$t.sorting";
  617.         }
  618.         return static::findBy($arrColumns$intPid$arrOptions);
  619.     }
  620.     /**
  621.      * Find the language fallback page by hostname
  622.      *
  623.      * @param string $strHost    The hostname
  624.      * @param array  $arrOptions An optional options array
  625.      *
  626.      * @return PageModel|Model|null The model or null if there is not fallback page
  627.      */
  628.     public static function findPublishedFallbackByHostname($strHost, array $arrOptions=array())
  629.     {
  630.         // Try to load from the registry (see #8544)
  631.         if (empty($arrOptions))
  632.         {
  633.             $objModel Registry::getInstance()->fetch(static::$strTable$strHost'contao.dns-fallback');
  634.             if ($objModel !== null)
  635.             {
  636.                 return $objModel;
  637.             }
  638.         }
  639.         $t = static::$strTable;
  640.         $arrColumns = array("$t.dns=? AND $t.fallback='1'");
  641.         if (isset($arrOptions['fallbackToEmpty']) && $arrOptions['fallbackToEmpty'] === true)
  642.         {
  643.             $arrColumns = array("($t.dns=? OR $t.dns='') AND $t.fallback='1'");
  644.         }
  645.         if (!static::isPreviewMode($arrOptions))
  646.         {
  647.             $time Date::floorToMinute();
  648.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  649.         }
  650.         return static::findOneBy($arrColumns$strHost$arrOptions);
  651.     }
  652.     /**
  653.      * Finds the published root pages
  654.      *
  655.      * @param array $arrOptions An optional options array
  656.      *
  657.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no parent pages
  658.      */
  659.     public static function findPublishedRootPages(array $arrOptions=array())
  660.     {
  661.         $t = static::$strTable;
  662.         $arrColumns = array("$t.type='root'");
  663.         if (isset($arrOptions['dns']))
  664.         {
  665.             $arrColumns = array("$t.type='root' AND $t.dns=?");
  666.         }
  667.         if (!static::isPreviewMode($arrOptions))
  668.         {
  669.             $time Date::floorToMinute();
  670.             $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')";
  671.         }
  672.         return static::findBy($arrColumns$arrOptions['dns'] ?? null$arrOptions);
  673.     }
  674.     /**
  675.      * Find the parent pages of a page
  676.      *
  677.      * @param integer $intId The page's ID
  678.      *
  679.      * @return Collection|PageModel[]|PageModel|null A collection of models or null if there are no parent pages
  680.      */
  681.     public static function findParentsById($intId)
  682.     {
  683.         $arrModels = array();
  684.         while ($intId && ($objPage = static::findByPk($intId)) !== null)
  685.         {
  686.             $intId $objPage->pid;
  687.             $arrModels[] = $objPage;
  688.         }
  689.         if (empty($arrModels))
  690.         {
  691.             return null;
  692.         }
  693.         return static::createCollection($arrModels'tl_page');
  694.     }
  695.     /**
  696.      * Find the first active page by its member groups
  697.      *
  698.      * @param array $arrIds An array of member group IDs
  699.      *
  700.      * @return PageModel|null The model or null if there is no matching member group
  701.      */
  702.     public static function findFirstActiveByMemberGroups($arrIds)
  703.     {
  704.         if (empty($arrIds) || !\is_array($arrIds))
  705.         {
  706.             return null;
  707.         }
  708.         $time Date::floorToMinute();
  709.         $objDatabase Database::getInstance();
  710.         $arrIds array_map('\intval'$arrIds);
  711.         $objResult $objDatabase->prepare("SELECT p.* FROM tl_member_group g LEFT JOIN tl_page p ON g.jumpTo=p.id WHERE g.id IN(" implode(','$arrIds) . ") AND g.jumpTo>0 AND g.redirect='1' AND g.disable!='1' AND (g.start='' OR g.start<='$time') AND (g.stop='' OR g.stop>'$time') AND p.published='1' AND (p.start='' OR p.start<='$time') AND (p.stop='' OR p.stop>'$time') ORDER BY " $objDatabase->findInSet('g.id'$arrIds))
  712.                                  ->limit(1)
  713.                                  ->execute();
  714.         if ($objResult->numRows 1)
  715.         {
  716.             return null;
  717.         }
  718.         $objRegistry Registry::getInstance();
  719.         /** @var PageModel|Model $objPage */
  720.         if ($objPage $objRegistry->fetch('tl_page'$objResult->id))
  721.         {
  722.             return $objPage;
  723.         }
  724.         return new static($objResult);
  725.     }
  726.     /**
  727.      * Find a page by its ID and return it with the inherited details
  728.      *
  729.      * @param integer $intId The page's ID
  730.      *
  731.      * @return PageModel|null The model or null if there is no matching page
  732.      */
  733.     public static function findWithDetails($intId)
  734.     {
  735.         $objPage = static::findByPk($intId);
  736.         if ($objPage === null)
  737.         {
  738.             return null;
  739.         }
  740.         return $objPage->loadDetails();
  741.     }
  742.     /**
  743.      * Register the contao.dns-fallback alias when the model is attached to the registry
  744.      *
  745.      * @param Registry $registry The model registry
  746.      */
  747.     public function onRegister(Registry $registry)
  748.     {
  749.         parent::onRegister($registry);
  750.         // Register this model as being the fallback page for a given dns
  751.         if ($this->fallback && $this->type == 'root' && !$registry->isRegisteredAlias($this'contao.dns-fallback'$this->dns))
  752.         {
  753.             $registry->registerAlias($this'contao.dns-fallback'$this->dns);
  754.         }
  755.     }
  756.     /**
  757.      * Unregister the contao.dns-fallback alias when the model is detached from the registry
  758.      *
  759.      * @param Registry $registry The model registry
  760.      */
  761.     public function onUnregister(Registry $registry)
  762.     {
  763.         parent::onUnregister($registry);
  764.         // Unregister the fallback page
  765.         if ($this->fallback && $this->type == 'root' && $registry->isRegisteredAlias($this'contao.dns-fallback'$this->dns))
  766.         {
  767.             $registry->unregisterAlias($this'contao.dns-fallback'$this->dns);
  768.         }
  769.     }
  770.     /**
  771.      * Get the details of a page including inherited parameters
  772.      *
  773.      * @return PageModel The page model
  774.      *
  775.      * @throws NoRootPageFoundException If no root page is found
  776.      */
  777.     public function loadDetails()
  778.     {
  779.         // Loaded already
  780.         if ($this->blnDetailsLoaded)
  781.         {
  782.             return $this;
  783.         }
  784.         // Set some default values
  785.         $this->protected = (bool) $this->protected;
  786.         $this->groups $this->protected StringUtil::deserialize($this->groups) : false;
  787.         $this->layout $this->includeLayout $this->layout false;
  788.         $this->cache $this->includeCache $this->cache false;
  789.         $this->alwaysLoadFromCache $this->includeCache $this->alwaysLoadFromCache false;
  790.         $this->clientCache $this->includeCache $this->clientCache false;
  791.         $pid $this->pid;
  792.         $type $this->type;
  793.         $alias $this->alias;
  794.         $name $this->title;
  795.         $title $this->pageTitle ?: $this->title;
  796.         $folderUrl '';
  797.         $palias '';
  798.         $pname '';
  799.         $ptitle '';
  800.         $trail = array($this->id$pid);
  801.         $time time();
  802.         // Inherit the settings
  803.         if ($this->type == 'root')
  804.         {
  805.             $objParentPage $this// see #4610
  806.         }
  807.         else
  808.         {
  809.             // Load all parent pages
  810.             $objParentPage self::findParentsById($pid);
  811.             if ($objParentPage !== null)
  812.             {
  813.                 while ($pid && $type != 'root' && $objParentPage->next())
  814.                 {
  815.                     $pid $objParentPage->pid;
  816.                     $type $objParentPage->type;
  817.                     // Parent title
  818.                     if (!$ptitle)
  819.                     {
  820.                         $palias $objParentPage->alias;
  821.                         $pname $objParentPage->title;
  822.                         $ptitle $objParentPage->pageTitle ?: $objParentPage->title;
  823.                     }
  824.                     // Page title
  825.                     if ($type != 'root')
  826.                     {
  827.                         // If $folderUrl is not yet set, use the alias of the first
  828.                         // parent page if it is not a root page (see #2129)
  829.                         if (!$folderUrl && $objParentPage->alias)
  830.                         {
  831.                             $folderUrl $objParentPage->alias '/';
  832.                         }
  833.                         $alias $objParentPage->alias;
  834.                         $name $objParentPage->title;
  835.                         $title $objParentPage->pageTitle ?: $objParentPage->title;
  836.                         $trail[] = $objParentPage->pid;
  837.                     }
  838.                     // Cache
  839.                     if ($objParentPage->includeCache)
  840.                     {
  841.                         $this->cache $this->cache !== false $this->cache $objParentPage->cache;
  842.                         $this->alwaysLoadFromCache $this->alwaysLoadFromCache !== false $this->alwaysLoadFromCache $objParentPage->alwaysLoadFromCache;
  843.                         $this->clientCache $this->clientCache !== false $this->clientCache $objParentPage->clientCache;
  844.                     }
  845.                     // Layout
  846.                     if ($objParentPage->includeLayout && $this->layout === false)
  847.                     {
  848.                         $this->layout $objParentPage->layout;
  849.                     }
  850.                     // Protection
  851.                     if ($objParentPage->protected && $this->protected === false)
  852.                     {
  853.                         $this->protected true;
  854.                         $this->groups StringUtil::deserialize($objParentPage->groups);
  855.                     }
  856.                 }
  857.             }
  858.             // Set the titles
  859.             $this->mainAlias $alias;
  860.             $this->mainTitle $name;
  861.             $this->mainPageTitle $title;
  862.             $this->parentAlias $palias;
  863.             $this->parentTitle $pname;
  864.             $this->parentPageTitle $ptitle;
  865.             $this->folderUrl $folderUrl;
  866.         }
  867.         // Set the root ID and title
  868.         if ($objParentPage !== null && $objParentPage->type == 'root')
  869.         {
  870.             $this->rootId $objParentPage->id;
  871.             $this->rootAlias $objParentPage->alias;
  872.             $this->rootTitle $objParentPage->title;
  873.             $this->rootPageTitle $objParentPage->pageTitle ?: $objParentPage->title;
  874.             $this->rootSorting $objParentPage->sorting;
  875.             $this->domain $objParentPage->dns;
  876.             $this->rootLanguage $objParentPage->language;
  877.             $this->language $objParentPage->language;
  878.             $this->staticFiles $objParentPage->staticFiles;
  879.             $this->staticPlugins $objParentPage->staticPlugins;
  880.             $this->dateFormat $objParentPage->dateFormat;
  881.             $this->timeFormat $objParentPage->timeFormat;
  882.             $this->datimFormat $objParentPage->datimFormat;
  883.             $this->validAliasCharacters $objParentPage->validAliasCharacters;
  884.             $this->adminEmail $objParentPage->adminEmail;
  885.             $this->enforceTwoFactor $objParentPage->enforceTwoFactor;
  886.             $this->twoFactorJumpTo $objParentPage->twoFactorJumpTo;
  887.             // Store whether the root page has been published
  888.             $this->rootIsPublic = ($objParentPage->published && (!$objParentPage->start || $objParentPage->start <= $time) && (!$objParentPage->stop || $objParentPage->stop $time));
  889.             $this->rootIsFallback true;
  890.             $this->rootUseSSL $objParentPage->useSSL;
  891.             $this->rootFallbackLanguage $objParentPage->language;
  892.             // Store the fallback language (see #6874)
  893.             if (!$objParentPage->fallback)
  894.             {
  895.                 $this->rootIsFallback false;
  896.                 $this->rootFallbackLanguage null;
  897.                 $objFallback = static::findPublishedFallbackByHostname($objParentPage->dns);
  898.                 if ($objFallback !== null)
  899.                 {
  900.                     $this->rootFallbackLanguage $objFallback->language;
  901.                 }
  902.             }
  903.         }
  904.         // No root page found
  905.         elseif (TL_MODE == 'FE' && $this->type != 'root')
  906.         {
  907.             System::log('Page ID "' $this->id '" does not belong to a root page'__METHOD__TL_ERROR);
  908.             throw new NoRootPageFoundException('No root page found');
  909.         }
  910.         $this->trail array_reverse($trail);
  911.         // Use the global date format if none is set (see #6104)
  912.         if (!$this->dateFormat)
  913.         {
  914.             $this->dateFormat Config::get('dateFormat');
  915.         }
  916.         if (!$this->timeFormat)
  917.         {
  918.             $this->timeFormat Config::get('timeFormat');
  919.         }
  920.         if (!$this->datimFormat)
  921.         {
  922.             $this->datimFormat Config::get('datimFormat');
  923.         }
  924.         $this->isPublic = ($this->published && (!$this->start || $this->start <= $time) && (!$this->stop || $this->stop $time));
  925.         // HOOK: add custom logic
  926.         if (!empty($GLOBALS['TL_HOOKS']['loadPageDetails']) && \is_array($GLOBALS['TL_HOOKS']['loadPageDetails']))
  927.         {
  928.             $parentModels = array();
  929.             if ($objParentPage instanceof Collection)
  930.             {
  931.                 $parentModels $objParentPage->getModels();
  932.             }
  933.             foreach ($GLOBALS['TL_HOOKS']['loadPageDetails'] as $callback)
  934.             {
  935.                 System::importStatic($callback[0])->{$callback[1]}($parentModels$this);
  936.             }
  937.         }
  938.         // Prevent saving (see #6506 and #7199)
  939.         $this->preventSaving();
  940.         $this->blnDetailsLoaded true;
  941.         return $this;
  942.     }
  943.     /**
  944.      * Generate a front end URL
  945.      *
  946.      * @param string $strParams    An optional string of URL parameters
  947.      * @param string $strForceLang Force a certain language
  948.      *
  949.      * @return string An URL that can be used in the front end
  950.      */
  951.     public function getFrontendUrl($strParams=null$strForceLang=null)
  952.     {
  953.         if ($strForceLang !== null)
  954.         {
  955.             @trigger_error('Using PageModel::getFrontendUrl() with $strForceLang has been deprecated and will no longer work in Contao 5.0.'E_USER_DEPRECATED);
  956.         }
  957.         $this->loadDetails();
  958.         $objUrlGenerator System::getContainer()->get('contao.routing.url_generator');
  959.         $strUrl $objUrlGenerator->generate
  960.         (
  961.             ($this->alias ?: $this->id) . $strParams,
  962.             array
  963.             (
  964.                 '_locale' => ($strForceLang ?: $this->rootLanguage),
  965.                 '_domain' => $this->domain,
  966.                 '_ssl' => (bool) $this->rootUseSSL,
  967.             )
  968.         );
  969.         // Make the URL relative to the base path
  970.         if (=== strncmp($strUrl'/'1))
  971.         {
  972.             $strUrl substr($strUrl, \strlen(Environment::get('path')) + 1);
  973.         }
  974.         return $this->applyLegacyLogic($strUrl$strParams);
  975.     }
  976.     /**
  977.      * Generate an absolute URL depending on the current rewriteURL setting
  978.      *
  979.      * @param string $strParams An optional string of URL parameters
  980.      *
  981.      * @return string An absolute URL that can be used in the front end
  982.      */
  983.     public function getAbsoluteUrl($strParams=null)
  984.     {
  985.         $this->loadDetails();
  986.         $objUrlGenerator System::getContainer()->get('contao.routing.url_generator');
  987.         $strUrl $objUrlGenerator->generate
  988.         (
  989.             ($this->alias ?: $this->id) . $strParams,
  990.             array
  991.             (
  992.                 '_locale' => $this->rootLanguage,
  993.                 '_domain' => $this->domain,
  994.                 '_ssl' => (bool) $this->rootUseSSL,
  995.             ),
  996.             UrlGeneratorInterface::ABSOLUTE_URL
  997.         );
  998.         return $this->applyLegacyLogic($strUrl$strParams);
  999.     }
  1000.     /**
  1001.      * Generate the front end preview URL
  1002.      *
  1003.      * @param string $strParams An optional string of URL parameters
  1004.      *
  1005.      * @return string The front end preview URL
  1006.      */
  1007.     public function getPreviewUrl($strParams=null)
  1008.     {
  1009.         $container System::getContainer();
  1010.         if (!$previewScript $container->getParameter('contao.preview_script'))
  1011.         {
  1012.             return $this->getAbsoluteUrl($strParams);
  1013.         }
  1014.         $context $container->get('router')->getContext();
  1015.         $baseUrl $context->getBaseUrl();
  1016.         // Add the preview script
  1017.         $context->setBaseUrl($previewScript);
  1018.         $objUrlGenerator $container->get('contao.routing.url_generator');
  1019.         $strUrl $objUrlGenerator->generate
  1020.         (
  1021.             ($this->alias ?: $this->id) . $strParams,
  1022.             array
  1023.             (
  1024.                 '_locale' => $this->rootLanguage,
  1025.                 '_domain' => $this->domain,
  1026.                 '_ssl' => (bool) $this->rootUseSSL,
  1027.             ),
  1028.             UrlGeneratorInterface::ABSOLUTE_URL
  1029.         );
  1030.         $context->setBaseUrl($baseUrl);
  1031.         return $this->applyLegacyLogic($strUrl$strParams);
  1032.     }
  1033.     /**
  1034.      * Return the slug options
  1035.      *
  1036.      * @return array The slug options
  1037.      */
  1038.     public function getSlugOptions()
  1039.     {
  1040.         $slugOptions = array('locale'=>$this->language);
  1041.         if ($this->validAliasCharacters)
  1042.         {
  1043.             $slugOptions['validChars'] = $this->validAliasCharacters;
  1044.         }
  1045.         return $slugOptions;
  1046.     }
  1047.     /**
  1048.      * Modifies a URL from the URL generator.
  1049.      *
  1050.      * @param string $strUrl
  1051.      * @param string $strParams
  1052.      *
  1053.      * @return string
  1054.      */
  1055.     private function applyLegacyLogic($strUrl$strParams)
  1056.     {
  1057.         // Decode sprintf placeholders
  1058.         if (strpos($strParams'%') !== false)
  1059.         {
  1060.             @trigger_error('Using sprintf placeholders in URLs has been deprecated and will no longer work in Contao 5.0.'E_USER_DEPRECATED);
  1061.             $arrMatches = array();
  1062.             preg_match_all('/%([sducoxXbgGeEfF])/'$strParams$arrMatches);
  1063.             foreach (array_unique($arrMatches[1]) as $v)
  1064.             {
  1065.                 $strUrl str_replace('%25' $v'%' $v$strUrl);
  1066.             }
  1067.         }
  1068.         // HOOK: add custom logic
  1069.         if (isset($GLOBALS['TL_HOOKS']['generateFrontendUrl']) && \is_array($GLOBALS['TL_HOOKS']['generateFrontendUrl']))
  1070.         {
  1071.             @trigger_error('Using the "generateFrontendUrl" hook has been deprecated and will no longer work in Contao 5.0.'E_USER_DEPRECATED);
  1072.             foreach ($GLOBALS['TL_HOOKS']['generateFrontendUrl'] as $callback)
  1073.             {
  1074.                 $strUrl System::importStatic($callback[0])->{$callback[1]}($this->row(), $strParams$strUrl);
  1075.             }
  1076.             return $strUrl;
  1077.         }
  1078.         return $strUrl;
  1079.     }
  1080. }
  1081. class_alias(PageModel::class, 'PageModel');