Jump to content
lmarcelocc

[Ps 1.6] - Module development - Controllers and views

Recommended Posts

Hi all,

 

i'm trying to create a prestashop module, i'm a little used to MVC but this one is getting me crazy :)

 

I have this controller in my:

/prestashop16/modules/myModuleName/controllers

include_once dirname(__FILE__).'/../../classes/Interaction.php';

class AdminJobstatusController extends ModuleAdminController
{
    
    public function __construct()
    {
        $this->bootstrap = true;
        $this->display = 'list';
        $this->meta_title = $this->l('Job Repair Status');
        parent::__construct();
        if (!$this->module->active)
            Tools::redirectAdmin($this->context->link->getAdminLink('AdminHome'));
        
        parent::__construct();
    }

    
    public function setMedia()
    {
       
        // Add default css
        parent::setMedia();
        
        return;
    }
    
    
    public function initToolBarTitle()
    {
        $this->toolbar_title[] = $this->l('Job Repair Status');
    }

    
    public function initPageHeaderToolbar()
    {
        parent::initPageHeaderToolbar();
        unset($this->page_header_toolbar_btn['back']);
    }
    
    
    public function postProcess()
    {
        
    }
    
    
   public function renderList(){

        $this->toolbar_title[] = $this->l('All Jobs');
        
        $fields_list = array(
            'orderId' => array(
                'title' => $this->l('Order'),
                'width' => 140,
                'type' => 'text'
            ),
            'status' => array(
                'title' => $this->l('Status'),
                'width' => 140,
                'type' => 'int'
            ),
            'estimatedTime' => array(
                'title' => $this->l('Estimated Repair Time'),
                'width' => 140,
                'type' => 'text'
            ),
            'pickuptime' => array(
                'title' => $this->l('Pickup Datetime'),
                'width' => 140,
                'type' => 'text'
            ),
            'updated' => array(
                'title' => $this->l('Last update'),
                'width' => 140,
                'type' => 'text'
            ),
        );
        
        $helper = new HelperList();
        
        $helper->shopLinkType = '';

        $helper->simple_header = false;
        
        // Actions to be displayed in the "Actions" column
        $helper->actions = array('edit', 'delete', 'view');

        $helper->identifier = 'id';
        $helper->show_toolbar = true;
        $helper->title = $this->l('All jobs');
        $helper->specificConfirmDelete = true;
        
  
        $helper->token = $this->context->controller->token;

        $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->module->name;
        
        // Call webservice
        $info = Interaction::getWebServiceInfo().$this->_displayInfo();

        return $info.$helper->generateList(Interaction::getAllJobs(), $fields_list);
    }
    
    
    
    
  
    
    public function renderView()
    {
        
        $jobId = Tools::getValue('id');
        
        if (!Validate::isInt($jobId))
            $this->errors[] = Tools::displayError('Can\'t get job id!.');


        if($jobId)         
            $this->base_tpl_view = 'edit_job.tpl';

        
//            $this->content = $this->createTemplate(dirname(__MODULE_DIR__) . '/../../views/templates/admin/edit_job.tpl')->fetch();
        
//        $tpl = $this->context->smarty->createTemplate(dirname(__FILE__) . '/../../views/templates/admin/edit_job.tpl');

//        return $tpl->fetch();
                
        return parent::renderView();
    }
    
}

This controller have this method:

renderList() wich create the list with no problems with the correct actions, like mentioned in:

$helper->actions = array('edit', 'delete', 'view');

 

 

 

Now what I want to achieve is:

1 - I know that if I click on edit will send some url params like 'id'. How can I do something with it in my controller? In cakePHP we do something like editAction(){} 

 

2 - After do my stuff with user interaction, how can I set a template to it? With $this->base_tpl_view?

I have my templates files in 

/prestashop16/modules/myModuleName/views/templates/admin/myModuleName/helpers/view

 

 

Thanks in advance for your time.

 

Best regards,

Marcelo

Edited by lmarcelocc (see edit history)

Share this post


Link to post
Share on other sites

For action = edit, you need to define renderForm() method on your controller

for example :

public function renderForm()
{
    // make sure object is loaded
    if (!($obj = $this->loadObject(true)))
        return;

    $this->fields_form = array(
        // array fields for the form, similiar with array on your renderList()
        // for reference, you can see the available Prestashop AdminController
        // e.g : ...\controllers\admin\AdminCustomersController.php
    );

    // then ... let the parent controller class handle it (update object)
    return parent::renderForm();
}
  • Like 1

Share this post


Link to post
Share on other sites

Thank you gonebdg :)

 

But,  and if I want to upgrade 2 custom tables with parent controller ?

 

And if I add new action 'Add' ho can i handle it?

 

Sorry and thank you for your patience.

 

 

Best regards and wish you a nice weekend.

 

Marcelo

Share this post


Link to post
Share on other sites

Usually i create my Admin module controller and determine the required variables in class constructor, also create custom classes file for the data which will be processed (add/edit/delete) by this controller.
So the data will be treated as an object, because that was the reason why I use PHP OOP and MVC pattern (Prestashop)

 

example :

<?php
/*
** My Admin Module Controller
** Module name : mymodulename (as defined on module file, $this->name)
** With this controller I will be able to Add/Edit/Delete data (object) that i want
** Controller Class name doesn't have to use or same as the module name
** In here the class name is Admin + Name + Controller
** "Name" will be used as directory name where the necessary template helper file placed
** e.g: view.tpl
** ..\modules\mymodulename\views\templates\admin\name\helpers\view\view.tpl
*/

class AdminNameController extends ModuleAdminController
{
	public function __construct()
	{
		$this->bootstrap = true;
		$this->module = 'mymodulename'; // valid module name
		$this->table = 'db_table_name'; // DB table name where your object data stored
		$this->className = 'MyObjectClassName'; // The class name of my object
		$this->lang = false;
		$this->explicitSelect = true;
		$this->allow_export = true;
		$this->delete = true;
		$this->context = Context::getContext();
		$this->orderBy = 'id_object'; // DB column field which hold my object ID
		$this->_orderWay = 'DESC';
		$this->fields_list = $this->fieldList();
		$this->shopLinkType = 'shop';
		$this->actions = array('view', 'edit', 'delete');
		$this->bulk_actions = array(
			'delete' => array(
				'text' => $this->l('Delete selected'),
				'icon' => 'icon-trash',
				'confirm' => $this->l('Delete selected object?')
			)
		);

		parent::__construct();
	}

        public function fieldList()
        {
            // determine object fields in here. it will be processed by renderList() method
            // Note: fieldList can also determined directly on class constructor

            return $fields_list;
        }

        /* Function used to render the list to display for this controller */
        public function renderList()
        {
            // No need to use/override this method if not necessary

            return $list;
        }

        /* Function used to render the view page */
        public function renderView()
        {
            // form to add/edit my object are dermined here

            return parent::renderForm();
        }

        /* Function used to render the form for this controller */
        public function renderForm()
        {
            // form to add/edit my object are dermined here

            return parent::renderForm();
        }
}

If everytings is ok, and i've created the renderForm() method for my controller, the "Add new" action menu will automatically available. On the top right of the data list table (rendered by my controller) there will be an action menu icon [+] which created automatically by Prestashop system.

 

The parent classes AdminController.php will handle the process with processAdd() method

 

If i click this icon menu, i can create new object value without having to bother writing my php code on my controller.

Unless there is customizations needed or special circumstances which require me to extend processAdd() method.

 

I suggest you to take a look deep inside Prestashop classes controller files :
AdminModuleController.php and AdminController.php
and then start to create your Admin Module Controller file based on the available Prestashop Admin Controller.

  • Like 2

Share this post


Link to post
Share on other sites

Thank you very much gonebdg :)

 

Will follow your tips.

 

Merry christmas :D

 

 

Thanks,

Marcelo

Share this post


Link to post
Share on other sites

Hello gonebdg,

 

i'm follow your advises and now i'm able to add  / update my DB with an object, but now i have some doubts with whats the best way to do what i want, now I have something like in my controller:

include_once dirname(__FILE__).'/../../classes/Save.php';

class AdminJobstatusController extends ModuleAdminController
{
    public function __construct()
    {
        $this->bootstrap = true;
        $this->module = 'jobStatus'; // valid module name
        $this->table = 'jobStatus'; // DB table name where your object data stored
        $this->className = 'jobStatusObj'; // The class name of my object
        $this->lang = false;
        $this->explicitSelect = true;
        $this->allow_export = true;
        $this->delete = true;
        $this->context = Context::getContext();
        $this->orderBy = 'id_jobStatus'; // DB column field which hold my object ID
        $this->_orderWay = 'DESC';
        $this->fields_list = $this->fieldList();
        $this->shopLinkType = '';
        
        $this->shopLinkType = 'shop';
        $this->actions = array('view', 'edit', 'delete');

        $this->bulk_actions = array(
            'delete' => array(
            'text' => $this->l('Delete selected'),
            'icon' => 'icon-trash',
            'confirm' => $this->l('Delete selected object?')
            )
        );

        parent::__construct();
    }



public function renderForm()
    {

        // form to add/edit my object are dermined here
        // make sure object is loaded
        if (!($obj = $this->loadObject(true)))
            return;

        // Get order states available on store
        $orderStates = OrderState::getOrderStates((int)$this->context->language->id);
        
        foreach ($orderStates as $status)
            $this->statuses_array[] = array('id_order_state' => $status['id_order_state'],
                                            'status' => $status['name']);
         
        // array fields for the form, similiar with array on your renderList()
        // for reference, you can see the available Prestashop AdminController
        // e.g : ...\controllers\admin\AdminCustomersController.php
        $this->fields_form = array(
            'legend' => array(
                    'title' => (Tools::getValue('id_jobStatus')) ? sprintf($this->l('Add information to job: #%s'), Interaction::getOrderIdByJobId(Tools::getValue('id_jobStatus'))) : $this->l('Add new job'),
                    'icon' => 'icon-angle-double-right'
            ),
            'input' => array(
                array(  
                    'type' => 'select',
                    'label' => $this->l('Select status'),
                    'name' => 'status',
                    'required' => true,
                    'options' => array(
                        'query' => $this->statuses_array,
                        'id' => 'id_order_state',
                        'name' => 'status'
                    ),
                    'col' => '4',
                    'desc' => $this->l('To create new status go to Orders -> Statuses.'),
                    'hint' => $this->l('To create new status go to Orders -> Statuses.')
                ),
                array(
                    'type' => 'text',
                    'label' => $this->l('Message'),
                    'name' => 'message',
                    'required' => false,
                    'col' => '6',
                    'suffix' => '<i class="icon-envelope-o"></i>',
                    'desc' => $this->l('Message to save/send to customer.'),
                    'hint' => $this->l('Message to save/send to customer.')
                ),
                array(
                    'type' => 'text',
                    'validation' => 'isInt',
                    'label' => $this->l('Time estimated to finish the job.'),
                    'name' => 'estimatedTime',
                    'required' => false,
                    'col' => '1',
                    'suffix' => '<i class="icon-clock-o"></i>',
                    'desc' => $this->l('(days)'),
                    'hint' => $this->l('(days)')
                ),
                array(
                    'type' => 'datetime',
                    'label' => $this->l('Pickup time'),
                    'name' => 'pickupTime',
                    'required' => false,
                    'col' => '6',
                    'desc' => $this->l('When customer can pickup/receive his product.'),
                    'hint' => $this->l('When customer can pickup/receive his product.')
                ),
                array(
                    'type' => 'switch',
                    'label' => $this->l('Advise customer by email?'),
                    'name' => 'emailSent',
                    'is_bool' => true,
                    'values' => array(
                        array(
                            'id' => 'active_on',
                            'value' => 1,
                            'label' => $this->l('Yes')
                        ),
                        array(
                            'id' => 'active_off',
                            'value' => 0,
                            'label' => $this->l('No')
                        )
                    ),
                    'desc' => $this->l('If you would like to advise customer by email about status update.')
                ), 
            ),
            'submit' => array(
                'title' => $this->l( 'Save' ),
                'class' => 'btn btn-default pull-right',
                'name' => 'saveAction',
            )    
        );
               
        
              
        // then ... let the parent controller class handle it (update object)
        return parent::renderForm();
        
    }
}

and my Model:

class jobStatusObj extends ObjectModel {
    
    /**
     * @see ObjectModel::$definition
    */
    public static $definition = array(
            'table' => 'jobStatus',
            'primary' => 'id_jobStatus',
            'fields' => array(
//                    'id_jobStatus'  =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => true),
                    'orderId'       =>  array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'size' => 25, 'required' => false),
                    'status'        =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => true),
                    'estimatedTime' =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => false),
                    'pickupTime'    =>	array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
//                    'idJobStatus'   =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => true),
//                    'emailSent'     =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => true),
//                    'message'       =>  array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'size' => 250, 'required' => true),
            ),
    );
}

My problem:

 

I have two db tables:

Table name: jobStatus

Screen_Shot_12_23_14_at_04_32_PM_001.png

 

Table name: jobStatusHistory

Screen_Shot_12_23_14_at_04_32_PM.png

 

Note: My form to add / edit have all the fields necessary to fill all this two tables.

 

1º I want to use the same object to save in both tables, how can I achieve that? Probably in my model in $definition variable.

 

2º For 1º goes fine I think I should make difeference in my renderForm() method, because when add new one i will need to set orderId (this is supposed to be an order Id create in BO), or should I make orderId my primary key and set it in my model?

 

 

Hope you can give me another good tip or maybe someone else :)

 

Best regards,

Marcelo 

Edited by lmarcelocc (see edit history)

Share this post


Link to post
Share on other sites

Sure you can.

You can create object methods to achieve that
But the variables which will be saved in separate DB table can not be added within the object property $definition.
Object property $definition is to define variables belong to the specified DB table or to define variables related to multilingual, multishop or object associations.

 

I'm not sure if i'm understand your second question.

If you need to set a value for orderId, you just have to add it on your form or you can automatically retrieving the value with the existing object.

  • Like 1

Share this post


Link to post
Share on other sites

Sure you can.

You can create object methods to achieve that

But the variables which will be saved in separate DB table can not be added within the object property $definition.

Object property $definition is to define variables belong to the specified DB table or to define variables related to multilingual, multishop or object associations.

 

I'm not sure if i'm understand your second question.

If you need to set a value for orderId, you just have to add it on your form or you can automatically retrieving the value with the existing object.

Hello,

 

forget my second question :)

 

I get it, now I understand clear $definition property.

 

So, I have to use/create some methods in my controller to get the user inputed values, validate them, and then, maybe for better structure, create some other class with my custom methods and call them to save that info in the other table?

 

Which method should I override to threat data and then save it like mencioned above? processAdd() ?

 

Maybe something like ?

public function processAdd()
{
// Validate user input data
$customer_email = strval(Tools::getValue('email'));
/* ... */

if (Validate::isEmail($customer_email))
     // All fine with all fields
     // Call custom class methods to save in the other table
}

Should be this the right method to achieve what I want? Or perhaps there's some other that will be more correct to use here?

 

Thank you for your patience gonebdg.

 

Best wishes,

Marcelo 

Edited by lmarcelocc (see edit history)

Share this post


Link to post
Share on other sites

Hello,

 

i'm getting there, is now working as expected, thanks gonebdg.

 

Now i'm trying to do another thing and I have looked to helperList and can't find it, in my:

$fields_list = array(
            'id_jobStatus' => array(
                'title' => $this->l('ID'),
                'align' => 'text-center',
                'class' => 'fixed-width-xs'
            ),
            'orderId' => array(
                'title' => $this->l('Order'),
                'width' => 140,
                'type' => 'text'
            ),
            'customerEmail' => array(
                'title' => $this->l('Customer Email'),
                'width' => 140,
                'type' => 'text'
            ),
            'status' => array(
                'title' => $this->l('Status'),
                'width' => 140,
                'type' => 'int'
            )
       );

so, status fields is an int, i'm getting it from OrderState::getOrderStates and saving it in my custom table, I want to show it by status name instead of id. How can I achieve this? 

 

Hope someone can help me.

 

Thanks in advance.

Best regards,

Marcelo

Share this post


Link to post
Share on other sites

I guess you should override parent method renderList()

 

something like this :

/* 
** Override renderList() method to show order state name instead ID
** @see public function renderList() ; /classes/controller/AdminController.php
** In here "status" is a field which hold id_order_state
*/
public function renderList()
{
     if (!($this->fields_list && is_array($this->fields_list)))
         return false;
     $this->getList($this->context->language->id);

     // Start Modification
     $nb_list = count($this->_list);        
     for($i=0;$i <= $nb_list;$i++)
     {
         if (isset($this->_list[$i]['status']) && $status = $this->_list[$i]['status'])
         {
             // instantiate object OrderState
             $order_state = new OrderState((int)$status, (int)$this->context->language->id);
             // Show OrderState name instead ID
             $this->_list[$i]['status'] = $order_state->name;
         }        
     }
     // End Modification

     // instantiate object HelperList
     $helper = new HelperList();
        
     // Empty list is ok
     if (!is_array($this->_list))
     {
         $this->displayWarning($this->l('Bad SQL query', 'Helper').'<br />'.htmlspecialchars($this->_list_error));
         return false;
     }

     $this->setHelperDisplay($helper);
     $helper->tpl_vars = $this->tpl_list_vars;
     $helper->tpl_delete_link_vars = $this->tpl_delete_link_vars;

     // For compatibility reasons, we have to check standard actions in class attributes
     foreach ($this->actions_available as $action)
     {
         if (!in_array($action, $this->actions) && isset($this->$action) && $this->$action)
             $this->actions[] = $action;
     }

     $list = $helper->generateList($this->_list, $this->fields_list);

     return $list;
}

NOTE:

This is just an example and untested, then maybe this example won't working as expected, but i hope this example can help you to figuring out how to achieve your purpose.

AND don't forget to change your field_list "status" type from "int" to "text"

Edited by gonebdg - webindoshop.com (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

Hello, I'm working on a module in version 1.6 of prestashop. N amine listing I am trying to together with the edit button appear also a send butt that will open in another window and will show a form, the code looks like this: $ Helper-> actions = array ('edit', 'send'); But I still can not show the button on the form. Thanks for your help. Regards, Sílvia Pimenta.

Hello, I'm working on a module in version 1.6 of prestashop. N amine listing I am trying to together with the edit button appear also a send butt that will open in another window and will show a form, the code looks like this: $ Helper-> actions = array ('edit', 'send'); But I still can not show the button on the form. Thanks for your help. Regards, Sílvia Pimenta.

Share this post


Link to post
Share on other sites
On 12/20/2014 at 10:51 AM, gonebdg - webindoshop.com said:

Usually i create my Admin module controller and determine the required variables in class constructor, also create custom classes file for the data which will be processed (add/edit/delete) by this controller.
So the data will be treated as an object, because that was the reason why I use PHP OOP and MVC pattern (Prestashop)

 

example :


<?php
/*
** My Admin Module Controller
** Module name : mymodulename (as defined on module file, $this->name)
** With this controller I will be able to Add/Edit/Delete data (object) that i want
** Controller Class name doesn't have to use or same as the module name
** In here the class name is Admin + Name + Controller
** "Name" will be used as directory name where the necessary template helper file placed
** e.g: view.tpl
** ..\modules\mymodulename\views\templates\admin\name\helpers\view\view.tpl
*/

class AdminNameController extends ModuleAdminController
{
	public function __construct()
	{
		$this->bootstrap = true;
		$this->module = 'mymodulename'; // valid module name
		$this->table = 'db_table_name'; // DB table name where your object data stored
		$this->className = 'MyObjectClassName'; // The class name of my object
		$this->lang = false;
		$this->explicitSelect = true;
		$this->allow_export = true;
		$this->delete = true;
		$this->context = Context::getContext();
		$this->orderBy = 'id_object'; // DB column field which hold my object ID
		$this->_orderWay = 'DESC';
		$this->fields_list = $this->fieldList();
		$this->shopLinkType = 'shop';
		$this->actions = array('view', 'edit', 'delete');
		$this->bulk_actions = array(
			'delete' => array(
				'text' => $this->l('Delete selected'),
				'icon' => 'icon-trash',
				'confirm' => $this->l('Delete selected object?')
			)
		);

		parent::__construct();
	}

        public function fieldList()
        {
            // determine object fields in here. it will be processed by renderList() method
            // Note: fieldList can also determined directly on class constructor

            return $fields_list;
        }

        /* Function used to render the list to display for this controller */
        public function renderList()
        {
            // No need to use/override this method if not necessary

            return $list;
        }

        /* Function used to render the view page */
        public function renderView()
        {
            // form to add/edit my object are dermined here

            return parent::renderForm();
        }

        /* Function used to render the form for this controller */
        public function renderForm()
        {
            // form to add/edit my object are dermined here

            return parent::renderForm();
        }
}

If everytings is ok, and i've created the renderForm() method for my controller, the "Add new" action menu will automatically available. On the top right of the data list table (rendered by my controller) there will be an action menu icon [+] which created automatically by Prestashop system.

 

The parent classes AdminController.php will handle the process with processAdd() method

 

If i click this icon menu, i can create new object value without having to bother writing my php code on my controller.

Unless there is customizations needed or special circumstances which require me to extend processAdd() method.

 

I suggest you to take a look deep inside Prestashop classes controller files :
AdminModuleController.php and AdminController.php
and then start to create your Admin Module Controller file based on the available Prestashop Admin Controller.

Hi
thank you for your explain, I have module admin controller in prestashop 1.7 and I setTemplate() in initContent() method and now I want to use Helperlist and render list method but my own template overrides on renderList() and list is not show in admin module controller page.

how can I use custom template and render list width helper?

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More