src/menu/InjectItem.php
<?php
namespace luya\cms\menu;
use luya\cms\Exception;
use luya\cms\Menu;
use Yii;
use yii\base\BaseObject;
use yii\helpers\Inflector;
/**
* An item inject gives a module the possibility to add items into the menu Container.
*
* The most important propertie of the injectItem clas is the `childOf` definition, this
* is where you have to define who is the parent *nav_item.id*.
*
* An item inject contain be done during the eventAfterLoad event to attach at the right
* initializer moment of the item, but could be done any time. To inject an item use the
* `injectItem` method on the menu Container like below:
*
* ```php
* Yii::$app->menu->injectItem(new InjectItem([
* 'childOf' => 123,
* 'title' => 'This is the inject title',
* 'alias' => 'this-is-the-inject-alias',
* ]));
* ```
*
* Instead of using the childOf property you can directly set an menu item:
*
* ```php
* Yii::$app->menu->injectItem(new InjectItem([
* 'item' => Yii::$app->menu->current,
* 'title' => 'This is the inject title',
* 'alias' => 'this-is-the-inject-alias',
* ]));
* ```
*
* You can also use the chain method to create a new inject item:
*
* ```php
* $item = (new InjectItem())->setTitle('My Title')->setAlias('my Alias')->setItem(Yii::$app->menu->current);
* ```
*
* To attach the item at right moment you can bootstrap your module and use the `eventAfterLoad`
* event of the menu component:
*
* ```php
* Yii::$app->menu->on(\luya\cms\Menu::EVENT_AFTER_RESOLVE_CURRENT, function($event) {
*
* $newItem = new InjectItem([
* 'childOf' => 123,
* 'title' => 'Inject Title',
* 'alias' => 'inject-title',
* ]);
*
* $event->sender->injectItem($newItem);
* });
* ```
*
* Inside a configuration file this could be done as:
*
* ```php
* 'menu' => [
* 'class' => 'luya\cms\Menu',
* 'on eventAfterLoad' => function($event) {
* // ...
* $event->sender->injectItem($newItem);
* }
* ]
* ```
*
* Be aware that the parent item must be available for current language.
*
* @property $childOf integer The child of id in order read data from this parent item.
* @property $item \luya\cms\menu\Item The resolved Item.
* @property $navId integer|string The navId for this inject item.
* @property $id integer|string The id (navItemId) for this inject item.
* @property $link string The link to the detail view.
* @property $alias The alias path.
* @property $title The navigation menu title.
* @property $lang The language container name.
* @property $description Alternative page descriptions.
* @property $parentNavId Parent page definition
*
* @author Basil Suter <basil@nadar.io>
* @since 1.0.0
*/
class InjectItem extends BaseObject implements InjectItemInterface
{
/**
* @var integer The user id who created this page.
*/
public $createUserId = 0;
/**
* @var integerThe user id who updated this page as last person.
*/
public $updateUserId = 0;
/**
* @var integer The number which is used to sort the injected item. Lower is at the top.
*/
public $sortIndex = 0;
/**
* @var boolean Whether this page is hidden or not.
*/
public $isHidden = false;
// Getter & Setter
private $_item;
/**
* Returns the evalutead menu item whether from the childOf property or set from the setter method.
* @return Item
* @throws Exception
*/
public function getItem()
{
if ($this->_item === null) {
$this->_item = Yii::$app->menu->find()->where(['id' => $this->childOf])->with('hidden')->one();
if (!$this->_item) {
throw new Exception("Unable to find item with id " . $this->childOf);
}
}
return $this->_item;
}
/**
* Setter method for the item property.
*
* @return \luya\cms\menu\InjectItem
*/
public function setItem(Item $item)
{
$this->childOf = $item->id;
$this->_item = $item;
return $this;
}
private $_childOf;
/**
* Setter method for childOf property.
*
* @param integer $id
* @return \luya\cms\menu\InjectItem
*/
public function setChildOf($id)
{
$this->_childOf = (int) $id;
return $this;
}
/**
* Getter method for the childOf property.
*
* @throws Exception
* @return number
*/
public function getChildOf()
{
if ($this->_childOf === null) {
throw new Exception("In order to inject an item, you have to set the `childOf` property.");
}
return $this->_childOf;
}
private $_alias;
/**
* Setter method for the item alias.
*
* @param string $alias A slugable alias string will be parsed by the inflector::slug method.
* @return \luya\cms\menu\InjectItem
*/
public function setAlias($alias)
{
$this->_alias = Inflector::slug($alias);
return $this;
}
/**
* Getter method for the alias.
* @return string The alias with the parent childOf alias prefixed.
* @throws Exception
*/
public function getAlias()
{
if ($this->_alias === null) {
throw new Exception('The $alias property can not be null and must be set.');
}
return $this->item->alias . '/' . $this->_alias;
}
private $_link;
/**
* Setter method fro the link.
*
* @param string $url
* @return \luya\cms\menu\InjectItem
*/
public function setLink($url)
{
$this->_link = $url;
return $this;
}
/**
* Getter method for the menu link.
*
* @return string The built link.
*/
public function getLink()
{
return $this->_link ?? Yii::$app->menu->buildItemLink($this->alias, $this->getLang());
}
private $_title;
/**
* Setter method for the menu title.
*
* @param string $title The menu item title.
* @return \luya\cms\menu\InjectItem
*/
public function setTitle($title)
{
// if the alias is empty use the title for the alias.
if ($this->_alias === null) {
$this->setAlias($title);
}
$this->_title = $title;
return $this;
}
/**
* Getter method for the menu title.
*
* @throws Exception
* @return string
*/
public function getTitle()
{
if ($this->_title === null) {
throw new Exception('The $title property can not be null and must be set.');
}
return $this->_title;
}
private $_description;
/**
* Setter method for menu page description.
*
* @param string $description Description for the menu item.
* @return \luya\cms\menu\InjectItem
*/
public function setDescription($description)
{
$this->_description = $description;
return $this;
}
/**
* Getter method for the menu page description.
*
* @return string The menu item description.
*/
public function getDescription()
{
return $this->_description;
}
// Getters
/**
* Getter method for the container from the child of item.
*
* @return integer
*/
public function getContainer()
{
return $this->item->container;
}
/**
* Returns the depth number based on the alias paths.
*
* @return number
*/
public function getDept()
{
return count(explode('/', $this->alias));
}
private $_lang;
/**
* Returns the language from the childOf item.
*
* @return string
*/
public function getLang()
{
if ($this->_lang === null) {
$this->_lang = $this->item->lang;
}
return $this->_lang;
}
/**
* Setter method for language container.
*
* @param string $lang The language short code for the given item, if nothing set the item will be resolved
* due to useage of the parent item from $this->item.
*/
public function setLang($lang)
{
$this->_lang = $lang;
}
private $_parentNavId;
/**
* Getter method for the parent nav id from the childOf item.
*
* @return integer
*/
public function getParentNavId()
{
if ($this->_parentNavId === null) {
return $this->item->navId;
}
return $this->_parentNavId;
}
/**
* Overide default implementation of evaluated process for parent nav id
*
* @param int $parentNavId
*/
public function setParentNavId($parentNavId)
{
$this->_parentNavId = $parentNavId;
}
/**
* Getter method for the create item timestamp.
*
* @return number
*/
public function getTimestampCreate()
{
return time();
}
/**
* Getter method for the update item timestamp.
*
* @return number
*/
public function getTimestampUpdate()
{
return time();
}
/**
* Getter method for the isHhome item, which is false by default.
* @return number
*/
public function getIsHome()
{
return (int) false;
}
/**
* Getter method for the type which is by default a page.
*
* @return number
*/
public function getType()
{
return Menu::ITEM_TYPE_PAGE;
}
/**
* Getter method for the redirect content if its a redirect page, by default 0.
*
* @return number
*/
public function getRedirect()
{
return 0;
}
private $_id;
/**
* Setter method for the id (unique id).
*
* @param integer $id
*/
public function setId($id)
{
$this->_id = $id;
}
/**
* Getter method for the unique id.
*/
public function getId(): string|int
{
if ($this->_id === null) {
$this->_id = random_int(10000, 1_000_000);
}
return $this->_id;
}
private $_navId;
/**
* Setter method for the navId.
*
* @param unknown $navId
*/
public function setNavId($navId)
{
$this->_navId = $navId;
}
/**
* Getter method for the navId.
*
* @return string|unknown
*/
public function getNavId()
{
if ($this->_navId === null) {
$this->_navId = random_int(10000, 1_000_000);
}
return $this->_navId;
}
/**
* Parse the injected item to an array.
*
* @return array
*/
public function toArray()
{
return [
'id' => $this->getId(),
'nav_id' => $this->getNavId(),
'lang' => $this->getLang(),
'link' => $this->getLink(),
'title' => Yii::$app->menu->encodeValue($this->title),
'title_tag' => Yii::$app->menu->encodeValue($this->title),
'alias' => $this->getAlias(),
'description' => Yii::$app->menu->encodeValue($this->description),
'keywords' => null,
'create_user_id' => $this->createUserId,
'update_user_id' => $this->updateUserId,
'timestamp_create' => $this->getTimestampCreate(),
'timestamp_update' => $this->getTimestampUpdate(),
'is_home' => $this->getIsHome(),
'parent_nav_id' => $this->getParentNavId(),
'sort_index' => $this->sortIndex,
'is_hidden' => (bool) $this->isHidden,
'type' => $this->getType(),
'redirect' => $this->getRedirect(),
'container' => $this->getContainer(),
'depth' => $this->getDept(),
];
}
}