echo Menu::widget([
'items' => [
// Important: you need to specify url as 'controller/action',
// not just as 'controller' even if default action is used.
['label' => 'Home', 'url' => ['site/index']],
// 'Products' menu item will be selected as long as the route is 'product/index'
['label' => 'Products', 'url' => ['product/index'], 'items' => [
['label' => 'New Arrivals', 'url' => ['product/index', 'tag' => 'new']],
['label' => 'Most Popular', 'url' => ['product/index', 'tag' => 'popular']],
]],
['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest],
],
]);
How about using a MenuItem class instead of putting everything in associative arrays? Arrays like these are not type safe and does not communicate intent. Further more, you can’t use inheritance to make subclasses of different types of menu items. Associative arrays lead to spaghetti code and does not scale well.
Edit: Some links:
Edit 2: One patchy solution to this could be using objects with ArrayAccess implemented.
Edit 3: Remember that our project is HUGE. First commit from 2003, 200+ contributors. It’s not a web page, but a scientific web app.
If you had been around since the very beginning of Yii, when @qiang started writing Yii after having created PRADO, you’d know that there are good reasons for Yii using e.g. arrays for things like this and many other parts of Yii as well. It was intentionally made more lightweight.
If you think about it, it could have abstracted a lot of other arrays as well into classes of different type. But it hasn’t done that, and I think it’s good. There’s no point overengineering.
Instead, you are completely free to create classes for this if you want or need to, and as you mentioned yourself, just make them arrayable. That should solve your problem unless I’m missing something.
The point I’m trying to make is that Yii is a framework that is pragmatic yet nicely designed, but part of this is not overengineering such as in this case. Simply go ahead and extend your menu stuff with classes if you want to. This makes sense in your large project, but it doesn’t make much sense for the tons of smaller projects that have a simpler menu.
Well, type-safety might be worth it or not depending on size and time. Longer/bigger --> type-safety brings stability. Especially if lots of people will read the code and extend it for 10+ years.
Not possible. Both programming languages and frameworks have a strong lock-in. But superpose our internal “opinions” on top of Yii might be the solution. If we can agree in the team.
There was a reason not to wrap everything in objects. First of all, it was not cheap with the PHP versions that were there at Yii 1.1 and Yii 2.0 creation times.
In Yii 3 we are moving to way more strictness while trying not to lose overall feeling of simplicity (with mixed success).
Yep, it’s not always easy or obvious which kind of interfaces are correct, or how to design interfaces. In my screenshot above I’m passing an array $options to the constructor. This still has several benefits over associative arrays, like default values, validation, immutability, encapsulation and type-safety (even if it’s mostly a “tag” on a data package). Named arguments would probably make the $options array obsolete.
Nice. But no CMenu or similar? Or how would you exemplify “more strictness” in relation to Yii 1 and 2? I see that the FlashMessage widget accepts not an array of data but explicitly typed objects in the constructor instead. https://github.com/yiisoft/app/blob/master/src/Widget/FlashMessage.php