Zend Navigation Find Page and Render Menu with its Subpages - zend-framework

I am putting together a Zend Navigation for a site with 4 different levels of access: Guest, Member1, Member2, and Admin.
My navigation XML looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<nav>
<default>
<label>Home</label>
<controller>index</controller>
<action>index</action>
<resource>index</resource>
<privilege>index</privilege>
<pages>
<home>
...
</home>
<signin>
...
</signin>
<signup>
...
</signup>
</pages>
</default>
<member1>
<label>Member1 Main</label>
<controller>member1</controller>
<action>index</action>
<resource>member1</resource>
<privilege>index</privilege>
<pages>
<dashboard>
...
</dashboard>
<settings>
<label>Settings</label>
<controller>auth</controller>
<action>editpassword</action>
<resource>auth</resource>
<privilege>editpassword</privilege>
<class>settings</class>
<title>User settings</title>
<pages>
<account>
...
</account>
<logout>
...
</logout>
</pages>
</settings>
</pages>
</member1>
<member2>
<label>Member2 Main</label>
<controller>member2</controller>
<action>index</action>
<resource>member2</resource>
<privilege>index</privilege>
<pages>
<dashboard>
...
</dashboard>
<profile>
...
</profile>
<settings>
<label>Settings</label>
<controller>auth</controller>
<action>editpassword</action>
<resource>auth</resource>
<privilege>editpassword</privilege>
<class>settings</class>
<pages>
<account>
...
</account>
<logout>
...
</logout>
</pages>
</settings>
</pages>
</member2>
<admin>
<label>Dashboard</label>
<controller>admin</controller>
<action>index</action>
<resource>admin</resource>
<privilege>index</privilege>
<pages>
<dashboard>
...
</dashboard>
<logout>
...
</logout>
</pages>
</admin>
</nav>
</config>
Since I am using submenus and want consistency for top menu, I want to use a Zend's findBy feature to locate current user's status and display that menu. This is done as such:
if ( $this->user ) {
$submenu = $this->navigation()->findOneByLabel('Member1 Main');
$options = array(
'ulClass' => 'navigation',
'renderParents' => true,
'minDepth' => null,
'maxDepth' => null
);
echo $this->navigation()->menu()->renderMenu($submenu, $options);
} else {
echo $this->navigation()->menu()->setUlClass('navigation')->setOnlyActiveBranch(true)->setMinDepth(1)->setMaxDepth(1);
}
My Bootstrap bit for Nav is pretty generic and looks like this:
function _initNavigation()
{
$this->bootstrap('layout');
$layout = $this->getResource('layout');
$view = $layout->getView();
$navConfig = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav');
$navigation = new Zend_Navigation($navConfig);
$front = Zend_Controller_Front::getInstance();
$myPlagin = $front->getPlugin('My_Controller_Plugin_Acl');
$view->navigation($navigation)->setAcl($myPlagin->getMyAcl())
->setRole($myPlagin->getMyUserRole());
}
Now, I can get the "Member1 Main" page to appear, but it only shows that one page, but what I need to render is that page's whole submenu. It seems that findOneByLabel only looks up that particular page only and not its descendants. Is there a way to pull the whole submenu?
Thanks.

Turns out I had to use findAllByLabel to get the expected result. Thanks #RockyFord

Related

Add custom variables in magento 2 to use in REST API

I am using some data in my web site like social links, contact address, contact phone, slider banners, I can use them as html in blocks or contact pages. But I am facing a problem, How to call them as REST API. I Already uses Magento2 API:
/V1/cmsBlock/:blockId
/V1/cmsPage/:pageId
But the respobse is html and it is so bad. any help?
For the data like social links, contact numbers etc I suggest you to add this as text in the configuration, to do so you can create a module that has the following structure:
app/code/Jsparo/Customapi/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Jsparo_Customapi',
__DIR__
);
app/code/Jsparo/Customapi/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
<module name="Jsparo_Customapi" setup_version="1.0.0">
</module>
</config>
app/code/Jsparo/Customapi/etc/adminhtml/system.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="jsparo" translate="label" sortOrder="1100">
<label>Jsparo</label>
</tab>
<section id="jsparo_social" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Social</label>
<tab>jsparo</tab>
<resource>Jsparo_Social::config</resource>
<group id="facebook" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Facebook</label>
<field id="url" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Facebook Url</label>
</field>
</group>
</section>
</system>
</config>
app/code/Jsparo/Customapi/etc/webapi.xml
<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/jsparo/facebook" method="GET">
<service class="Jsparo\Customapi\Api\FacebookInterface" method="getUrl"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
</routes>
app/code/Jsparo/Customapi/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Jsparo\Customapi\Api\FacebookInterface" type="Jsparo\Customapi\Model\Facebook"/>
</config>
app/code/Jsparo/Customapi/Api/FacebookInterface.php
<?php
namespace Jsparo\Customapi\Api;
interface FacebookInterface {
/**
* #return string $url
*/
public function getUrl();
}
app/code/Jsparo/Customapi/Helper/Data.php
<?php
namespace Jsparo\Customapi\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
class Data extends AbstractHelper {
const prefix = 'jsparo_social/';
private function moduleConfig($key) {
return $this->scopeConfig->getValue(self::prefix . $key);
}
public function getFacebookUrl() {
return $this->moduleConfig('facebook/url');
}
}
app/code/Jsparo/Customapi/Model/Facebook.php
<?php
namespace Jsparo\Customapi\Model;
use Jsparo\Customapi\Helper\Data;
class Facebook implements FacebookInterface {
private $helper;
public function __construct(
Data $helper
) {
$this->helper = $helper;
}
public function getUrl() {
return $this->helper->getFacebookUrl();
}
}
You might have to do some adjustments and add all the fields / api endpoints that you need to it.
You can add also Caching to your API by using the Magento\Framework\App\CacheInterface to avoid having to perform certain computations.
Notice that I created the endpoint with the anonymous role, so that it is not protected.
EDIT: I created a github repository where you can see the full source and edited the couple typos that were above. I assume that this module source code gets added in app/code/Jsparo/Customapi.

Magento Observer Event not firing in server but working in local

I am facing the issue when i move the code to server.It is working fine in my local system.
when i searched about the issue i found i have to use capital letters in config file.
I have updated the config file to caps but still the issue exist.
Please suggest.
Config.xml
<?xml version="1.0"?>
<config>
<modules>
<Mdl_Ajaxcheckout>
<version>0.1.0</version>
<depends>
<Mage_Customer />
<Mage_Checkout />
</depends>
</Mdl_Ajaxcheckout>
</modules>
<global>
<models>
<mdlajaxcheckout>
<class>Mdl_Ajaxcheckout_Model</class>
</mdlajaxcheckout>
</models>
<events>
<checkout_cart_product_add_after>
<observers>
<mdl_ajaxcheckout_model_observer>
<class>Mdl_Ajaxcheckout_Model_Observer</class>
<method>modifyPrice</method>
</mdl_ajaxcheckout_model_observer>
</observers>
</checkout_cart_product_add_after>
</events>
<blocks>
<mdlajaxcheckout>
<class>Mdl_Ajaxcheckout_Block</class>
</mdlajaxcheckout>
</blocks>
<helpers>
<mdlajaxcheckout>
<class>Mdl_Ajaxcheckout_Helper</class>
</mdlajaxcheckout>
</helpers>
</global>
<frontend>
<layout>
<updates>
<mdlajaxcheckout>
<file>mdlajaxcheckout.xml</file>
</mdlajaxcheckout>
</updates>
</layout>
<translate>
<modules>
<Mdl_Ajaxcheckout>
<files>
<default>mdl_ajaxcheckout.csv</default>
</files>
</Mdl_Ajaxcheckout>
</modules>
</translate>
</frontend>
<frontend>
<routers>
<mdlajaxcheckout>
<use>standard</use>
<args>
<module>Mdl_Ajaxcheckout</module>
<frontName>mdlajaxcheckout</frontName>
</args>
</mdlajaxcheckout>
</routers>
</frontend>
<adminhtml>
<acl>
<resources>
<admin>
<children>
<catalog>
<children>
<mdlajaxcheckout_adminform>
<title>Configuration</title>
</mdlajaxcheckout_adminform>
</children>
</catalog>
</children>
</admin>
</resources>
</acl>
<acl>
<resources>
<admin>
<children>
<system>
<children>
<config>
<children>
<mdlajaxcheckout>
<title>Mdl Ajax Cart</title>
</mdlajaxcheckout>
</children>
</config>
</children>
</system>
<customer>
<children>
<mdlajaxcheckout translate="title">
<title>Mdl Ajax Cart</title>
<sort_order>45</sort_order>
</mdlajaxcheckout>
</children>
</customer>
</children>
</admin>
</resources>
</acl>
</adminhtml>
<default>
<mdlajaxcheckout>
<default>
<mdl_ajax_cart_loading_size>260x50</mdl_ajax_cart_loading_size>
<mdl_ajax_cart_confirm_size>320x134</mdl_ajax_cart_confirm_size>
<mdl_ajax_cart_image_size>55x55</mdl_ajax_cart_image_size>
<mdl_ajax_cart_show_popup>1</mdl_ajax_cart_show_popup>
</default>
</mdlajaxcheckout>
</default>
<global>
</global>
</config>
Observer.php
<?php
class Mdl_Ajaxcheckout_Model_Observer
{
public function modifyPrice(Varien_Event_Observer $obs)
{
// Get the quote item
$item = $obs->getQuoteItem();
// Ensure we have the parent item, if it has one
$item = ( $item->getParentItem() ? $item->getParentItem() : $item );
//$demo=new Mdl_Ajaxcheckout_IndexController();
// Load the custom price
$price ="20";
// Set the custom price
$item->setCustomPrice($price);
$item->setOriginalCustomPrice($price);
// Enable super mode on the product.
$item->getProduct()->setIsSuperMode(true);
Mage::getSingleton('core/session')->setWelcomeMessage();
}
}
?>
code for enabling the module.
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Mdl_Ajaxcheckout>
<!-- Whether our module is active: true or false -->
<active>true</active>
<!-- Which code pool to use: core, community or local -->
<codePool>community</codePool>
</Mdl_Ajaxcheckout>
</modules>
</config>
Finally I got the solution for above thread.
We need to disable the compiler status in admin.
system->tools->compilation->click disable.
Now your observer event will work.

Zend Navigation - Rendering a submenu

I define all my pages in a XML file like the following:
<?xml version="1.0" encoding="UTF-8"?>
<configdata>
<nav>
<dashboard>
<label>Dashboard</label>
<module>default</module>
<controller>dashboard</controller>
<action>index</action>
<title>Die Schaltzentrale</title>
</dashboard>
<user>
<label>User</label>
<module>default</module>
<controller>user</controller>
<action>index</action>
<title>Verwaltung der Benutzer</title>
<userList>
<module>default</module>
<controller>user</controller>
<action>index</action>
<label>Userliste anzeigen</label>
</userList>
<newUser>
<label>User anlegen</label>
<module>default</module>
<controller>user</controller>
<action>new</action>
</newUser>
<editUser>
<label>User bearbeiten</label>
<module>default</module>
<controller>user</controller>
<action>edit</action>
</editUser>
</user>
</nav>
</configdata>
In my bootstrap I setup my navigation like this:
protected function _initNavigation()
{
$this->bootstrap('layout');
$layout = $this->getResource('layout');
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$view = $layout->getView();
$navigation = new Zend_Navigation($config);
$view->navigation($navigation);
Zend_Registry::set('Zend_Navigation',$navigation);
}
This setup enables me to render my main menu with the following lines:
$partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial);
echo $this->navigation()->menu()->render();
So far so good. My problem is now to render a particular submenu. Let's say I want to render a menu with all actions of the user controller. I tried to render it with:
$page = $this->navigation()->findOneBy('controller','user');
echo $this->navigation()->menu()->renderMenu($page);
But I got no output. I also tried to obtain an output by setting the minDepth or maxDepth option without any success. Has anyone a hind for me, how I can bring it to work?
Your approach is very close. Change the findOneBy line to:
$page = $this->navigation()->findOneBy('label','User');
This will fetch all the pages under the User page.
I do not think it is possible to find a page by controller.
[edit]
I have modified your xml by adding a 'pages' section under user. This tells Zend Navigation that userList, newUser and editUser are sub-pages of user:
<?xml version="1.0" encoding="UTF-8"?>
<configdata>
<nav>
<dashboard>
<label>Dashboard</label>
<module>default</module>
<controller>dashboard</controller>
<action>index</action>
<title>Die Schaltzentrale</title>
</dashboard>
<user>
<label>User</label>
<module>default</module>
<controller>user</controller>
<action>index</action>
<title>Verwaltung der Benutzer</title>
<pages>
<userList>
<module>default</module>
<controller>user</controller>
<action>index</action>
<label>Userliste anzeigen</label>
</userList>
<newUser>
<label>User anlegen</label>
<module>default</module>
<controller>user</controller>
<action>new</action>
</newUser>
<editUser>
<label>User bearbeiten</label>
<module>default</module>
<controller>user</controller>
<action>edit</action>
</editUser>
</pages>
</user>
</nav>
</configdata>

zend naviagtion not working due to zend route

EDIT::
the problem was caused due to zend route please check updates
I am using xml file for navigation.
EDIT::the following code is from layout.phtml file
$config = new Zend_Config_Xml(APPLICATION_PATH.'/configs/adminnav.xml', 'nav');
$container = new Zend_Navigation($config);
$this->navigation()->setContainer($container);
echo $this->navigation();
when i am in my edit page, all don't any menu link. all get is /admin/controller/edit/ everywhere on menu item. any idea?
my edit action takes id, if id is not supplied then it will generate and error. however add and list method works fine
UPDATES::
<?xml version="1.0"?>
<config>
<nav>
<home>
<label>home</label>
<uri>#</uri>
<pages>
<home>
<label>home</label>
<module>admin</module>
<controller>home</controller>
<action>index</action>
</home>
<help>
<label>help</label>
<module>admin</module>
<controller>home</controller>
<action>help</action>
</help>
</pages>
</home>
<page>
<label>pages</label>
<uri>#</uri>
<pages>
<static>
<label>static pages</label>
<module>admin</module>
<controller>page</controller>
<action>index</action>
</static>
<editpage>
<label>static pages</label>
<module>admin</module>
<controller>page</controller>
<action>edit</action>
</editpage>
</pages>
</page>
<destination>
<label>destinations</label>
<uri>#</uri>
<pages>
<list>
<label>list all</label>
<module>admin</module>
<controller>destination</controller>
<action>index</action>
</list>
<featured>
<label>featured</label>
<module>admin</module>
<controller>destination</controller>
<action>featured</action>
</featured>
<add>
<label>add destination</label>
<module>admin</module>
<controller>destination</controller>
<action>add</action>
</add>
<editdest>
<label>edit destination</label>
<module>admin</module>
<controller>destination</controller>
<action>edit</action>
</editdest>
</pages>
</destination>
<tours>
<label>tours</label>
<uri>#</uri>
<pages>
<list>
<label>list tours</label>
<module>admin</module>
<controller>tour</controller>
<action>index</action>
</list>
<featured>
<label>featured tours</label>
<module>admin</module>
<controller>tour</controller>
<action>featured</action>
</featured>
<add>
<label>add tours</label>
<module>admin</module>
<controller>tour</controller>
<action>add</action>
</add>
<edittour>
<label>edit tours</label>
<module>admin</module>
<controller>tour</controller>
<action>add</action>
</edittour>
</pages>
</tours>
<hotels>
<label>hotels and resort</label>
<uri>#</uri>
<pages>
<list>
<label>list hotel</label>
<module>admin</module>
<controller>hotel</controller>
<action>index</action>
</list>
<add>
<label>add hotel</label>
<module>admin</module>
<controller>hotel</controller>
<action>add</action>
</add>
<edithotel>
<label>add hotel</label>
<module>admin</module>
<controller>hotel</controller>
<action>add</action>
</edithotel>
</pages>
</hotels>
<message>
<label>message</label>
<uri>#</uri>
<pages>
<all>
<label>all message</label>
<module>admin</module>
<controller>message</controller>
<action>index</action>
</all>
<contactus>
<label>contact</label>
<module>admin</module>
<controller>message</controller>
<action>contact</action>
</contactus>
<inquiry>
<label>inquiry</label>
<module>admin</module>
<controller>message</controller>
<action>inquiry</action>
</inquiry>
<reservation>
<label>reservation</label>
<module>admin</module>
<controller>message</controller>
<action>reservation</action>
</reservation>
</pages>
</message>
<advertisement>
<label>advertisement</label>
<uri>#</uri>
<pages>
<list>
<label>list ads</label>
<module>admin</module>
<controller>advertisement</controller>
<action>index</action>
</list>
<add>
<label>add ads</label>
<module>admin</module>
<controller>advertisement</controller>
<action>add</action>
</add>
<editad>
<label>edit ads</label>
<module>admin</module>
<controller>advertisement</controller>
<action>edit</action>
</editad>
</pages>
</advertisement>
<setting>
<label>settings</label>
<uri>#</uri>
<pages>
<view>
<label>view</label>
<module>admin</module>
<controller>setting</controller>
<action>view</action>
</view>
<account>
<label>account setting</label>
<module>admin</module>
<controller>setting</controller>
<action>account</action>
</account>
<site>
<label>site setting</label>
<module>admin</module>
<controller>setting</controller>
<action>site</action>
</site>
</pages>
</setting>
</nav>
</config>
UPDATE::route for the edit action on bootstrap.php
$frontcontroller = Zend_Controller_Front::getInstance();
$router = $frontcontroller->getRouter('router');
//add route for edit page so that pageid is not displayed in the url
$router->addRoute(
'edit-page',
new Zend_Controller_Router_Route('admin/page/edit/:pageid', array(
'module' => 'admin',
'controller' => 'page',
'action' => 'edit',
'pageid' => 'pageid'
))
);
UPDATE::to Phil
<editdest>
<label>edit destination</label>
<module>admin</module>
<controller>destination</controller>
<action>edit</action>
<route>12</route>
</editdest>
Error for this::
Fatal error: Zend_Controller_Router_Exception: Route 12 is not defined in
/usr/share/php/libzend-framework-php/Zend/View/Helper/Navigation/HelperAbstract.php
on line 522
If there are any static routes involved, you need to set the route name on all navigation pages. This is because the navigation view helper uses the Url view helper to create links.
If there is no route name present, it uses the current route.
If the current route is a static one, it will only ever resolve to one URL, no matter what parameters are thrown at it.
You should use the route you defined in $router->addRoute.
It should be:
$router->addRoute(
'edit-page',
new Zend_Controller_Router_Route('admin/page/edit/:pageid', array(
'module' => 'admin',
'controller' => 'destination',
'action' => 'edit',
'pageid' => 'pageid'
))
);
<editdest>
<label>edit destination</label>
<module>admin</module>
<controller>destination</controller>
<action>edit</action>
<route>edit-page</route>
<params>
<pageid>12</pageid>
</params>
</editdest>
If you need different edit links on each page, you have to update the params in navigation container dynamically, i.e.:
// (pseudocode, not tested)
$this->navigation()->getContainer()->findOneByLabel('edit destination')->params->pageid = 12

Zend Framework - how to apply icon in xml file and retriev it

When it load the xml file, the icon cause failure inside the label tags. How to fix it?
// horizontal top menu
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nav>
<page1>
<label><img src='icon.icon' /> Page 1</label>
<controller>index</controller>
</page1>
<home>
<label>Home</label>
<controller>index</controller>
</home>
</nav>
</root>
// controller test
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav');
$container = new Zend_Navigation($config);
$this->view->navigation($container);
I suppose you could do it with CSS instead
// horizontal top menu
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nav>
<page1>
<label>Page 1</label>
<controller>index</controller>
<class>menu-page1-icon</class>
</page1>
</nav>
</root>
CSS
.menu-page1-icon:before {
content: url(path/to/icon.icon);
}
It should probably be in a cdata section:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nav>
<page1>
<label><![CDATA[<img src='icon.icon' /> Page 1]]></label>
<controller>index</controller>
</page1>
<home>
<label>Home</label>
<controller>index</controller>
</home>
</nav>
</root>
http://msdn.microsoft.com/en-us/library/ms256076.aspx