Somehow, I have to create admin pages of my module. And this is how I am creating tabs
private function createTab()
{
$data = array(
'id_tab' => '',
'id_parent' => 0,
'class_name' => 'AdminSomeMenu',
'module' => $this->name,
'position' => 1, 'active' => 1
);
$res = Db::getInstance()->insert('tab', $data);
$id_tab = Db::getInstance()->Insert_ID();
$lang = (int)Configuration::get('PS_LANG_DEFAULT');
//Define tab multi language data
$data_lang = array(
'id_tab' => $id_tab,
'id_lang' => $lang,
'name' => $this->name
);
// Now insert the tab lang data
$res &= Db::getInstance()->insert('tab_lang', $data_lang);
$arrayTabs = array('TAB1','TAB2','TAB3');
foreach ($arrayTabs as $requiredTabs)
{
$tab = new Tab();
// Need a foreach for the language
$tab->name[$lang] = $this->l($requiredTabs);
$tab->class_name = 'Admin'.$requiredTabs;
$tab->id_parent = $id_tab;
$tab->module = $this->name;
$tab->add();
}
return true;
}
I hope I am going fine.
Once the tabs are created am trying linking with the following code.
<?php
class AdminMenuController extends ModuleAdminController
{
public function __construct()
{
$module = "mymodulename"
Tools::redirectAdmin('index.php?controller=AdminModules&configure='.$module.'&token='.Tools::getAdminTokenLite('AdminModules'));
}
}
This way the controller not found was gone. But I can create only the configure page through such link.
How should I go to achieve personalized page for each tabs.
Ah ! That was a missing parent::__construct(); in controllers causing the problem for not letting tabs behave the way they should.
<?php
class AdminTAB1Controller extends ModuleAdminController
{
public function __construct()
{
parent::__construct();
/* Tools::redirectAdmin('index.php?controller=AdminModules&configure='.$module.'&token='.Tools::getAdminTokenLite('AdminModules')); */
echo "Support page";
/* or further function can be called to load tpl files from views/templates/admin/ */
}
}
Now I have different pages for my tabs in both PS 1.6 and 1.7 !
Related
Firstly, I tried all the questions & answers related to this topic. Additionally and I tried related questions and try to solve it but no success. So please read my question thoroughly.
1) i want to create a custom controller on custom module in prestashop without tab.and get browser url Link.
2) how to create a controller url link with tocken on twig file.
i have successfully created module and installed in my PS.
i create a controller [Checkstatus.php]
file path module/mymodule/contollers/admin/Checkstatus.php
<?php
class CheckstatusController extends ModuleAdminController {
public function __construct()
{
$this->page_name = 'checkstatus'; // page_name and body id
echo "sfg";
parent::__construct();
}
public function init()
{
parenrt::init();
}
public function demoAction()
{
return $this->render('#Modules/your-module/templates/admin/demo.html.twig');
}
}
my Custom module
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class MyModule extends PaymentModule
{
public function __construct()
{
$this->name = 'MyCustomModule';
$this->tab = 'payments XYZ';
$this->version = '1.0';
$this->author = 'XYZ Technologies';
$this->bootstrap = true;
$this->displayName = 'XYZ';
$this->description = 'XYZ.';
$this->confirmUninstall = 'Are you sure you want to uninstall XYZ module?';
$this->ps_versions_compliancy = array('min' => '1.7.0', 'max' => _PS_VERSION_);
$this->allow_countries = array('CH', 'LI', 'AT', 'DE');
$this->allow_currencies = array('CHF', 'EUR');
parent::__construct();
}
/**
* Install this module and register the following Hooks:
*
* #return bool
*/
public function install()
{
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'MyCustomModule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`customer_id` int(255) NOT NULL,
`MyCustomModule` int(255) DEFAULT NULL,
`lastcheck_date` date,
`add_date` date,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
');
return parent::install() && $this->registerHook('Statusbtnoncustomerview');
}
/**
* Uninstall this module and remove it from all hooks
*
* #return bool
*/
public function uninstall()
{
return parent::uninstall() && $this->uninstallDb() && $this->unregisterHook('Statusbtnoncustomerview');
}
public function uninstallDb()
{
return Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'MyCustomModule');
}
public function hookStatusbtnoncustomerview()
{
/**
* Verify if this module is enabled
*/
if (!$this->active) {
return;
}
return $this->fetch('module:MyCustomModule/views/templates/hook/personal_information.html.twig');
}
/**
* Returns a string containing the HTML necessary to
* generate a configuration screen on the admin
*
* #return string
*/
public function getContent()
{
$output = null;
if (Tools::isSubmit('submit'.$this->name)) {
// get configuration fields value
$MyCustomModule_Account_Data = strval(Tools::getValue('MyCustomModule_Account_Data'));
$credit_Checkbox = strval(Tools::getValue('credit_Checkbox_1'));
$interval_Month = strval(Tools::getValue('Interval_Month'));
if (
!$MyCustomModule_Account_Data ||
empty($MyCustomModule_Account_Data) ||
!Validate::isGenericName($MyCustomModule_Account_Data)
) {
$output .= $this->displayError($this->l('Please Enter MyCustomModule Account Data.'));
} else{
// Update configuration fields value
Configuration::updateValue('MyCustomModule_Account_Data', $MyCustomModule_Account_Data);
Configuration::updateValue('credit_Checkbox_1', $credit_Checkbox);
Configuration::updateValue('Interval_Month', $interval_Month);
// Display message after successfully submit value
$output .= $this->displayConfirmation($this->l('Settings updated'));
}
}
return $output.$this->displayForm();
}
/**
* Display a form
*
* #param array $params
* #return form html using helper form
*/
public function displayForm()
{
// Get default language
$defaultLang = (int)Configuration::get('PS_LANG_DEFAULT');
$credit_Checkbox = [
[
'id'=>1,
'name'=>'',
'val' => 1
]
];
// Init Fields form array
$fieldsForm[0]['form'] = [
'legend' => [
'title' => $this->l('Configuration'),
],
'input' => [
[
'type' => 'text',
'label' => $this->l('MyCustomModule Account Data'),
'name' => 'MyCustomModule_Account_Data',
'required' => true
],
[
'type'=>'checkbox',
'label'=> $this->l('credit'),
'name'=>'credit_Checkbox',
'values'=>[
'query'=>$credit_Checkbox,
'id'=>'id',
'name'=>'name'
]
],
[
'type' => 'html',
'html_content' => '<input type="number" min="0" step="1" value="'.Configuration::get('Interval_Month').'" name="Interval_Month">',
'label' => $this->l('interval Month'),
'name' => 'Interval_Month',
'size' => 20
],
],
'submit' => [
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right'
]
];
$helper = new HelperForm();
// Module, token and currentIndex
$helper->module = $this;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
// Language
$helper->default_form_language = $defaultLang;
$helper->allow_employee_form_lang = $defaultLang;
// Title and toolbar
$helper->title = $this->displayName;
$helper->show_toolbar = true; // false -> remove toolbar
$helper->toolbar_scroll = true; // yes - > Toolbar is always visible on the top of the screen.
$helper->submit_action = 'submit'.$this->name;
$helper->toolbar_btn = [
'save' => [
'desc' => $this->l('Save'),
'href' => AdminController::$currentIndex.'&configure='.$this->name.'&save'.$this->name.
'&token='.Tools::getAdminTokenLite('AdminModules'),
],
'back' => [
'href' => AdminController::$currentIndex.'&token='.Tools::getAdminTokenLite('AdminModules'),
'desc' => $this->l('Back to list')
]
];
// Load current value
$helper->fields_value['MyCustomModule_Account_Data'] = Configuration::get('MyCustomModule_Account_Data');
$helper->fields_value['credit_Checkbox_1'] = Configuration::get('credit_Checkbox_1');
$helper->fields_value['Interval_Month'] = Configuration::get('Interval_Month');
return $helper->generateForm($fieldsForm);
}
}
i trying this url : http://localhost/prestashop/admin482vzxnel/index.php?module=mymodule&controller=checkstatus
geting error :
Page not found
The controller checkstatus is missing or invalid.
Thanks
To include a Class in a module you can use php require. Once included in module main file you can create an instance of you class where you want in your module.
To assign variable that you can use on template there is $this->context->smarty->assig() function.
The code Below is just an example of how include and use a Class in a custom module Controller.
Even the edit in the hookStatusbtnoncustomerview() is an example of how retrieve the module link and the link on his method, so take the code below such as it is, only an example
require_once (dirname(__FILE__)).'contollers/admin/Checkstatus.php';
class MyModule extends PaymentModule
{
public function __construct()
{
$this->name = 'MyCustomModule';
$this->tab = 'payments XYZ';
$this->version = '1.0';
$this->author = 'XYZ Technologies';
$this->bootstrap = true;
$this->displayName = 'XYZ';
$this->description = 'XYZ.';
$this->confirmUninstall = 'Are you sure you want to uninstall XYZ module?';
$this->ps_versions_compliancy = array('min' => '1.7.0', 'max' => _PS_VERSION_);
$this->allow_countries = array('CH', 'LI', 'AT', 'DE');
$this->allow_currencies = array('CHF', 'EUR');
$this->checkController = null;
parent::__construct();
}
private function _useCheckstatus(){
$this->checkController = new CheckstatusController();
}
public function MyMethod (){
$this->_useCheckstatus();
$this->checkController->demoAction();
}
public function hookStatusbtnoncustomerview()
{
/**
* Verify if this module is enabled
*/
if (!$this->active) {
return;
}
$this->context->smarty->assign(
array(
'my_module_name' => Configuration::get('MyCustomModule'),
'my_module_link' => $this->context->link->getModuleLink('MyCustomModule', 'mymethod'),
'token' => Tools::getToken(false)
)
);
return $this->fetch('module:MyCustomModule/views/templates/hook/personal_information.html.twig');
}
.........
it's not easy to investigate how prestashop works, so my tip is: look at the code from other modules, and take example from them.
Instead if you need to override a Core Prestashop Controller in your module you have to put the override file in /mymodule/override/controllers/admin/ModuleAdminController.php. installing/resetting the module will put this file within root/override/controllers/admin/ folder and the override becomes active. just remember to clear PS cache in "advanced settings->performance"
I am working in CakePHP 2.6.1 and I have a project in which I have to create an API. So I have created a function and its working fine when I am logged in but when I try to access without login, it redirects to the login page.
My function looks like :
class AndroidController extends AppController {
public function admin_survey_question()
{
$this->loadModel('Question');
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$this->Question->unbindModel(
array('hasMany' => array('Result'))
);
$info = $this->Question->find('all', array(
'fields' => array('Question.id,Question.question, Question.options'),
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
Here,In core.php there is a Routing.prefixes used as admin.
Configure::write('Routing.prefixes', array('admin','services'));
When I call this api
http://navyon.com/dev/mt/admin/android/survey_question?survey_id=2
then it redirects to the login page.
I need access api without login.So how can I resolve this problem?
To make accessible this method admin_survey_question without authentication, you need to allow it in beforeFilter
class AndroidController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('admin_survey_question');
}
public function admin_survey_question()
{
$this->loadModel('Question');
Configure::write('debug', '2');
$survey_id = $_REQUEST['survey_id'];
$this->layout = "";
//$condition = "Question.survey_id = '".$survey_id."'";
$this->Question->unbindModel(
array('hasMany' => array('Result'))
);
$info = $this->Question->find('all', array(
'fields' => array('Question.id,Question.question, Question.options'),
'conditions' => array(
"Question.survey_id" => $survey_id /*dont use array() */
)
));
echo json_encode($info);
exit;
}
}
See Docs
I am looking for a way to access and change the DATABASE_CONFIG variables, based on user input. Using CakePHP I created a custom datasource, based on the one provided in the docs, to access an external API. The API returns a JSON string containing the 12 most recent objects. I need to be able to change the page number in the API request to get the next 12 results, as well as accept a free text query entered by the user.
app/Config/Database.php
class DATABASE_CONFIG {
public $behance = array(
'datasource' => 'BehanceDatasource',
'api_key' => '123456789',
'page' => '1',
'text_query' => 'foo'
);
}
app/Model/Datasource/BehanceDataSource.php
App::uses('HttpSocket', 'Network/Http');
class BehanceDatasource extends DataSource {
public $description = 'Beehance datasource';
public $config = array(
'api_key' => '',
'page' => '',
'text_query' => ''
);
public function __construct($config) {
parent::__construct($config);
$this->Http = new HttpSocket();
}
public function listSources($data = null) {
return null;
}
public function describe($model) {
return $this->_schema;
}
public function calculate(Model $model, $func, $params = array()) {
return 'COUNT';
}
public function read(Model $model, $queryData = array(), $recursive = null) {
if ($queryData['fields'] === 'COUNT') {
return array(array(array('count' => 1)));
}
$queryData['conditions']['api_key'] = $this->config['api_key'];
$queryData['conditions']['page'] = $this->config['page'];
$queryData['conditions']['page'] = $this->config['text_query'];
$json = $this->Http->get('http://www.behance.net/v2/projects', $queryData['conditions']);
$res = json_decode($json, true);
if (is_null($res)) {
$error = json_last_error();
throw new CakeException($error);
}
return array($model->alias => $res);
}
}
Is there anyway to access and change the $behance array, or is there another way to go about accessing an external API with cakePHP that I am totally missing?
I made a product site at the end of last year using DataObjects as Pages - Part 2 Silverstripe, the site is live now, and I need to implement a site search function for the site.
I implemented a search function like Tutorial 4 - Site Search however this doesn't work with the product search since each product is a dataobject rather than a page.
Can anyone shed some light on how I can make the site search work for the products?
I know there is a tutorial 3 DataObject as Pages I tried it but it messed up all my existing products as well as some additional existing functions for the products. Someone suggested http://silverstripe.org/all-other-modules/show/6641?start=24 but unsuccessful so far.
Any help on how to do the search function for the products is appreciated.
Thanks.
Here is my Product.php code
<?php
class Product extends DataObject
{
static $db = array(
'Title' => 'Varchar(255)',
'Description' => 'HTMLText',
'Price' => 'Decimal(6,2)',
'URLSegment' => 'Varchar(255)'
);
//Set our defaults
static $defaults = array(
'Title' => 'New Product',
'URLSegment' => 'new-product'
);
static $has_one = array(
'Image' => 'Image',
'PDF' => 'File'
);
//Relate to the category pages
static $belongs_many_many = array(
'Categories' => 'CategoryPage'
);
//Fields to show in ModelAdmin table
static $summary_fields = array(
'Title' => 'Title',
'URLSegment' => 'URLSegment',
'Price' => 'Price (£)'
);
//Add an SQL index for the URLSegment
static $indexes = array(
"URLSegment" => true
);
//Fields to search in ModelAdmin
static $searchable_fields = array (
'Title',
'URLSegment',
'Description',
'Categories.ID' => array(
'title' => 'Category'
)
);
function getCMSFields()
{
$fields = parent::getCMSFields();
//Main Tab
$fields->addFieldToTab("Root.Main", new TextField('Title', 'Title'));
$fields->addFieldToTab("Root.Main", new TextField('URLSegment', 'URL Segment'));
$fields->addFieldToTab("Root.Main", new NumericField('Price'));
$fields->addFieldToTab("Root.Main", new HTMLEditorField('Description'));
//added below for the ordering
$Categories = DataObject::get('CategoryPage');
$map = $Categories->map('ID', 'CheckboxSummary');
asort($map);
$fields->addFieldToTab("Root.Categories", new CheckboxsetField('Categories', 'Categories', $map));
//Images
$fields->addFieldToTab("Root.Images", new ImageField('Image', 'Image', Null, Null, Null, 'Uploads/category_banners'));
$fields->addFieldToTab("Root.Files", new FileIFrameField('PDF'));
return $fields;
}
//Set URLSegment to be unique on write
function onBeforeWrite()
{
// If there is no URLSegment set, generate one from Title
if((!$this->URLSegment || $this->URLSegment == 'new-product') && $this->Title != 'New Product')
{
$this->URLSegment = SiteTree::generateURLSegment($this->Title);
}
else if($this->isChanged('URLSegment'))
{
// Make sure the URLSegment is valid for use in a URL
$segment = preg_replace('/[^A-Za-z0-9]+/','-',$this->URLSegment);
$segment = preg_replace('/-+/','-',$segment);
// If after sanitising there is no URLSegment, give it a reasonable default
if(!$segment) {
$segment = "product-$this->ID";
}
$this->URLSegment = $segment;
}
// Ensure that this object has a non-conflicting URLSegment value.
$count = 2;
while($this->LookForExistingURLSegment($this->URLSegment))
{
$this->URLSegment = preg_replace('/-[0-9]+$/', null, $this->URLSegment) . '-' . $count;
$count++;
}
parent::onBeforeWrite();
}
//Test whether the URLSegment exists already on another Product
function LookForExistingURLSegment($URLSegment)
{
return (DataObject::get_one('Product', "URLSegment = '" . $URLSegment ."' AND ID != " . $this->ID));
}
//Generate the link for this product
function Link()
{
//if we are on a category page return that
if(Director::CurrentPage()->ClassName == 'CategoryPage')
{
$Category = Director::CurrentPage();
}
//Otherwise just grab the first category this product is in
else
{
$Category = $this->Categories()->First();
}
//Check we have a category then return the link
if($Category)
{
return $Category->absoluteLink() . 'show/' . $this->URLSegment;
}
}
//Return the Title as a menu title
public function MenuTitle()
{
return $this->Title;
}
function canView() {
return true;
}
public function LinkingMode()
{
//Check that we have a controller to work with and that it is a StaffPage
if(Controller::CurrentPage() && Controller::CurrentPage()->ClassName == 'CategoryPage')
{
//check that the action is 'show' and that we have a StaffMember to work with
if(Controller::CurrentPage()->getAction() == 'show' && $Product = Controller::CurrentPage()->getCurrentProduct())
{
//If the current StaffMember is the same as this return 'current' class
return ($Product->ID == $this->ID) ? 'current' : 'link';
}
}
}
}
and here is my CategoryPage.php
<?php
class CategoryPage extends Page
{
static $has_one = array(
'CategoryBanner' => 'Image',
'Photo' => 'Image'
);
static $many_many = array(
'Products' => 'Product'
);
static $allowed_children = array(
'none' => 'none'
);
function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab("Root.Content.Images", new ImageField('Photo'));
//Banner Images
$fields->addFieldToTab("Root.Content.Banner", new ImageField('CategoryBanner', 'Banner', Null, Null, Null, 'Uploads/category_banners'));
return $fields;
}
//important for sidebar showing, this is sitetree stuff - relationship between categories and products 20012012
public function onBeforeDelete()
{
$CurrentVal = $this->get_enforce_strict_hierarchy();
$this->set_enforce_strict_hierarchy(false);
parent::onBeforeDelete();
$this->set_enforce_strict_hierarchy($CurrentVal);
}
public function Children(){
return $this->Products();
}
//added this on 03022011 for the parent page to show on Categories in admin
function CheckboxSummary(){
return $this->Parent()->Title . ' - ' . $this->Title;
}
}
class CategoryPage_Controller extends Page_Controller
{
static $allowed_actions = array(
'show'
);
public function init()
{
parent::init();
Requirements::css('themes/tutorial/css/products.css');
//added this to make the gallery js work 10012012
Requirements::set_write_js_to_body(false);
Requirements::javascript("mysite/javascript/jquery-1.4.2.min.js"); Requirements::javascript("mysite/javascript/jquery.cycle.lite.min.js");
Requirements::javascript("mysite/javascript/toggle_menu.js");
}
//Return the list of products for this category
public function getProductsList()
{
return $this->Products(Null, 'Price ASC');
}
//Get's the current product from the URL, if any
public function getCurrentProduct()
{
$Params = $this->getURLParams();
$URLSegment = Convert::raw2sql($Params['ID']);
if($URLSegment && $Product = DataObject::get_one('Product', "URLSegment = '" . $URLSegment . "'"))
{
return $Product;
}
}
//Shows the Product detail page
function show()
{
//Get the Product
if($Product = $this->getCurrentProduct())
{
$Data = array(
'Product' => $Product,
'MetaTitle' => $Product->Title
);
//return our $Data array to use, rendering with the ProductPage.ss template
return $this->customise($Data)->renderWith(array('ProductPage', 'Page'));
}
else //Product not found
{
return $this->httpError(404, 'Sorry that product could not be found');
}
}
//Generate out custom breadcrumbs
public function Breadcrumbs() {
//Get the default breadcrumbs
$Breadcrumbs = parent::Breadcrumbs();
if($Product = $this->getCurrentProduct())
{
//Explode them into their individual parts
$Parts = explode(SiteTree::$breadcrumbs_delimiter, $Breadcrumbs);
//Count the parts
$NumOfParts = count($Parts);
//Change the last item to a link instead of just text
$Parts[$NumOfParts-1] = ('' . $Parts[$NumOfParts-1] . '');
//Add our extra piece on the end
$Parts[$NumOfParts] = $Product->Title;
//Return the imploded array
$Breadcrumbs = implode(SiteTree::$breadcrumbs_delimiter, $Parts);
}
return $Breadcrumbs;
}
}
If you are doing any serious search stuff, the built-in search functionality (based on MySQL MyISAM) is not ideal. I'd suggest to use Solr or Sphinx, integrated into SilverStripe with https://github.com/silverstripe/silverstripe-sphinx or https://github.com/nyeholt/silverstripe-solr (I'd start off with the first one). This will also index DAOs.
For my company I'm working on a custom translation module for Magento.
On the form for translating an existing string, I would like to change the behaviour of the "Save And Continue"-button to a "Save And Next"-button.
With which I mean that instead of still editing thesame string, you get the next one in line.
I have tried to edit the link that is called for the Save And Continue:
Original:
[save-link] + "/back/edit/"
To:
[save-link] + "/back/edit/id/[id]/"
But to no avail. I'm hoping someone can set me in the right direction.
The unchanged code of the edit-form:
<?php
class Phpro_Advancedtranslate_Block_Adminhtml_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
{
public function __construct()
{
parent::__construct();
$this->_objectId = 'id';
$this->_blockGroup = 'advancedtranslate';
$this->_controller = 'adminhtml';
$this->_updateButton('save', 'label', Mage::helper('advancedtranslate')->__('Save Item'));
$this->_updateButton('delete', 'label', Mage::helper('advancedtranslate')->__('Delete Item'));
$this->_addButton('saveandcontinue', array(
'label' => Mage::helper('adminhtml')->__('Save And Next'),
'onclick' => 'saveAndContinueEdit()',
'class' => 'save',
), -100);
$currentId = Mage::getSIngleton('adminhtml/session')->getTranslateId();
$strings = Mage::getModel("advancedtranslate/advancedtranslate")->getCollection();
foreach ($strings as $string) {
$id = $string->getId();
if ($id != $currentId && $id < $nextId) {
$nextId = $id;
}
}
$this->_formScripts[] = "
function toggleEditor() {
if (tinyMCE.getInstanceById('advancedtranslate_content') == null) {
tinyMCE.execCommand('mceAddControl', false, 'advancedtranslate_content');
} else {
tinyMCE.execCommand('mceRemoveControl', false, 'advancedtranslate_content');
}
}
function saveAndContinueEdit(){
editForm.submit($('edit_form').action+'back/edit/');
}
";
}
public function getHeaderText()
{
return Mage::helper('advancedtranslate')->__("Edit Item '%s'", 'test');
}
}
This functionality has to happen in the controller that handles the Post. Set the _redirect to redirect to the next item.