Prestashop hook ModuleRoutes - prestashop

I have a problem with register hook and i cant find good documentation about moduleRoutes
my hook function :
public function hookModuleRoutes()
{
return [
'module-youtube_video-display' => [
'controller' => 'display',
'rule' => 'youtube_video',
'params' => [
'fc' => 'module',
'module' => 'youtube_video'
]
]
];
}
modules\youtube_video\vpages\controllers\front\display.php
class VpagesDisplayModuleFrontController extends ModuleFrontController {
public function init(){
parent::init();
$this->setTemplate('youtube_video.tpl');
}
}
modules\youtube_video\views\templates\hook\youtube_video.tpl
<div id="custom-text">
<p>{$youtube_url}</p></div>
i try this with difrent tutorials and still get 404 when i try go to route

You forgot a some features of Prestashop like 'link rewrite' and 'language'.
Try this:
public function hookModuleRoutes($params)
{
$head = Configuration::get('your_config', $this->language->id);
$my_youtube_video = array(
'module-youtube_video-display' => array(
'controller' => 'display',
'rule' => $head . '/youtube_video/{link_rewrite}',
'keywords' => array(
'link_rewrite' => array('regexp' => '[_a-zA-Z0-9-\pL]*', 'param' => 'link_rewrite'),
),
'params' => array(
'fc' => 'module',
'module' => 'youtube_video',
),
)
);
return $my_youtube_video;
}
And why do you have the 'vpages' in here? Why not just modules\youtube_video\controllers\front\display.php
And don't forget upon module install:
$this->registerHook('moduleRoutes');

Related

install.php is not being run during installation

My install.php is not being run during installation.I checked everywhere.To be sure,I ran the code in install.php elsewhere and it worked well. But during installation only the install.php is being skipped somehow.My module name is Hotelreservation, hence the code in install.php is as below. Why is there no error display during installation ?
<?php
class Hotelreservation_Installer extends Engine_Package_Installer_Module
{
public function onInstall()
{
$this->_hotelroomsBrowsePage();
parent::onInstall();
}
protected function _hotelroomsBrowsePage()
{
$db = $this->getDb();
// profile page
$page_id = $db->select()
->from('engine4_core_pages', 'page_id')
->where('name = ?', 'hotelreservation_index_browse')
->limit(1)
->query()
->fetchColumn();
if (!$page_id) {
// Insert page
$db->insert('engine4_core_pages', array(
'name' => 'hotelreservation_index_browse',
'displayname' => 'HotelRooms Browse Page',
'title' => 'Browse Rooms',
'description' => 'this page displays rooms',
'custom' => 0,
));
$page_id = $db->lastInsertId();
// Insert main
$db->insert('engine4_core_content', array(
'type' => 'container',
'name' => 'main',
'page_id' => $page_id,
));
$main_id = $db->lastInsertId();
// Insert middle
$db->insert('engine4_core_content', array(
'type' => 'container',
'name' => 'middle',
'page_id' => $page_id,
'parent_content_id' => $main_id,
'order' => 2,
));
$middle_id = $db->lastInsertId();
// Insert hotelreservation.browse-menu
$db->insert('engine4_core_content', array(
'type' => 'widget',
'name' => 'hotelreservation.browse-menu',
'page_id' => $page_id,
'parent_content_id' => $middle_id,
'order' => 1,
));
// Insert core content
$db->insert('engine4_core_content', array(
'type' => 'widget',
'name' => 'core.content',
'page_id' => $page_id,
'parent_content_id' => $middle_id,
'order' => 2,
));
// Insert left
$db->insert('engine4_core_content', array(
'type' => 'container',
'name' => 'left',
'page_id' => $page_id,
'parent_content_id' => $main_id,
'order' => 3,
));
$left_id = $db->lastInsertId();
}
return $this;
}
}// end class
Did you add info to mainfest file like this in packages array
'callback' => array(
'path' => 'Your path to php file',
'class' => 'Hotelreservation_Installer',
),
I agree with Arif. Check the file manifest.php inside of //settings:
(info of module Album)
'callback' => array(
'path' => 'application/modules/Album/settings/install.php',
'class' => 'Album_Installer',
),
I had this same issue and got it to work.
It turns out that the installer looks in application/packages/module-yourmodule-x.x.x.json first. around line 35 you'll find:
"callback": {
"path": null,
"class": "Engine_Package_Installer_Module",
"priority": 100
},
change that to:
"callback": {
"path": "application/modules/Yourmodule/settings/install.php",
"class": "Yourmodule_Installer",
"priority": 100
},
now, when you run the installer, your install.php will be called.

How can I use yii widget nested another widget?

class CommonHeaderWidget extends CWidget {
public function run() {
// I want use Another widget here,
// but it's no use like this:
$this->getController->widget('bootstrap.widgets.TbNavbar', array(
'items' => array(
array(
'class' => 'bootstrap.widgets.TbMenu',
'items' => array(
array('label' => 'mall', 'url' => '#'),
array('label' => 'Join', 'url' => #),
),
),
),
));
// end.
$this->render('commonHeader');
}
}
Then,I put the widget TbNavbar in commonHeader view ,it's no use too! How can I do?

Yii file CFormInputElement won't display unless explicitly marked "safe"

I'm trying to use Form Builder to build a simple file upload prompt. I want to specify the rule for the file to be similar to
array('formFile', 'file', 'allowEmpty' => false, 'types' => 'html'),
but something is wrong. The file upload element only appears if I explicitly mark the element as 'safe' (and remove the 'file' rule). What am I missing?
models/UploadForm.php
class UploadForm extends CFormModel
{
public $year;
public $formFile;
public function rules ()
{
return array(
array('year', 'required'),
array('year', 'date', 'format'=>'yyyy'),
// array('formFile', 'safe'),
array('formFile', 'file', 'allowEmpty' => false, 'types' => 'html'),
);
}
static public function getYearOptions () {...}
}
views/extranet/uploadForm.php
return array(
'title' => 'Select year',
'method' => 'post',
'enctype' => 'multipart/form-data',
'elements' => array(
'year' => array(
'type' => 'dropdownlist',
'items' => UploadForm::getYearOptions(),
),
'formFile' => array(
'type' => 'file',
'label' => 'form source file',
),
),
'buttons' => array(
'upload' => array(
'type' => 'submit',
'label' => 'upload',
),
),
);
controllers/ExtranetController.php
class ExtranetController extends CController
{
public function actionIndex ()
{
$form = new CForm('application.views.extranet.uploadForm', new UploadForm());
if ($form->submitted('upload') && $form->validate()) {...}
$this->render('index', array('form' => $form));
}
}
The reason for this is very simple.
The form builder only renders input elements which are considered safe (I.E. have a validation rule). What you have done is perfectly fine, except CFileValidator isn't "safe" by default, whereas other validators are safe.
The quickest way to solve this is the following:
// In your model::rules() function
return array(
array('formFile', 'file', 'allowEmpty' => false, 'types' => 'html', 'safe' => true),
);
Refer to these two links for more information: the CFileValidator#safe documentation, and the Github issue for a problem very similar to yours.

ZF2: create url aliases in router

I'm new to Zend Framework 2 and i want to learn this framework. I want to create url aliases in router.
For example, I have defined something like this in module.config.php
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Controller\AliasSegment',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
When i type www.myapp.local/node/1 it routes to the default action in default controller of my application. What i want is a router extension that can handle aliases for url paths. For example:
www.myapp.local/node/1 = www.myapp.local/aboutus
www.myapp.local/node/2 = www.myapp.local/company/gallery
I know that it was possible in ZF. Here is a link to tutorial how to achieve this in ZF:
friendly urls
I know that this is in Polish but code is self-explanatory i think :)
The idea is to use url helper to assembly valid url using aliases or normal segments (node/[:id])
I've already created AliasSegment class in my Application\Controller folder but it shows me an error:
Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Application\Controller\AliasSegment' in C:\xampp\htdocs\industengine\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:450 Stack trace: #0
My AliasSegment class (incomplete):
<?php
namespace Zend\Mvc\Router\Http;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
class AliasSegment extends Segment
{
public function match(Request $request, $pathOffset = null)
{
}
}
I was looking for an answer for hours and i couldnt find anything. Please tell me at least what I'm doing wrong, where to insert a code or maybe You know better sollution?
I'm not looking for ready application. I want to learn something but i would appreciate if You can tell me an answer in details :)
Thanks in advance and sorry for my English :)
EDITED:
My custom router is working now. At this moment aliases are hardcoded but it works.
My AliasSegment class looks now:
<?php
namespace Application\Controller;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class AliasSegment extends \Zend\Mvc\Router\Http\Segment
{
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
//sample logic here
//for /about/gallery uri set node id to 1
//todo: get action, controller and module from navigation
if($path == '/about/gallery'){
$uri->setPath('/node/1');
$request->setUri($uri);
}
return parent::match($request, $pathOffset);
}
protected function buildPath(array $parts, array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams, $isOptional, $hasChild);
}
}
In this case /about/gallery is an alias to /node/1. Both adresses are correct. The buildPath function returns alias path correctly. Well, I hope this would be usefull for somebody :)
However i want to setup it in Zend_Navigation with additional parameter named 'link'.
I've done 50% of what i want to achieve however now I have problem to get Zend_Navigation from my router. I don't know how to pass it. I guess it should be something like this:
$sm = $this->getServiceLocator();
$auth = $sm->get('Navigation');
It works in my IndexController but doesnt work in my AliasSegment. I need to find in navigation array nodes with 'link' parameter.
EDIT
I've found solution. The answer is below.
unable to fetch or create an instance for Application\Controller\AliasSegment
if this is controller then I would expect in module.config.php to have:
'controllers' => array(
'invokables' => array(
'\Application\Controller\AliasSegment' => '\Application\Controller\AliasSegment',
)
),
also namespace of your class looks a bit weird:
namespace Zend\Mvc\Router\Http;
what about:
namespace Application\Controller;
OK, I've made it. The important thing for this Thread:
ZF2: How to get Zend\Navigation inside custom route?.
You can use any segment type route. But this may need a little modifications to match function.
If navigation's single page will have 'link' param, the url will be converted to 'link' string but other params will stay behind it. Just think of it as an overlay for default URI of current route.
I had to modify my custom route class a little bit. First of all, i had to change its namespace to Application\Router. Here is a full class:
// EDIT - file within ModuleName/src/Router/Alias.php
namespace Application\Router;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class Alias extends Http\Segment
{
private static $_navigation = null;
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
$items = self::$_navigation->findAllBy('route', 'node');
$params = null;
if($items != null){
$t = sizeof($items);
for ($i=0; $i < $t; $i++) {
$item = $items[$i];
$params = $item->getParams();
if (isset($params['link']) && $params['link']==$path){
$uri->setPath('/'.$item->getRoute().'/'.$params['id']);
$request->setUri($uri);
break;
}
}
}
return parent::match($request, $pathOffset);
}
public function setNavigation($navigation){
self::$_navigation = $navigation;
}
protected function buildPath(array $parts,
array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams,
$isOptional, $hasChild);
}
}
here is sample part of module.config.php:
'navigation' => array(
// The DefaultNavigationFactory we configured in (1) uses 'default' as the sitemap key
'default' => array(
// And finally, here is where we define our page hierarchy
'account' => array(
'label' => 'Account',
'route' => 'node',
'params' => array(
'id' => '2',
),
'pages' => array(
'home' => array(
'label' => 'Dashboard',
'route' => 'node',
'params' => array(
'id' => '8',
'link' => '/about/gallery'
),
),
'login' => array(
'label' => 'Sign In',
'route' => 'node',
'params' => array(
'id' => '6',
'link' => '/signin'
),
),
'logout' => array(
'label' => 'Sign Out',
'route' => 'node',
'params' => array(
'id' => '3',
),
),
),
),
),
),
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Router\Alias',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
If it is just for routes like /about and /about/galery then you can simply use literal routes with child routes
'about' => array(
'type' => 'literal',
'options' => array(
'route' => '/about',
'defaults' => array(
'controller' => 'module-controller-about',
'action' => 'index'
)
),
'may_terminate' => true,
'child_routes' => array(
'galery' => array(
'type' => 'literal',
'options' => array(
'route' => '/galery',
'defaults' => array(
'controller' => 'module-controller-galery'
)
)
)
)
)
When it comes to URLs like /blog/1-my-great-seo-title you probably have to set-up a Regex route (which is the slowest, literals are fastest).
Maybe check out DASPRiDs Slides from his Router Presentation

Invalid type given. String expected - Zend Framework 2

Im working on Zend Framework 2 especially with Zend Forms. I have declared a Select dropdown box in
Form:
$selectElement = new Element\Select('selectElement');
$selectElement->setAttribute('title', 'Select a Value')
->setAttribute('id', 'id');
$data = array(
array(
//Fetching the values from database
),
);
$selectElement->setAttribute('multiple', 'multiple')
->setValueOptions($data);
$this->add($selectElement);
InputFilter:
$inputFilter->add($factory->createInput(array(
'name' => 'selectElement',
'required' => false,
'filters' => array(
array(
'name' => 'Int'
),
),
)));
I have used Zend Debug to get the values which are in the selectElement dropbox in this fashion:
$dataSelectElements = $this->getRequest()->getPost('selectElement');
\Zend\Debug\Debug::dump($dataSelectElements);
Debug Result:
array(4) {
[0] => string(2) "20"
[1] => string(2) "22"
[2] => string(2) "23"
[3] => string(2) "75"
}
Basically Im getting the id's from the selectElement form to store it in the database. Right now Im getting a notice and zend form error:
Notice Error:
Notice: Array to string conversion in ..\zendframework\zendframework\library\Zend\Filter\Int.php on line 29
And a form invalid error:
array(1) {
[0] => array(1) {
["selectElement "] => array(1) {
["explodeInvalid"] => string(35) "Invalid type given. String expected"
}
}
}
Is there a solution to over come this problem. Any help would be appreciated.
The Int filter will attempt to make an Integer out of your array of data, which is not going to work.
Previously I've used the Callback filter, which can be used to loop through the data and check if each value is an Int.
For example:
'filters' => array(
array(
'name' => 'Callback',
'options' => array(
'callback' => function($values) {
return array_filter($values, function($value) {
return ((int)$value == $value);
});
}
)
),
),
I did bit differently, something like this
form
class Companyform extends Form
{
public function __construct()
{
// we want to ignore the name passed
parent::__construct('company');
$this->setAttribute ('method', 'post');
$this->setAttribute ('class', 'form-horizontal');
$this->add ( array (
'name' => 'parentID',
'type' => 'Zend\Form\Element\Select',
'attributes' => array(
'id' => 'parentID',
'type' => 'select',
'placeholder' => "Parent Company",
),
'options' => array(
'label' => 'Parent Company'
)
));
$this->add(array(
'name' => 'btnsubmit',
'attributes' => array(
'id' => 'btnsubmit',
'type' => 'submit',
'value' => 'Add',
'class' => 'btn btn-primary'
),
));
}
}
controller
public function addAction()
{
$request = $this->getRequest();
$companyList = $this->_getCompanyList();
$form = new Companyform();
$form->get('parentID')->setAttribute('options',$companyList);
if ($request->isPost())
{
$company = new Company();
$form->setInputFilter($company->getInputFilter());
$form->setData($request->getPost());
if ($form->isvalid())
{
}
}
}
public function _getCompanyList()
{
$companies = $this->Em()->getEntityManager()->getRepository('XXXX\Entity\Company')->findBy(array('isDeleted'=>'0'));
$companyIDList = array();
$companyIDList[0] = "No Parent";
foreach ($companies as $company)
{
$companyIDList[$company->id] = $company->companyName;
}
return $companyIDList;
}
Entity class
protected $inputFilter;
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'companyName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 255,
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
You may need to add following library in entity
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
In ZendFramework 2, when you creating a (add) element from your Form file, Check the attribute: inarrayvalidator is true.
$this->add(array(
'name' => 'select_name',
'type' => 'select',
'id' => 'select_name',
'options' => array(
'label' => 'Select Name',
),
'attributes' => array(
'id' => 'select_id',
'inarrayvalidator' => true,
),
));
I hope, this works...