How to insert an image in a template using HelperForm? - php

I am creating a custom module using PrestaShop 1.7 and I want to be be able to upload an image for the background. The image should be displayed if the field background_image is defined.
I am able to do it, but the image is outside of the form, as you can see in the image below.
The image should be displayed immediately above the background image field, like this (see below).
Here is my .tpl file:
{if isset($background_image)}
<div>
<div class="col-lg-3"></div>
<div>
<img src="/modules/cb_sectionaboutus/img/{$background_image}" class="img-thumbnail" width="400" />
</div>
</div>
{/if}
And here is part of the main PHP file of the module:
/**
* Load the configuration form
*/
public function getContent()
{
/**
* If values have been submitted in the form, process.
*/
if (((bool)Tools::isSubmit('submitCb_sectionaboutusModule')) == true) {
$this->postProcess();
}
$this->context->smarty->assign('module_dir', $this->_path);
/* Passes the background image to the template */
$data = $this->getDataFromDB();
$background_image = $data['background_image'];
$this->context->smarty->assign('background_image', $background_image);
// About section & Documentation
$output = $this->context->smarty->fetch($this->local_path.'views/templates/admin/configure.tpl');
return $output.$this->renderForm();
}
/**
* Create the form that will be displayed in the configuration of your module.
*/
protected function renderForm()
{
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitCb_sectionaboutusModule';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
.'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id
);
return $helper->generateForm(array($this->getConfigForm()));
}
/**
* Create the structure of your form.
*/
protected function getConfigForm()
{
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'textarea',
'label' => $this->l('Title'),
'name' => 'title',
'desc' => $this->l('Enter the title'),
'class' => 'rte',
'autoload_rte' => true
),
array(
'type' => 'file',
'label' => $this->l('Background Image'),
'name' => 'background_image',
'desc' => $this->l('Maximum image size: ') . $this->upload_file_size_limit_in_mb . ' MB.',
'display_image' => true
)
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
/**
* Set values for the inputs.
*/
protected function getConfigFormValues()
{
$data = $this->getDataFromDB();
return array(
'title' => $data['title'],
'background_image' => $data['background_image']
);
}
/**
* Get the data from the database
*/
public function getDataFromDB()
{
$sql = 'SELECT * FROM ' . _DB_PREFIX_ . $this->name . ' WHERE id_' . $this->name . ' = ' . 1;
return Db::getInstance()->ExecuteS($sql)[0];
}
/**
* Save form data.
*/
protected function postProcess()
{
/* Current data */
$data_from_db = $this->getDataFromDB();
/* New data */
$form_values = $this->getConfigFormValues();
/* Sets the background image as the old value, in case there is no new upload */
$form_values['background_image'] = $data_from_db['background_image'];
/* Validates the background image file */
$file_name = $this->validateFile();
/* Checks whether the background image has been successfully uploaded */
if ($file_name) {
/* Sets the new background image */
$form_values['background_image'] = $file_name;
}
// Has rows in table --> UPDATE
if ($data_from_db) {
$sql = $sql = "UPDATE " . _DB_PREFIX_ . $this->name . " SET ";
foreach (array_keys($form_values) as $key) {
$sql .= $key . " = '" . $form_values[$key] . "', ";
}
$sql = trim($sql, " "); // first trim last space
$sql = trim($sql, ","); // then trim trailing and prefixing commas
$sql .= " WHERE id_" . $this->name . " = " . 1;
}
// No rows in table --> INSERT
else {
$columns = "id_cb_sectionaboutus, " . implode(", ", array_keys($form_values));
$values = array_map('Tools::getValue', array_keys($form_values));
$values = "1, " . "'" . implode("', '", array_values($values)) . "'";
$sql = 'INSERT INTO ' . _DB_PREFIX_ . $this->name . ' (' . $columns . ') VALUES (' . $values . ')';
}
Db::getInstance()->ExecuteS($sql);
}
How can I insert the uploaded image in the middle of the form using HelperForm?
I would prefer a solution with HelperForm, but I don't know if it works, so I will accept any answer tha gives me a good solution.

PHP file - getConfigForm function
protected function getConfigForm()
{
// ADDED THESE LINES
$image = '';
$background_image = $this->getDataFromDB()['background_image'];
if ($background_image) {
$image_url = $background_image ? '/modules/cb_sectionaboutus/img/' . $background_image : '';
$image = '<div class="col-lg-6"><img src="' . $image_url . '" class="img-thumbnail" width="400"></div>';
}
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'file',
'label' => $this->l('Background Image'),
'name' => 'background_image',
'desc' => $this->l('Maximum image size: ') . $this->upload_file_size_limit_in_mb . ' MB.',
'display_image' => true,
'image' => $image // ADDED THIS OPTION
),
array(
'type' => 'textarea',
'label' => $this->l('Title'),
'name' => 'title',
'desc' => $this->l('Enter the title'),
'class' => 'rte',
'autoload_rte' => true
)
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
and remove everything from the template.

Related

Wordpress + Elementor: cyrillic in PDF

To generate a PDF file with data from the submitted form, I use Dynamic Content PDF Generator for Elementor Pro Form. The problem is with Cyrillic characters - they are displayed in the created pdf file as question marks. The file «DCE_Extension_Form_PDF.php» contains the following code:
<?php
namespace DynamicContentForElementor\Extensions;
use Elementor\Controls_Manager;
use DynamicContentForElementor\DCE_Helper;
use DynamicContentForElementor\DCE_Tokens;
if (!defined('ABSPATH'))
exit; // Exit if accessed directly
function _dce_extension_form_pdf($field) {
switch ($field) {
case 'enabled':
return true;
case 'docs':
return 'https://www.dynamic.ooo/widget/pdf-generator-for-elementor-pro-form/';
case 'description' :
return __('Add PDF Creation Actions to Elementor PRO Form', 'dynamic-content-for-elementor');
}
}
if (!DCE_Helper::is_plugin_active('elementor-pro') || !class_exists('ElementorPro\Modules\Forms\Classes\Action_Base')) {
class DCE_Extension_Form_PDF extends DCE_Extension_Prototype {
public $name = 'Form PDF';
private $is_common = false;
public static $depended_plugins = ['elementor-pro'];
static public function is_enabled() {
return _dce_extension_form_pdf('enabled');
}
public static function get_description() {
return _dce_extension_form_pdf('description');
}
public function get_docs() {
return _dce_extension_form_pdf('docs');
}
}
} else {
class DCE_Extension_Form_PDF extends \ElementorPro\Modules\Forms\Classes\Action_Base {
public $name = 'Form PDF';
public static $depended_plugins = ['elementor-pro'];
public $has_action = true;
static public function is_enabled() {
return _dce_extension_form_pdf('enabled');
}
public static function get_description() {
return _dce_extension_form_pdf('description');
}
public function get_docs() {
return _dce_extension_form_pdf('docs');
}
public static function get_plugin_depends() {
return self::$depended_plugins;
}
static public function get_satisfy_dependencies($ret = false) {
return true;
}
public function get_script_depends() {
return [];
}
public function get_style_depends() {
return [];
}
/**
* Get Name
*
* Return the action name
*
* #access public
* #return string
*/
public function get_name() {
return 'dce_form_pdf';
}
/**
* Get Label
*
* Returns the action label
*
* #access public
* #return string
*/
public function get_label() {
return __('PDF', 'dynamic-content-for-elementor');
}
/**
* Register Settings Section
*
* Registers the Action controls
*
* #access public
* #param \Elementor\Widget_Base $widget
*/
public function register_settings_section($widget) {
$widget->start_controls_section(
'section_dce_form_pdf',
[
'label' => $this->get_label(), //__('DCE', 'dynamic-content-for-elementor'),
'condition' => [
'submit_actions' => $this->get_name(),
],
]
);
$widget->add_control(
'dce_form_pdf_name', [
'label' => __('Name', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::TEXT,
'default' => '[date|U]',
'description' => __('The PDF file name, the .pdf extension will automatically added', 'dynamic-content-for-elementor'),
'label_block' => true,
]
);
$widget->add_control(
'dce_form_pdf_folder', [
'label' => __('Folder', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::TEXT,
'default' => 'elementor/pdf/[date|Y]/[date|m]',
'description' => __('The directory inside /wp-content/uploads/xxx where save the PDF file', 'dynamic-content-for-elementor'),
'label_block' => true,
]
);
$widget->add_control(
'dce_form_pdf_template',
[
'label' => __('Template', 'dynamic-content-for-elementor'),
'type' => 'ooo_query',
'placeholder' => __('Template Name', 'dynamic-content-for-elementor'),
'label_block' => true,
'query_type' => 'posts',
'object_type' => 'elementor_library',
'description' => __('Use a Elementor Template as body fo this PDF', 'dynamic-content-for-elementor'),
]
);
$paper_sizes = array_keys(\Dompdf\Adapter\CPDF::$PAPER_SIZES);
$tmp = array();
foreach ($paper_sizes as $asize) {
$tmp[$asize] = strtoupper($asize);
}
$paper_sizes = $tmp;
$widget->add_control(
'dce_form_pdf_size',
[
'label' => __('Page Size', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::SELECT,
'default' => 'a4',
'options' => $paper_sizes,
]
);
$widget->add_control(
'dce_form_pdf_orientation', [
'label' => __('Page Orientation', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::CHOOSE,
'options' => [
'portrait' => [
'title' => __('Portrait', 'dynamic-content-for-elementor'),
'icon' => 'fa fa-arrows-v',
],
'landscape' => [
'title' => __('Landscape', 'dynamic-content-for-elementor'),
'icon' => 'fa fa-arrows-h',
]
],
'toggle' => false,
'default' => 'portrait',
]
);
$widget->add_control(
'dce_form_pdf_margin', [
'label' => __('Page Margin', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::DIMENSIONS,
'size_units' => ['px', '%', 'em'],
]
);
$widget->add_control(
'dce_form_section_page', [
'label' => __('Sections Page', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::SWITCHER,
'description' => __('Force every Template Section in a new page', 'dynamic-content-for-elementor'),
]
);
/*$widget->add_control(
'dce_form_pdf_background',
[
'label' => __('background', 'elementor'),
'type' => Controls_Manager::MEDIA,
'dynamic' => [
'active' => true,
'categories' => $refl->getConstants(),
],
'placeholder' => __('Select condition field', 'elementor'),
]
);*/
$widget->add_control(
'dce_form_pdf_save', [
'label' => __('Save', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::SWITCHER,
'description' => __('Save the generated PDF file as Media', 'dynamic-content-for-elementor'),
]
);
$widget->add_control(
'dce_form_pdf_title', [
'label' => __('Title', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::TEXT,
'default' => 'Form data by [field id="name"] in [date|Y-m-d H:i:s]',
'description' => __('The PDF file Title', 'dynamic-content-for-elementor'),
'label_block' => true,
'condition' => [
'dce_form_pdf_save!' => '',
],
]
);
$widget->add_control(
'dce_form_pdf_content', [
'label' => __('Description', 'dynamic-content-for-elementor'),
'type' => Controls_Manager::TEXT,
'default' => '[field id="message"]',
'description' => __('The PDF file Description', 'dynamic-content-for-elementor'),
'label_block' => true,
'condition' => [
'dce_form_pdf_save!' => '',
],
]
);
$widget->add_control(
'dce_form_pdf_help', [
'type' => \Elementor\Controls_Manager::RAW_HTML,
'raw' => '<div id="elementor-panel__editor__help" class="p-0"><a id="elementor-panel__editor__help__link" href="'.$this->get_docs().'" target="_blank">'.__( 'Need Help', 'elementor' ).' <i class="eicon-help-o"></i></a></div>',
'separator' => 'before',
]
);
$widget->end_controls_section();
}
/**
* Run
*
* Runs the action after submit
*
* #access public
* #param \ElementorPro\Modules\Forms\Classes\Form_Record $record
* #param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler
*/
public function run($record, $ajax_handler) {
$settings = $record->get('form_settings');
$fields = DCE_Helper::get_form_data($record);
$settings = DCE_Helper::get_dynamic_value($settings, $fields);
$this->dce_elementor_form_pdf($fields, $settings, $ajax_handler);
}
/**
* On Export
*
* Clears form settings on export
* #access Public
* #param array $element
*/
public function on_export($element) {
$tmp = array();
if (!empty($element)) {
foreach ($element as $key => $value) {
if (substr($key, 0, 4) == 'dce_') {
$element[$key];
}
}
}
}
function dce_elementor_form_pdf($fields, $settings = null, $ajax_handler = null) {
global $dce_form, $post;
if (empty($settings['dce_form_pdf_template'])) {
$ajax_handler->add_error_message(__('Error: PDF Template not found or not setted', 'dynamic-content-for-elementor'));
return;
}
// verify Template
$template = get_post($settings['dce_form_pdf_template']);
if (!$template || $template->post_type != 'elementor_library') {
$ajax_handler->add_error_message(__('Error: PDF Template not setted correctly', 'dynamic-content-for-elementor'));
return;
}
$post = get_post($fields['submitted_on_id']); // to retrive dynamic data from post where the form was submitted
$pdf_folder = '/' . $settings['dce_form_pdf_folder'] . '/';
$upload = wp_upload_dir();
$pdf_dir = $upload['basedir'] . $pdf_folder;
$pdf_url = $upload['baseurl'] . $pdf_folder;
$pdf_name = $settings['dce_form_pdf_name'] . '.pdf';
$dce_form['pdf']['path'] = $pdf_dir . $pdf_name;
$dce_form['pdf']['url'] = $pdf_url . $pdf_name;
//var_dump($dce_form); die();
$pdf_html = do_shortcode('[dce-elementor-template id="' . $settings['dce_form_pdf_template'] . '"]');
$pdf_html = DCE_Helper::get_dynamic_value($pdf_html, $fields);
// add CSS
$css = DCE_Helper::get_post_css($settings['dce_form_pdf_template']);
// from flex to table
$css .= '.elementor-section .elementor-container { display: table !important; width: 100% !important; }';
$css .= '.elementor-row { display: table-row !important; }';
$css .= '.elementor-column { display: table-cell !important; }';
$css .= '.elementor-column-wrap, .elementor-widget-wrap { display: block !important; }';
$css = str_replace(':not(.elementor-motion-effects-element-type-background) > .elementor-element-populated', ':not(.elementor-motion-effects-element-type-background)', $css);
$css .= '.elementor-column .elementor-widget-image .elementor-image img { max-width: none !important; }';
$cssToInlineStyles = new \TijsVerkoyen\CssToInlineStyles\CssToInlineStyles();
$pdf_html = $cssToInlineStyles->convert(
$pdf_html,
$css
);
$pdf_html = DCE_Helper::template_unwrap($pdf_html);
// link image from url to path
$site_url = site_url();
//$pdf_html = str_replace('src="'.$site_url, 'src="'.$upload['basedir'], $pdf_html);
// from div to table
//$pdf_html = DCE_Helper::tablefy($pdf_html);
if (is_rtl()) {
// fix for arabic and hebrew
$pdf_html .= '<style>* { font-family: DejaVu Sans, sans-serif; }</style>';
}
if (!empty($settings['dce_form_section_page'])) {
//$pdf_html .= '<style>.elementor-top-section:not(:first-child) { page-break-before: always; }</style>';
$pdf_html .= '<style>.elementor-top-section { page-break-before: always; }.elementor-top-section:first-child { page-break-before: no; }</style>';
}
if (!empty($settings['dce_form_pdf_background'])) {
$bg_path = get_attached_file($settings['dce_form_pdf_background']);
$pdf_html .= '<style>body { background-image: url("'.$bg_path.'"); }</style>';
$pdf_html .= '<style>body { background-repeat: no-repeat; background-position: center; background-size: cover; }</style>';
/*
$data = file_get_contents($bg_path);
$base64 = 'data:image/' . $type . ';base64,' . base64_encode($data);
$pdf_html .= '<style>body { background-image: url(<?php echo $base64 ?>); }</style>';
*/
}
$pdf_html .= '<style>#page { margin: '.$settings['dce_form_pdf_margin']['top'].$settings['dce_form_pdf_margin']['unit'].' '.$settings['dce_form_pdf_margin']['right'].$settings['dce_form_pdf_margin']['unit'].' '.$settings['dce_form_pdf_margin']['bottom'].$settings['dce_form_pdf_margin']['unit'].' '.$settings['dce_form_pdf_margin']['left'].$settings['dce_form_pdf_margin']['unit'].'; }</style>';
//$ajax_handler->add_error_message($pdf_html); return false;
//echo $pdf_html; die();
if (!is_dir($pdf_dir)) {
// create dir
mkdir($pdf_dir, 0755, true);
}
// https://github.com/dompdf/dompdf
//$auth = base64_encode("username:password");
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => FALSE,
'verify_peer_name' => FALSE,
// 'allow_self_signed'=> TRUE
),
/*'http' => array(
'header' => "Authorization: Basic $auth"
)*/
));
$options = new \Dompdf\Options();
$options->set('isRemoteEnabled', TRUE);
$options->setIsRemoteEnabled(true);
//$options->set('defaultFont', 'Courier');
// instantiate and use the dompdf class
$dompdf = new \Dompdf\Dompdf($options);
$dompdf->setHttpContext($context);
$dompdf->loadHtml($pdf_html);
$dompdf->set_option('isRemoteEnabled', TRUE);
$dompdf->set_option('isHtml5ParserEnabled', true);
// (Optional) Setup the paper size and orientation
$dompdf->setPaper($settings['dce_form_pdf_size'], $settings['dce_form_pdf_orientation']);
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser
//$dompdf->stream();
$output = $dompdf->output();
if (!file_put_contents($pdf_dir . $pdf_name, $output)) {
$ajax_handler->add_error_message(__('Error generating PDF', 'dynamic-content-for-elementor'));
}
if ($settings['dce_form_pdf_save']) {
// Insert the post into the database
// https://codex.wordpress.org/Function_Reference/wp_insert_attachment
// $filename should be the path to a file in the upload directory.
$filename = $dce_form['pdf']['path'];
// The ID of the post this attachment is for.
$parent_post_id = $fields['submitted_on_id'];
// Check the type of file. We'll use this as the 'post_mime_type'.
$filetype = wp_check_filetype( basename( $filename ), null );
// Get the path to the upload directory.
$wp_upload_dir = wp_upload_dir();
// Prepare an array of post data for the attachment.
$attachment = array(
'guid' => $wp_upload_dir['url'] . '/' . basename( $filename ),
'post_mime_type' => $filetype['type'],
'post_status' => 'inherit',
'post_title' => $settings['dce_form_pdf_title'],
'post_content' => $settings['dce_form_pdf_content'],
);
// Insert the attachment.
$attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );
// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
require_once( ABSPATH . 'wp-admin/includes/image.php' );
// Generate the metadata for the attachment, and update the database record.
$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
wp_update_attachment_metadata( $attach_id, $attach_data );
//set_post_thumbnail( $parent_post_id, $attach_id );
// https://developer.wordpress.org/reference/functions/wp_insert_post/
/*$db_ins = array(
'post_title' => $settings['dce_form_pdf_title'],
'post_status' => 'public',
'post_type' => 'attachment',
'post_content' => $settings['dce_form_pdf_content'],
);
$obj_id = wp_insert_post($db_ins);*/
if ($attach_id) {
$dce_form['pdf']['id'] = $attach_id;
$dce_form['pdf']['title'] = $settings['dce_form_pdf_title'];
$dce_form['pdf']['description'] = $settings['dce_form_pdf_content'];
if (!empty($fields) && is_array($fields)) {
foreach ($fields as $akey => $adata) {
update_post_meta($attach_id, $akey, $adata);
}
}
} else {
$ajax_handler->add_error_message(__('Error saving PDF as Media', 'dynamic-content-for-elementor'));
}
}
}
}
}
I have tried different ways to add fonts and encodings to this code, but my programming knowledge is not enough, so I either received an error when submitting the form, or I received a file with the same question marks.

Cannot add any stylesheets to module in prestashop 1.7

I've encountered problem with adding any stylesheets to prestashop front office. I was reading multiple articles, tried multiple solutions and I can't get it to work. Adding styles to back office was not a problem (but that this code for adding styles to back office is workaround I think). Here is the module code. (I've added stylesheet import in multiple places to check every solution. In other modules this methods works as intended). Sorry for messy code I'm not that good in PHP.
<?php
if (!defined('_PS_VERSION_'))
exit();
class PromotionBanner extends Module
{
public function __construct()
{
$this->name = 'promotionbanner';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'example';
$this->author_uri = 'https://example.com';
$this->ps_versions_compliancy = array('min' => '1.7.1.0', 'max' => _PS_VERSION_);
$this->bootstrap = true;
$this->need_instance = 0;
$this->dir = '/modules/promotionbanner';
$this->css_path = Tools::getShopDomainSsl(true, true) . __PS_BASE_URI__ . 'modules/' . $this->name
. '/' . $this->_path . 'views/css/';
parent::__construct();
$this->displayName = $this->l('Promotion Banner', 'promotionbanner');
$this->description = $this->l('This module provides configurable promotion banner on your website');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall the module?', 'promotionbanner');
}
private function updateConf()
{
Configuration::updateValue('banner_text', $this->l('Wybrane produkty tańsze o 15%! Kod rabatowy: '));
Configuration::updateValue('banner_coupon_code', $this->l('Wybierz kupon rabatowy'));
}
public function install()
{
$this->updateConf();
return parent::install() && $this -> registerHook('displayWrapperTop') && $this->registerHook('header');
}
public function uninstall()
{
if (!parent::uninstall() || !Configuration::deleteByName('promotionbanner_module') &&
!Configuration::deleteByName('banner_coupon_code'))
return false;
return true;
}
public function hookDisplayWrapperTop($params)
{
$this->context->smarty->assign(
array(
'banner_text' => Configuration::get('banner_text'),
'banner_coupon_code' => Configuration::get('banner_coupon_code')
)
);
$this->context->controller->registerStylesheet(
'modules-promotion-banner2', //This id has to be unique
'modules/'.$this->name.'/views/css/front.css',
array('media' => 'all', 'priority' => 150)
);
return $this->display(__FILE__, 'promotionbanner.tpl');
}
public function hookHeader() {
$this->context->controller->addCSS($this->_path . 'views/css/front.css', 'all');
$this->context->controller->registerStylesheet(
'modules-promotion-banner', //This id has to be unique
'modules/'.$this->name.'/views/css/front.css',
array('media' => 'all', 'priority' => 150)
);
}
public function hookActionFrontControllerSetMedia($params) {
$this->context->controller->registerStylesheet(
'module-promotionbanner-style',
'modules/'.$this->name.'/views/css/front.css',
[
'media' => 'all',
'priority' => 200,
]
);
}
public function getPromotions()
{
$cart_rule = _DB_PREFIX_ . 'cart_rule';
$request = "SELECT $cart_rule.id_cart_rule, " . _DB_PREFIX_ . "cart_rule_lang.name, $cart_rule.code " .
"FROM $cart_rule INNER JOIN " . _DB_PREFIX_ . 'cart_rule_lang ON ' . _DB_PREFIX_ . 'cart_rule.id_cart_rule='
. _DB_PREFIX_ . 'cart_rule_lang.id_cart_rule WHERE ' . _DB_PREFIX_ . 'cart_rule.code IS NOT NULL';
$db = Db::getInstance();
$cupons = $db->executeS($request);
$parsedCupons = array();
foreach ($cupons as $cupon) {
array_push($parsedCupons, array(
'code' => $cupon['code'],
'name' => $cupon['name']
));
}
return $parsedCupons;
}
public function displayForm()
{
$form = $this->renderForm();
$this->context->smarty->assign(array(
'banner_text' => Configuration::get('banner_text'),
'banner_coupon_code' => Configuration::get('banner_coupon_code'),
'form_url' => AdminController::$currentIndex . '&configure=' . $this->name . '&token=' . Tools::getAdminTokenLite('AdminModules'),
'name' => $this->name,
'form_tpl' => $form,
'coupon_codes' => $this->getPromotions()
));
$this->context->controller->addCSS(array(
$this->css_path . 'fontawesome-all.min.css',
$this->css_path . 'module.css'
));
$this->output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/menu.tpl');
return $this->output;
}
public function renderForm()
{
$helper = new HelperForm();
$helper->module = $this;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->title = $this->displayName;
$helper->show_toolbar = false;
$helper->toolbar_scroll = false;
$helper->submit_action = 'submit' . $this->name;
$helper->toolbar_btn = array(
'save' =>
array(
'desc' => $this->l('Save'),
'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&save' . $this->name .
'&token=' . Tools::getAdminTokenLite('AdminModules'),
)
);
$helper->fields_value = array(
'banner_text' => Configuration::get('banner_text'),
'banner_coupon_code' => Configuration::get('banner_coupon_code')
);
return $helper->generateForm(array($this->getConfigForm()));
}
public function getConfigForm()
{
$fields_form = array(
'form' => array(
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Banner text before code: '),
'name' => 'banner_text',
'lang' => false,
'required' => true,
'size' => 20
),
array(
'type' => 'select',
'label' => $this->l('Coupon code: '),
'name' => 'banner_coupon_code',
'required' => true,
'options' => array(
'query' => $this->getPromotions(),
'id' => 'code',
'name' => 'name'
)
)
),
'submit' => array(
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right'
)
)
);
return $fields_form;
}
public function getContent()
{
$output = "";
if (Tools::isSubmit('submit' . $this->name)) {
$banner_text = strval(Tools::getValue('banner_text'));
$banner_coupon_code = strval(Tools::getValue('banner_coupon_code'));
if (!isset($banner_text) || !isset($banner_coupon_code))
$output .= $this->displayError($this->l('Please insert something in this field.'));
else {
Configuration::updateValue('banner_text', $banner_text);
Configuration::updateValue('banner_coupon_code', $banner_coupon_code);
$output .= $this->displayConfirmation($this->l('Field updated successfully!'));
}
}
return $output . $this->displayForm();
}
}
Okay so I've managed to successfully register the stylesheet in the prestashop 1.7.6.1. But I think this is a good time to mention some of my mistakes and address some of the problems.
Checklist of registering a stylesheet in front office
Use correct hook for the job.
My problem has been unsolved because I've used a wrong hook.
Make sure that your __construct() registered a official hook for registering stylesheets (prestashop 1.7.x). The correct hook is: $this->registerHook('actionFrontControllerSetMedia'); you can find official docs here (If you don't have front controller in your module): https://devdocs.prestashop.com/1.7/themes/getting-started/asset-management/#without-a-front-controller-module
Make sure that you registered your hook function with $params (I don't know why but it doesn't work without a function parameter defined... This also stopped me from successfull register). The proper function should look like this:
$this->context->controller->registerStylesheet(
'stylesheet-id', //This id has to be unique
'modules/'.$this->name.'/views/css/front.css',
array('server' => 'local', 'priority' => 10)
);
}
As #bakis mentioned. After every try clear your browser cache + prestashop cache for chrome or chromium users I would suggest to disable the browser cache in inspector window completely.
I know that $this->context->controller->addCSS still exists, but this function is useful only for back office stylesheet register. Even the official docs are saying about it
Backward compatibility is kept for the addJS(), addCSS(), addJqueryUI() and addJqueryPlugin() methods.
That's pretty much everything about this question. I hope it will help someone in the future who is searching for answer.

Yii2 create data row works but update doesn't

I saw red some answers on similar questions but still can't understand where is my problem. I have a _form.php which is used when data row is created and updated аlso. When i create data row it is OK but when it redirects me to return $this->redirect(['view', 'id' => $model->id]); but the data is not updated. Tried to var_dump($model->getErrors()) (as I saw in the answers of another question) but it returns me and empty array.
These are my files:
Controller action:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$settings = new Settings();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$languages = Lang::find()->all();
foreach ($languages as $language) {
if ($language->default != 1) {
$names = 'names_' . $language->url;
$varNames = Yii::$app->OutData->sanitize($model->$names);
$model->$names = $varNames;
$review = 'review_' . $language->url;
$varReview = Yii::$app->OutData->sanitize($model->$review);
$model->$review = $varReview;
$metaDesc = 'meta_desc_' . $language->url;
$varMetaDesc = Yii::$app->OutData->sanitize($model->$metaDesc);
$model->$metaDesc = $varMetaDesc;
$url = 'url_' . $language->url;
$varUrl = Yii::$app->OutData->sanitize($model->$url);
$model->$url = $varUrl;
$cBirth = 'country_birth_' . $language->url;
$varcBirth = Yii::$app->OutData->sanitize($model->$cBirth);
$model->$cBirth = $varcBirth;
}
else
{
$model->names = Yii::$app->OutData->sanitize($model->names);
$model->review = Yii::$app->OutData->sanitize($model->review);
$model->meta_desc = Yii::$app->OutData->sanitize($model->meta_desc);
$model->url= Yii::$app->OutData->sanitize($model->url);
$model->country_birth = Yii::$app->OutData->sanitize($model->country_birth);
}
}
//записване на изображенията + thumb
if (isset($_POST["Author"]["imageFiles"]) and ! empty($_POST["Author"]["imageFiles"])) {
$model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
if (isset($model->imageFiles) and count($model->imageFiles) > 0) {
foreach ($model->imageFiles as $key => $file) {
$parseProdTitle = MakeURL::parseImageName($model->names.'_'.$model->id);
$fileName = $parseProdTitle . '_' . $model->id . '.' . $file->extension;
$fileName = Yii::$app->translate->cyr_to_lat($fileName);
$model->filename = $fileName;
$model->save(false);
$pic = Yii::getAlias('#frontend/web') . '/authors/thumb-270/' . $fileName;
$pic2 = Yii::getAlias('#frontend/web') . '/authors/' . $fileName;
$file->saveAs(Yii::getAlias('#frontend/web') . '/authors/' . $fileName);
$image = file_get_contents(Yii::getAlias('#frontend/web') . '/authors/' . $fileName);
file_put_contents($pic, $image);
$model->resizeImg($pic);
$settings->compress($pic, $pic, 90);
$settings->compress($pic2, $pic2, 90);
}
}
}
if($model->update()){
var_dump(1);die;
}else{
var_dump($model->getErrors());die;// it dumps here but it returns an empty array
}
if($model->validate()){
var_dump(1);die;// it dumps here so validate is ok ( I guess )
}else{
var_dump($model->getErrors());die;
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
And my model:
<?php
namespace backend\models;
use Yii;
use omgdef\multilingual\MultilingualBehavior;
use omgdef\multilingual\MultilingualQuery;
use kartik\helpers\Html;
/**
* This is the model class for table "author".
*
* #property integer $id
* #property integer $active
* #property string $filename
* #property integer $sort
* #property data $birthday
*
* #property AuthorLang[] $authorLangs
*/
class Author extends \yii\db\ActiveRecord
{
public $imageFiles;
private $languages = array();
public function __construct() {
foreach(Yii::$app->params['languages'] as $langArr){
$langParam = new Lang;
$langParam->id = $langArr['id'];
$langParam->url = $langArr['url'];
$langParam->local = $langArr['local'];
$langParam->name = $langArr['name'];
$langParam->default = $langArr['default'];
$langParam->active = $langArr['active'];
$this->languages[] = $langParam;
}
parent::__construct();
}
public static function find()
{
return new MultilingualQuery(get_called_class());
}
public function behaviors()
{
$languagesArray = [];
foreach($this->languages as $language){
if($language->default){
$defLang = $language->url;
}
$languagesArray[$language->local] = $language->name;
}
return [
'ml' => [
'class' => MultilingualBehavior::className(),
'languages' => $languagesArray,
//'languageField' => 'language',
//'localizedPrefix' => '',
//'requireTranslations' => false',
//'dynamicLangClass' => true',
//'langClassName' => PostLang::className(), // or namespace/for/a/class/PostLang
'defaultLanguage' => $defLang,
'langForeignKey' => 'author_id',
'tableName' => "{{%authorLang}}",
'attributes' => [
'names',
'review',
'meta_desc',
'url',
'country_birth',
]
],
];
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'author';
}
/**
* #inheritdoc
*/
public function rules()
{
$required = ['names', 'review', 'meta_desc', 'url', 'birthday', 'country_birth'];
$this->checkLanguage([$required]);
return [
[['active', 'sort'], 'required'],
[$required, 'required'],
['names', 'string', 'max' => 255],
['country_birth', 'string', 'max' => 255],
['review', 'string'],
['meta_desc', 'string', 'max' => 170],
['url', 'string', 'max' => 60],
[['active', 'sort'], 'integer'],
[['filename'], 'string'],
];
}
protected function checkLanguage($megaArr = [])
{
foreach ($this->languages as $language)
{
if($language->default != 1)
{
foreach ($megaArr as $fields)
{
foreach ($fields as $field)
{
$field .= '_' . $language->url;
}
}
}
}
}
public function changeActiveForm() {
$active = "";
if ($this->active == 1) {
$active = 'checked="checked"';
}
return '<label class="switch switch-custom block mbn taCenter">
<input type="checkbox" value="1" id="check_' . $this->id . '" name="field_types" class="legend-switch" ' . $active . ' onchange="changeStatusActive(' . $this->id . ', \'author\');"></input>
<label data-off="' . Yii::t('app', 'Не') . '" data-on="' . Yii::t('app', 'Да') . '" for="check_' . $this->id . '"></label>
<span></span>
</label>';
}
public function getKartikImagesList() {
$doctorImagesArr = array();
$doctorImages = Author::find()->where('id = :id', [':id' => $this->id])->orderBy(['id' => SORT_ASC])->one();
if(isset($doctorImages->filename) and $doctorImages->filename!="" and $doctorImages->filename!=Null) {
$fileName = Yii::getAlias('#frontend/web') . "/authors/" . $doctorImages->filename;
if (file_exists($fileName)) {
$fileNameUrl = Yii::$app->urlManagerFrontend->baseUrl . "/authors/thumb-270/" . $doctorImages->filename;
$doctorImagesArr[] = Html::img($fileNameUrl, ['class' => 'file-preview-image', 'style' => 'width: 350px;']) .
'<span class="glyphicons glyphicons-bin"></span>';
}
}
return $doctorImagesArr;
}
public function resizeImg($img) {
$sz = getimagesize($img);
$ratio = $sz[0] / $sz[1]; // w/h
$w2 = Yii::$app->params['thumbswidth']; // thumb 1 width
$image = new SimpleImage();
$image->load($img);
$image->resize($w2, round($w2 / $ratio));
$image->save($img);
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'active' => Yii::t('app','app.Active' ),
'filename' => Yii::t('app','app.Filename' ),
'sort' => Yii::t('app','app.Sort' ),
'country_birth' => Yii::t('app','app.Birth Country' ),
'names' => Yii::t('app','app.Names' ),
'meta_desc' => Yii::t('app','app.Meta Desc' ),
'filename' => Yii::t('app','app.Image' ),
'birthday' => Yii::t('app','app.Birthday' ),
'imageFiles' => Yii::t('app','app.Image' ),
'description' => Yii::t('app','app.Review' ),
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getAuthorLangs()
{
return $this->hasMany(AuthorLang::className(), ['author_id' => 'id']);
}
}
I didn't post the _form.php because it is the same for both actions (create and update) and I think that the problem is not in it.If you need it will update my question immediately. Thank you in advance!
For some reason it is possible that the update does not affect any row in the table. In this case the function return 0 .. for check this situation you should chek this this way
http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html#update()-detail
if($model->update() !== false){
var_dump(1);die;
}else{
var_dump($model->getErrors());die;// it dumps here but it returns an empty array
}
then, just for debugging, you could also try using $model->save(false) instead of $model->update() ... this way the $model is saved without regarding the validation rules ..

AJAX callback no response in custom Drupal block

I added a PhantomJS Capture module to my Drupal website. Test function showed my configuration works and I can use it from an administration interface. Now, I want to put it on a website, as a custom block so an end user could paste a website link and get screenshot of it back.
I implemented this piece of the code at the end of the module and form appears on a website.
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_info() {
$blocks = array();
$blocks['Scraping Block'] = array(
'info' => t('scraping block'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'Scraping Block':
$block['subject'] = 'Scraper';
$block['content'] = phantomjs_capture_admin_form();
break;
}
return $block;
}
However ajax callback is not firing on submit. How can I test this problem? Or is something wrong with my understanding of this module?
This is all code I've got in phantomjs_capture.module, I haven't changed any other files.
<?php
/**
* #file
* Defines the administration interface and utility functions to use PhantomJS
* and test screenshot capture functions.
*/
// #todo: hook_help.
/**
* Implements hook_menu().
*/
function phantomjs_capture_menu() {
$items = array();
$items['admin/config/user-interface/phantomjs_capture'] = array(
'title' => 'PhantomJS Screen capture',
'description' => 'Screen capture with PhantomJS',
'page callback' => 'drupal_get_form',
'page arguments' => array('phantomjs_capture_admin_form'),
'access arguments' => array('adminster site'),
);
return $items;
}
/**
* The administration form that allows site admins to enter information about
* the systems installation of PhantomJS.
*
* #return array $form
* Drupal form array witht the administration form.
*/
function phantomjs_capture_admin_form() {
$form = array();
$form['phantomjs_settings'] = array(
'#type' => 'fieldset',
'#title' => t('PhantomJS settings'),
'#collapsible' => FALSE,
);
$form['phantomjs_settings']['phantomjs_capture_binary'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('Path to phantomJS'),
'#description' => t('This module requries that you install PhantomJS on your server and enter the path to the executable. The program is not include in the module due to linces and operation system constrains. See !url for information about download.', array(
'!url' => l('PhantomJs.org', 'http://phantomjs.org/'),
)),
'#default_value' => variable_get('phantomjs_capture_binary', _phantomjs_capture_get_binray()),
);
$form['phantomjs_settings']['phantomjs_capture_dest'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('Default destination'),
'#description' => t('The default destination for screenshots captures with PhantomJS'),
'#default_value' => variable_get('phantomjs_capture_dest', 'phantomjs'),
);
$form['phantomjs_settings']['phantomjs_capture_script'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('PhantomJS capture script'),
'#description' => t('The script used by PhantomJS to capture the screen. It captures full HD images (1920 x 1080).'),
'#default_value' => variable_get('phantomjs_capture_script', drupal_get_path('module', 'phantomjs_capture') . '/js/phantomjs_capture.js'),
);
$form['phantomjs_capture_test'] = array(
'#type' => 'fieldset',
'#title' => t('Phantom JS test'),
'#description' => t('You can use the form in this section to test your installation of PhantomJS.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
);
$form['phantomjs_capture_test']['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#description' => t('Absolute URL to the homepage that should be capture (it has to be a complet URL with http://).'),
'#default_value' => 'http://www.google.com',
);
$form['phantomjs_capture_test']['format'] = array(
'#type' => 'select',
'#title' => 'File format',
'#options' => array(
'.png' => 'png',
'.jpg' => 'jpg',
'.pdf' => 'pdf',
),
);
$form['phantomjs_capture_test']['result'] = array(
'#prefix' => '<div id="phantomjs-capture-test-result">',
'#suffix' => '</div>',
'#markup' => '',
);
$form['phantomjs_capture_test']['button'] = array(
'#type' => 'button',
'#value' => t('Capture'),
"#ajax" => array(
"callback" => "phantomjs_capture_test_submit",
"wrapper" => "phantomjs-capture-test-result",
"method" => 'replace',
"effect" => "fade"
)
);
return $form;
}
/**
* Ajax callback for the test PhantomJS form on the administration page.
*
* #param type $form
* #param type $form_state
* #return type
*/
function phantomjs_capture_test_submit($form, $form_state) {
// Build urls and destionation.
$url = $form_state['values']['phantomjs_capture_test']['url'];
$file = 'test' . $form_state['values']['phantomjs_capture_test']['format'];
$dest = file_default_scheme() . '://' . variable_get('phantomjs_capture_dest', 'phantomjs');
// Get the screenshot and create success/error message.
$output = '<div class="messages status"><ul><li>' . t('File have been generated. You can get it !url', array('!url' => l(t('here'), file_create_url($dest . '/' . $file)))) . '.</ul></li></div>';
if (!phantomjs_capture_screen($url, $dest, $file)) {
$output = '<div class="messages error"><ul><li>' . t('The address entered could not be retrieved.') . '</ul></li></div>';
}
// Return
return array(
'phantomjs_capture_test' => array(
'result' => array(
'#prefix' => '<div id="phantomjs-capture-test-result">',
'#suffix' => '</div>',
'#markup' => $output,
),
),
);
}
/**
* Validation of the administration form. It tests that the locations given
* exists and that the PhantomJS binary is executable (by getting its version
* number).
*
* #param type $form
* #param type $form_state
*/
function phantomjs_capture_admin_form_validate(&$form, &$form_state) {
// Check that phantomjs exists.
if (!file_exists($form_state['values']['phantomjs_capture_binary'])) {
form_set_error('phantomjs_capture_binary', t('PhantomJS was not found at the location given.'));
}
else {
// Only show version message on "Save configuration" submit.
if ($form_state['clicked_button']['#value'] == t('Save configuration')) {
drupal_set_message(t('PhantomJS version #version found.', array(
'#version' => _phantomjs_capture_get_version($form_state['values']['phantomjs_capture_binary']),
)));
}
}
// Check that destination can be created.
$dest = file_default_scheme() . '://' . $form_state['values']['phantomjs_capture_dest'];
if (!file_prepare_directory($dest, FILE_CREATE_DIRECTORY)) {
form_set_error('phantomjs_capture_dest', t('The path was not writeable or could not be created.'));
}
// Check that capture script exists.
if (!file_exists($form_state['values']['phantomjs_capture_script'])) {
form_set_error('phantomjs_capture_script', t('PhantomJS script was not found at the location given.'));
}
// Remove test form.
unset($form_state['values']['phantomjs_capture_test']);
}
/**
* Returns the version number of the currently install PhantomJS.
*
* #param string $binary
* Optional absolute path with the PhantomJS binary. If not given the default
* location is used.
* #return string|boolean
* If PhantomJS is found and executeable the version number is returned else
* FALSE is returned.
*/
function _phantomjs_capture_get_version($binary = NULL) {
// If the binary is not given try the default path.
if (is_null($binary)) {
$binary = _phantomjs_capture_get_binray();
if (!$binary) {
drupal_set_message(t('PhantomJS binary was not found. Plase intall PhantomJS on the system.'));
return FALSE;
}
}
// Execute PhantomJS to get its version, if PhantomJS was found.
$output = array();
exec($binary . ' -v', $output);
return $output[0];
}
/**
* Returns the absolute path with the binray to the installed PhantomJS.
*
* #return string|boolean
* The executable PhantomJS binary or FALSE if not found.
*/
function _phantomjs_capture_get_binray() {
$binary = variable_get('phantomjs_capture_binary', '/usr/local/bin/phantomjs');
if (!file_exists($binary)) {
return FALSE;
}
return $binary;
}
/**
* Captures a screenshot using PhantomJS by calling the program.
*
* #param string $url
* The ULR/http(s) to render the screenshot from.
* #param type $dest
* The destionation for the rendered file (e.g. public://fecthed_images).
* #param type $filename
* The filename to store the file as in the destination.
* #param type $element
* The id of the DOM element to render in the document.
* #return boolean
* Returns TRUE if the screenshot was taken else FALSE on error.
*/
function phantomjs_capture_screen($url, $dest, $filename, $element = NULL) {
// Get PhantomJS binary.
$binary = _phantomjs_capture_get_binray();
if (!$binary) {
drupal_set_message(t('PhantomJS binary was not found. Plase intall PhantomJS on the system.'));
return FALSE;
}
// Check that destination is writeable.
if (!file_prepare_directory($dest, FILE_CREATE_DIRECTORY)) {
drupal_set_message(t('The PhantomJS destination path (#dest) was not writeable or could not be created.', array(
'#dest' => $dest,
)));
return FALSE;
}
// Get absolute path to PhantomJS script and the destionation file.
$script = realpath(variable_get('phantomjs_capture_script', drupal_get_path('module', 'phantomjs_capture') . '/js/phantomjs_capture.js'));
$dest = drupal_realpath($dest . '/' . $filename);
// Run PhantomJS to create the screen shot.
$output = array();
if ($element) {
exec($binary . ' ' . $script . ' ' . $url . ' ' . $dest . ' ' . escapeshellarg($element), $output);
} else {
exec($binary . ' ' . $script . ' ' . $url . ' ' . $dest, $output);
}
// Check that PhantomJS was able to load the page.
if ($output[0] == '500') {
return FALSE;
}
return TRUE;
}
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_info() {
$blocks = array();
$blocks['Scraping Block'] = array(
'info' => t('scraping block'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'Scraping Block':
$block['subject'] = 'Scraper';
$block['content'] = phantomjs_capture_admin_form();
break;
}
return $block;
}
I got the solution on a different website provided by #zaporylie. The problem wasn't AJAX but my approach to the problem. In short, he suggested to create a new custom module dependent on PhantomJS Capture and then to declare a block.
Here's working code with AJAX:
phantomjs_capture_block.info
name = PhantomJS Capture Block
description = Adds block with simple form.
core = 7.x
package = Other
dependencies[] = phantomjs_capture
phantomjs_capture_block.module
<?php
/**
* #file
* Simple form placed in block.
*/
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_block_info() {
$blocks['screenshot'] = array(
'info' => t('Screenshot'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_block_view($delta = '') {
$block = array();
if ($delta === 'screenshot') {
$block['title'] = t('Screenshot');
$block['content'] = drupal_get_form('phantomjs_capture_block_form');
}
return $block;
}
/**
* Simple form.
*/
function phantomjs_capture_block_form($form, &$form_state) {
$form['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#ajax' => array(
'callback' => 'phantomjs_capture_block_form_callback',
'wrapper' => 'phantomjs-capture-block-form-preview',
'method' => 'replace',
),
);
$form['preview'] = array(
'#type' => 'container',
'#attributes' => array(
'id' => 'phantomjs-capture-block-form-preview',
),
);
if (!empty($form_state['values']['url'])) {
$directory = 'public://';
$filename = REQUEST_TIME . '.png';
if (phantomjs_capture_screen($form_state['values']['url'], $directory, $filename)) {
$form['preview']['image'] = array(
'#theme' => 'image',
'#path' => $directory . '/' . $filename,
'#width' => '100%',
);
}
else {
drupal_set_message(t('Unable to create screenshot'), 'error');
}
}
return $form;
}
function phantomjs_capture_block_form_callback($form, $form_state) {
return $form['preview'];
}

Creating a block using PhantomJS Capture module

I've added a PhantomJS Capture module to my Drupal website. Test function showed my configuration works and I can use it from an administration interface. Now, I want to put it on a website, as a custom block. I added this piece of the code at the end of the module, so the form appears on the website.
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_info() {
$blocks = array();
$blocks['Scraping Block'] = array(
'info' => t('scraping block'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'Scraping Block':
$block['subject'] = 'Scraper';
$block['content'] = phantomjs_capture_admin_form();
break;
}
return $block;
}
However ajax callback is not firing on submit. What's wrong with the code or my understanding of this module? Thanks.
This is all code I've got in phantomjs_capture.module, I haven't changed any other files.
<?php
/**
* #file
* Defines the administration interface and utility functions to use PhantomJS
* and test screenshot capture functions.
*/
// #todo: hook_help.
/**
* Implements hook_menu().
*/
function phantomjs_capture_menu() {
$items = array();
$items['admin/config/user-interface/phantomjs_capture'] = array(
'title' => 'PhantomJS Screen capture',
'description' => 'Screen capture with PhantomJS',
'page callback' => 'drupal_get_form',
'page arguments' => array('phantomjs_capture_admin_form'),
'access arguments' => array('adminster site'),
);
return $items;
}
/**
* The administration form that allows site admins to enter information about
* the systems installation of PhantomJS.
*
* #return array $form
* Drupal form array witht the administration form.
*/
function phantomjs_capture_admin_form() {
$form = array();
$form['phantomjs_settings'] = array(
'#type' => 'fieldset',
'#title' => t('PhantomJS settings'),
'#collapsible' => FALSE,
);
$form['phantomjs_settings']['phantomjs_capture_binary'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('Path to phantomJS'),
'#description' => t('This module requries that you install PhantomJS on your server and enter the path to the executable. The program is not include in the module due to linces and operation system constrains. See !url for information about download.', array(
'!url' => l('PhantomJs.org', 'http://phantomjs.org/'),
)),
'#default_value' => variable_get('phantomjs_capture_binary', _phantomjs_capture_get_binray()),
);
$form['phantomjs_settings']['phantomjs_capture_dest'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('Default destination'),
'#description' => t('The default destination for screenshots captures with PhantomJS'),
'#default_value' => variable_get('phantomjs_capture_dest', 'phantomjs'),
);
$form['phantomjs_settings']['phantomjs_capture_script'] = array(
'#type' => 'textfield',
'#required' => TRUE,
'#title' => t('PhantomJS capture script'),
'#description' => t('The script used by PhantomJS to capture the screen. It captures full HD images (1920 x 1080).'),
'#default_value' => variable_get('phantomjs_capture_script', drupal_get_path('module', 'phantomjs_capture') . '/js/phantomjs_capture.js'),
);
$form['phantomjs_capture_test'] = array(
'#type' => 'fieldset',
'#title' => t('Phantom JS test'),
'#description' => t('You can use the form in this section to test your installation of PhantomJS.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
);
$form['phantomjs_capture_test']['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#description' => t('Absolute URL to the homepage that should be capture (it has to be a complet URL with http://).'),
'#default_value' => 'http://www.google.com',
);
$form['phantomjs_capture_test']['format'] = array(
'#type' => 'select',
'#title' => 'File format',
'#options' => array(
'.png' => 'png',
'.jpg' => 'jpg',
'.pdf' => 'pdf',
),
);
$form['phantomjs_capture_test']['result'] = array(
'#prefix' => '<div id="phantomjs-capture-test-result">',
'#suffix' => '</div>',
'#markup' => '',
);
$form['phantomjs_capture_test']['button'] = array(
'#type' => 'button',
'#value' => t('Capture'),
"#ajax" => array(
"callback" => "phantomjs_capture_test_submit",
"wrapper" => "phantomjs-capture-test-result",
"method" => 'replace',
"effect" => "fade"
)
);
return $form;
}
/**
* Ajax callback for the test PhantomJS form on the administration page.
*
* #param type $form
* #param type $form_state
* #return type
*/
function phantomjs_capture_test_submit($form, $form_state) {
// Build urls and destionation.
$url = $form_state['values']['phantomjs_capture_test']['url'];
$file = 'test' . $form_state['values']['phantomjs_capture_test']['format'];
$dest = file_default_scheme() . '://' . variable_get('phantomjs_capture_dest', 'phantomjs');
// Get the screenshot and create success/error message.
$output = '<div class="messages status"><ul><li>' . t('File have been generated. You can get it !url', array('!url' => l(t('here'), file_create_url($dest . '/' . $file)))) . '.</ul></li></div>';
if (!phantomjs_capture_screen($url, $dest, $file)) {
$output = '<div class="messages error"><ul><li>' . t('The address entered could not be retrieved.') . '</ul></li></div>';
}
// Return
return array(
'phantomjs_capture_test' => array(
'result' => array(
'#prefix' => '<div id="phantomjs-capture-test-result">',
'#suffix' => '</div>',
'#markup' => $output,
),
),
);
}
/**
* Validation of the administration form. It tests that the locations given
* exists and that the PhantomJS binary is executable (by getting its version
* number).
*
* #param type $form
* #param type $form_state
*/
function phantomjs_capture_admin_form_validate(&$form, &$form_state) {
// Check that phantomjs exists.
if (!file_exists($form_state['values']['phantomjs_capture_binary'])) {
form_set_error('phantomjs_capture_binary', t('PhantomJS was not found at the location given.'));
}
else {
// Only show version message on "Save configuration" submit.
if ($form_state['clicked_button']['#value'] == t('Save configuration')) {
drupal_set_message(t('PhantomJS version #version found.', array(
'#version' => _phantomjs_capture_get_version($form_state['values']['phantomjs_capture_binary']),
)));
}
}
// Check that destination can be created.
$dest = file_default_scheme() . '://' . $form_state['values']['phantomjs_capture_dest'];
if (!file_prepare_directory($dest, FILE_CREATE_DIRECTORY)) {
form_set_error('phantomjs_capture_dest', t('The path was not writeable or could not be created.'));
}
// Check that capture script exists.
if (!file_exists($form_state['values']['phantomjs_capture_script'])) {
form_set_error('phantomjs_capture_script', t('PhantomJS script was not found at the location given.'));
}
// Remove test form.
unset($form_state['values']['phantomjs_capture_test']);
}
/**
* Returns the version number of the currently install PhantomJS.
*
* #param string $binary
* Optional absolute path with the PhantomJS binary. If not given the default
* location is used.
* #return string|boolean
* If PhantomJS is found and executeable the version number is returned else
* FALSE is returned.
*/
function _phantomjs_capture_get_version($binary = NULL) {
// If the binary is not given try the default path.
if (is_null($binary)) {
$binary = _phantomjs_capture_get_binray();
if (!$binary) {
drupal_set_message(t('PhantomJS binary was not found. Plase intall PhantomJS on the system.'));
return FALSE;
}
}
// Execute PhantomJS to get its version, if PhantomJS was found.
$output = array();
exec($binary . ' -v', $output);
return $output[0];
}
/**
* Returns the absolute path with the binray to the installed PhantomJS.
*
* #return string|boolean
* The executable PhantomJS binary or FALSE if not found.
*/
function _phantomjs_capture_get_binray() {
$binary = variable_get('phantomjs_capture_binary', '/usr/local/bin/phantomjs');
if (!file_exists($binary)) {
return FALSE;
}
return $binary;
}
/**
* Captures a screenshot using PhantomJS by calling the program.
*
* #param string $url
* The ULR/http(s) to render the screenshot from.
* #param type $dest
* The destionation for the rendered file (e.g. public://fecthed_images).
* #param type $filename
* The filename to store the file as in the destination.
* #param type $element
* The id of the DOM element to render in the document.
* #return boolean
* Returns TRUE if the screenshot was taken else FALSE on error.
*/
function phantomjs_capture_screen($url, $dest, $filename, $element = NULL) {
// Get PhantomJS binary.
$binary = _phantomjs_capture_get_binray();
if (!$binary) {
drupal_set_message(t('PhantomJS binary was not found. Plase intall PhantomJS on the system.'));
return FALSE;
}
// Check that destination is writeable.
if (!file_prepare_directory($dest, FILE_CREATE_DIRECTORY)) {
drupal_set_message(t('The PhantomJS destination path (#dest) was not writeable or could not be created.', array(
'#dest' => $dest,
)));
return FALSE;
}
// Get absolute path to PhantomJS script and the destionation file.
$script = realpath(variable_get('phantomjs_capture_script', drupal_get_path('module', 'phantomjs_capture') . '/js/phantomjs_capture.js'));
$dest = drupal_realpath($dest . '/' . $filename);
// Run PhantomJS to create the screen shot.
$output = array();
if ($element) {
exec($binary . ' ' . $script . ' ' . $url . ' ' . $dest . ' ' . escapeshellarg($element), $output);
} else {
exec($binary . ' ' . $script . ' ' . $url . ' ' . $dest, $output);
}
// Check that PhantomJS was able to load the page.
if ($output[0] == '500') {
return FALSE;
}
return TRUE;
}
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_info() {
$blocks = array();
$blocks['Scraping Block'] = array(
'info' => t('scraping block'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'Scraping Block':
$block['subject'] = 'Scraper';
$block['content'] = phantomjs_capture_admin_form();
break;
}
return $block;
}
I got the solution on a different website provided by #zaporylie. The problem wasn my approach to the problem. In short, he suggested to create a new custom module dependent on PhantomJS Capture and then to declare a block.
Here's working code:
phantomjs_capture_block.info
name = PhantomJS Capture Block
description = Adds block with simple form.
core = 7.x
package = Other
dependencies[] = phantomjs_capture
phantomjs_capture_block.module
<?php
/**
* #file
* Simple form placed in block.
*/
/**
* Implements hook_block_info().
*/
function phantomjs_capture_block_block_info() {
$blocks['screenshot'] = array(
'info' => t('Screenshot'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function phantomjs_capture_block_block_view($delta = '') {
$block = array();
if ($delta === 'screenshot') {
$block['title'] = t('Screenshot');
$block['content'] = drupal_get_form('phantomjs_capture_block_form');
}
return $block;
}
/**
* Simple form.
*/
function phantomjs_capture_block_form($form, &$form_state) {
$form['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#ajax' => array(
'callback' => 'phantomjs_capture_block_form_callback',
'wrapper' => 'phantomjs-capture-block-form-preview',
'method' => 'replace',
),
);
$form['preview'] = array(
'#type' => 'container',
'#attributes' => array(
'id' => 'phantomjs-capture-block-form-preview',
),
);
if (!empty($form_state['values']['url'])) {
$directory = 'public://';
$filename = REQUEST_TIME . '.png';
if (phantomjs_capture_screen($form_state['values']['url'], $directory, $filename)) {
$form['preview']['image'] = array(
'#theme' => 'image',
'#path' => $directory . '/' . $filename,
'#width' => '100%',
);
}
else {
drupal_set_message(t('Unable to create screenshot'), 'error');
}
}
return $form;
}
function phantomjs_capture_block_form_callback($form, $form_state) {
return $form['preview'];
}

Categories