Edit via SFTP
<?php namespace ferret;
 FOLDER DOC: https://htyp.org/Ferreteria/v0.4/file/menu/items
  PURPOSE: base class for menu-links which are usage-aware
    Base class does not define how usage is determined.
    It is also still PASSIVE - status checks happen when rendering.
  ADDS: usage-awareness
    2017-02-08 Can't see any reason for ActionClass methods to be defined here; moving them to Dropin Link class
      (in dropin.php).
    2017-03-26 Figuring authorization at RunCalculations time now, instead of at Render time, because in the latter case
      we don't have the list of missing permits at render time (when we might want to display them).
abstract class cMenuLink extends \fcNavLink {
    #use ftLinkKey;
    // ++ SETUP ++ //
        array['base']	= base URL to prefix all output URLs
        array['name']	= value of unique key
        array['value'] 	= (optional) text to display
        array['popup']	= (optional) hover-over text
    const PERM_NONE = '';
    protected function SetupDefaults() : void {
        // this class is security-aware, but assumes permission by default:
        $this->SetRequiredPrivilege(self::PERM_NONE); // total lack of permit is adequate
    private $sPageTitle = NULL;
    public function SetPageTitle(string $s) { $this->sPageTitle = $s; }
    protected function HasPageTitle() : bool { return !is_null($this->sPageTitle); }
    protected function GetPageTitle() : string { return $this->sPageTitle; }
    private $sReqPriv = '';
    public function SetRequiredPrivilege(string $sPerm) { $this->sReqPriv = $sPerm; }
    protected function GetRequiredPrivilege() : string { return $this->sReqPriv; }
    protected function MakeURL_fromPath(string $sPath) : string {
        $osBase = $this->BasePath();
        $wpBase = $osBase->GetIt();
        if (strlen($wpBase) == 0) {
            $wpBase .= \ferret\globals\cAbstract::Me()->WebPath_Separator();
        return $wpBase.$sPath;
    // -- SETUP -- //
    // ++ CALCULATIONS ++ //
        2017-01-01 Deleting unauthorized nodes ensures that nothing further happens if not authorized.
            More practically, it also means that the folder doesn't need to do a count of "permitted" nodes
            in order to decide whether or not to display itself; it can assume any remaining nodes are permitted.
            If we later decide NOT to delete unauthorized nodes, then we need
                (a) some way to prevent them from being selected
                (b) some reasonably efficient way for the parent-folder to count how many are permitted
        2017-02-10 Came really close to needing to hide the "users" node from unauthorized users while still allowing
          them to access their own profile through it, but decided that "my profile" should be a "do:" command instead.
          If we (later) want admins to be able to modify other users' profiles without logging in as them, we can add
          an extra user ID parameter. No changes made here.
    protected function FigureIfAuthorized() : bool {
        $sPerm = $this->GetRequiredPrivilege();
        $ok = FALSE;
        $oApp = \fcApp::Me();
        if ($sPerm == self::PERM_NONE) {
            // in this context, NULL permission means everyone is authorized
            $ok = TRUE;
        } elseif ($oApp->UserIsLoggedIn()) {            if ($oApp->UserStatus()->Record()->GetIt()->CanDo($sPerm)) {
                // this item has been authorized for access
                $ok = TRUE;	// node has been authorized
        if (!$ok) {
            // We used to make sure the node has a parent before deleting it, but menu entries should never be the node-tree root.
            // And actually, root nodes should respond sensibly to this request anyway.
        return $ok;
    // -- CALCULATIONS -- //
    // ++ INPUT-TO-OUTPUT STATES ++ //
    private $isActive;
    protected function SetIsActive(bool $b) { $this->isActive = $b; }
    protected function GetIsActive() : bool { return $this->isActive; }
      PURPOSE: This is essentially a stub routine for descendents to override
	if they want to impose conditions.
    protected function GetShouldDisplay() : bool { return TRUE; }
    // -- INPUT-TO-OUTPUT STATES -- //