So I'm looking for a solution to save invoice automatically into my server folder, when I press view invoice as the generated URL occurs (http://www.example.com/admin11111/index.php?controller=AdminPdf&token="token"&submitAction=generateInvoicePDF&id_order="id").
I also did research on google, but this solution, somehow didnt work for me: https://www.prestash...es-in-a-folder/
From Prestashop Forum I got advice that I should use shell script, but using a shell download like wget or other only gets me html file, because when I download the invoice in Prestashop backoffice.. it takes some time to generate and the download save appears later.
With this 2 overrides you could accomplish this.
Override PDF.php:
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE)
parent::render('F', true);
return parent::render($display);
}
}
Override PDFGenerator.php:
class PDFGenerator extends PDFGeneratorCore
{
public function render($filename, $display = true)
{
if (empty($filename)) {
throw new PrestaShopException('Missing filename.');
}
$this->lastPage();
if ($display === true) {
$output = 'D';
} elseif ($display === false) {
$output = 'S';
} elseif ($display == 'D') {
$output = 'D';
} elseif ($display == 'S') {
$output = 'S';
} elseif ($display == 'F') {
$output = 'F';
$filename = _PS_ROOT_DIR_.'/'.$filename;
} else {
$output = 'I';
}
return $this->output($filename, $output);
}
}
Remember to choose another folder other than _PS_ROOT_DIR_. This was just for testing. Try $filename = _PS_ROOT_DIR_.'/../invoices/'.$filename; so it's not a public folder (and you must create the folder with the correct permissions.
Related
I'm making a PrestaShop 1.6 module and something weird is happening. In the configure page of this module I offer the user two forms. One to configure an automatic email and other to test the e-mail. My problem is that after submitting the second form the $this->context->smarty is null giving me this error:
Fatal error: Call to a member function assign() on null in /Users/andre/Projects/Web/xxx/modules/closecustomerthreademail/closecustomerthreademail.php on line 90
In line 90 I have: $this->context->smarty->assign('module_dir', $this->_path); which is inside of this function:
public function getContent()
{
/**
* If values have been submitted in the form, process.
*/
if (((bool)Tools::isSubmit('submitClosecustomerthreademailModule')) == true) {
$this->postProcess();
}
$this->context->smarty->assign('module_dir', $this->_path);
$output = $this->context->smarty->fetch($this->local_path.'views/templates/admin/configure.tpl');
return $output.$this->renderForm();
}
This is how I add two forms in the screen (renderForm method): return $helper->generateForm(array($this->getConfigForm(), $this->getTestForm()));
The postProcess. Sorry for pasting so much code, I'm trying to provide all the details I find relevant.
protected function postProcess()
{
if(Tools::isSubmit('test_form')) {
$this->sendTestEmailTo(Tools::getValue('CLOSECUSTOMERTHREADEMAIL_EMAIL_TO_TEST'));
}
elseif(Tools::isSubmit('config_form')) {
$form_values = $this->getConfigFormValues('config_form');
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
}
}
}
The sendTestEmailTo just has an IF statement and then call this function:
public function sendEmail($to_email, $to_name = null){
$id_lang = $this->context->language->id;
$template_dir = _PS_MODULE_DIR_.$this->name.'/views/templates/email/';
$vars = array(
'{html}' => Configuration::get('CLOSECUSTOMERTHREADEMAIL_EMAIL_HTML_BODY'),
'{text}' => Configuration::get('CLOSECUSTOMERTHREADEMAIL_EMAIL_TEXT_BODY')
);
require(_PS_CONFIG_DIR_.'config.inc.php');
require_once(_PS_ROOT_DIR_.'/init.php');
$send = Mail::Send(
(int)$id_lang,
'email',
Configuration::get('CLOSECUSTOMERTHREADEMAIL_EMAIL_SUBJECT'),
$vars,
$to_email,
$to_name,
null,
null,
null,
null,
$template_dir,
false,
(int)$this->context->shop->id,
null
);
return $send;
}
I'm failing to see what could be causing $this->context->smarty to be null. Would you have any tips to help me investigate?
EDIT
The construct method:
public function __construct()
{
$this->name = 'closecustomerthreademail';
$this->tab = 'others';
$this->version = '1.0.0';
$this->author = 'andre';
$this->need_instance = 0;
/**
* Set $this->bootstrap to true if your module is compliant with bootstrap (PrestaShop 1.6)
*/
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Close Customer Thread e-mail');
$this->description = $this->l('Sends an e-mail whenever you close a customer thread');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall this module?');
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
}
I'm glad that you've solved. But I guess that the problem is this:
require(_PS_CONFIG_DIR_.'config.inc.php');
require_once(_PS_ROOT_DIR_.'/init.php');
Remove those lines :), you shouldn't never include that files in a class method.
I couldn't figure out before the delivery so I had to do this to solve, a redirect:
protected function postProcess()
{
if(Tools::isSubmit('test_form')) {
$this->sendTestEmailTo(Tools::getValue('CLOSECUSTOMERTHREADEMAIL_EMAIL_TO_TEST'));
}
elseif(Tools::isSubmit('config_form')) {
$form_values = $this->getConfigFormValues('config_form');
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
}
}
$actual_link = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
Tools::redirectAdmin($actual_link);
}
I am using Yii 1.1 .I have a class file inside widgets folder named MyCommentsTbEditableSaver.
when i try to echo data with in that php file .it doesnot return any thing.
What is the reason behind this?
my code:`
public function insertRps()
{
//get params from request
$this->primaryKey = yii::app()->request->getParam('pk');
$this->attribute = yii::app()->request->getParam('name');
//$this->attribute = yii::app()->request->getParam('comments');
$this->value = yii::app()->request->getParam('value');
//checking params
if (empty($this->attribute)) {
throw new CException(Yii::t('MyCommentsTbEditableSaver.editable', 'Property "attribute" should be defined.'));
}
if (empty($this->primaryKey)) {
throw new CException(Yii::t('MyCommentsTbEditableSaver.editable', 'Property "primaryKey" should be defined.'));
}
$model=new ProjectComments();
$comments=Yii::app()->db->createCommand()
->select('count(project_id) as countProject')
->from('pm_project_comments')
->where("project_id = $this->primaryKey ")
->queryRow();
if($comments['countProject']==0)
{
$model->isNewRecord=TRUE;
$model->comments_rps=$this->value;
$model->project_id=$this->primaryKey;
//also set update details,added by bishal
$model->crtd_by=Yii::app()->user->id;
$model->crtd_dt = date('Y-m-d');
print_r($model);die;
$model->save();
}
}`
I am trying to add some functionality to my shop and have spent the past two days trying to come to grasp with how smarty actually works within prestashop or rather in general.
I have so far made a module that can install, on install it creates a tab on the left menu, I can click on the tab and it will load the controller but this is where i get stuck... I can't figure out how to display custom content within that state.
What i would like is very simple, just a paragraph of text and a button. When clicking the button i will do a few things and record a few things then show the results as a simple report.
So for starters... I'd like to create the page with the paragraph and button.
So i have created a folder in the module diretory called priceupdate
Inside of this there is:
/priceupdate.php
<?php
if (!defined('_PS_VERSION_'))
exit;
class PriceUpdate extends Module
{
public function __construct()
{
$this->name = 'priceupdate';
$this->tab = 'quick_bulk_update';
$this->version = '0.8';
$this->author = 'Me';
$this->need_instance = 0;
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Pricing Update');
$this->description = $this->l('Adds functionality relating to maintaining product my prices.');
$this->confirmUninstall = $this->l('Are you sure you would like to uninstall?');
}
public function install()
{
if (!parent::install()
|| !$this->installModuleTab('AdminPricingUpdate', array(1=>'Pricing Update'), 0))
return false;
return true;
}
public function uninstall()
{
if (!parent::uninstall()
|| !$this->uninstallModuleTab('AdminPricingUpdate', array(1=>'Pricing Update'), 0))
return false;
return true;
}
private function installModuleTab($tabClass, $tabName, $idTabParent)
{
$tab = new Tab();
$tab->name = $tabName;
$tab->class_name = $tabClass;
$tab->module = $this->name;
$tab->id_parent = $idTabParent;
if(!$tab->save())
return false;
return true;
}
private function uninstallModuleTab($tabClass)
{
$idTab = Tab::getIdFromClassName($tabClass);
if($idTab != 0)
{
$tab = new Tab($idTab);
$tab->delete();
return true;
}
return false;
}
}
?>
And
/controllers/admin/AdminPricingUpdateController.php
<?php
class AdminPricingUpdateController extends AdminController
{
public function __construct()
{
$this->lang = (!isset($this->context->cookie) || !is_object($this->context->cookie)) ? intval(Configuration::get('PS_LANG_DEFAULT')) : intval($this->context->cookie->id_lang);
parent::__construct();
}
public function display(){
parent::display();
}
public function renderList() {
return $this->context->smarty->fetch(dirname(__FILE__).'/content.tpl');
}
}
?>
This works however where I am stuck relates to the content.tpl part. What goes inside of this the content.tpl file in order to get it to make a blank page of content within the content area of the admin section?
I've looked through the manual and spent countless hours on forums looking though questions, tried to figure it out by breaking down other modules but i've found it too complex to really understand what is what.
If anyone could help me to understand this or point me to a source of info on this specific subject then it would be greatly appreciated, thanks!
Check that answer
If you need "a blank page of content within the content area of the admin section" you need to make the content.tpl blank.
Note in my example that you do not have to set the name of the template if it's called "content.tpl".
Background:
I have installed the PHP Memcached extension on my live server.
Despite various efforts, I can't seem to install Memcached within my XAMPP development box, so I am relying on the following code to only instantiate Memcached only on the Live server:
My connect file which is included in every page:
// MySQL connection here
// Memcached
if($_SERVER['HTTP_HOST'] != 'test.mytestserver') {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
}
At the moment I am instantiating each method, and I can't help thinking that that there is a better way to acheive my objective and wonder if anyone has any ideas?
My class file:
class instrument_info {
// Mysqli connection
function __construct($link) {
$this->link = $link;
}
function execute_query($query, $server) {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
$result = mysqli_query($this->link, $query) or die(mysqli_error($link));
$row = mysqli_fetch_array($result);
if($server == 'live')
$memcache->set($key, $row, 86400);
} // Close function
function check_something() {
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
$query = "SELECT something from somewhere";
if($_SERVER['HTTP_HOST'] != 'test.mytestserver') { // Live server
$key = md5($query);
$get_result = $memcache->get($key);
if($get_result) {
$row = $memcache->get($key);
} else {
$this->execute_query($query, 'live');
}
} else { // Test Server
$this->execute_query($query, 'prod');
}
} // Close function
} // Close Class
I would suggest that you read up on interface-based programming and dependency injection. Here's some example code that might give you an idea about how you should go about it.
interface CacheInterface {
function set($name, $val, $ttl);
function get($name);
}
class MemCacheImpl implements CacheInterface {
/* todo: implement interface */
}
class OtherCacheImpl implements CacheInterface {
/* todo: implement interface */
}
class InstrumentInfo {
private $cache;
private $link;
function __construct($link, $cache) {
$this->link = $link;
$this->cache = $cache;
}
function someFunc() {
$content = $this->cache->get('some-id');
if( !$content ) {
// collect content somehow
$this->cache->set('some-id', $content, 3600);
}
return $content
}
}
define('IS_PRODUCTION_ENV', $_SERVER['HTTP_HOST'] == 'www.my-real-website.com');
if( IS_PRODUCTION_ENV ) {
$cache = new MemCacheImpl();
} else {
$cache = new OtherCacheImpl();
}
$instrumentInfo = new InstrumentInfo($link, $cache);
BTW. You actually have the same problem when it comes to mysqli_query, your'e making your code dependent on a Mysql database and the mysqli extension. All calls to mysqli_query should also be moved out to its own class, representing the database layer.
I just started studying programming about 6 months ago and I have really been diving deep into Objective-C. Unfortunately, I don't know any programmers IRL to bounce general questions off of.
What languages are being used when people write programs that will search a website for information and then send it back? For example, if I wanted to write a program that would search weather.com for the daily temperature of the last 30 days in a given location and then send it back as say...an NSArray or NSDictionary, how would i do that? Can I do that in Objective C or is that super-advanced scripting language stuff? If I CAN do it in Objective-C, can someone link to a tutorial or place that may get me started learning that type of stuff? (I don't really know the term for this type of programming so my google searches have been unfruitful.)
I most commonly use PHP and MySQL with CURL
http://en.wikipedia.org/wiki/CURL
You can do some fun things like Search Engine Results Page queries, etc.
Here is the source from a crawler I use. I've cut out some parts for anonymity's sake, but it's a good almost-working example. I can help you get it running if need be.
<?php
class Crawler {
protected $markup = '';
protected $uri = '';
protected $db_location = "localhost";
protected $db_username = "***";
protected $db_password = "***";
protected $db_name = "***";
public function __construct() {
ini_set('memory_limit', -1);
}
public function getMarkup() {
$markup = "";
$markup = #file_get_contents($this->uri);
return $markup;
}
public function get($type) {
$method = "_get_{$type}";
if (method_exists($this, $method)){
return call_user_method($method, $this);
}
}
protected function db_query($query) {
$connection = mysql_connect($this->db_location,$this->db_username,$this->db_password) or die(mysql_error());
mysql_select_db($this->db_name,$connection) or die(mysql_error()." >> ".$query);
//echo $query."<br/>"; //for debugging
$result = mysql_query($query,$connection) or die (mysql_error()." >> ".$query);
$i = 0;
if($result != 1)
{
while ($data_array = mysql_fetch_array($result))
{
foreach($data_array as $key => $value)
{
$tableArray[$i][$key] = stripslashes($data_array[$key]);
}
$i++;
}
return $tableArray;
}
}
protected function db_insert($table,$array) {
$tableArray = $this->db_query("show columns from ".$table);
$inputString = "";
foreach($tableArray as $key => $value)
{
if (array_key_exists($value[0], $array) && $value[0]) {
$inputString .= "'".addslashes($array[$value[0]])."', ";
} else {
$inputString .= "'', ";
}
}
$inputString = substr($inputString, 0, -2);
$this->db_query("insert into $table values(".$inputString.")");
return mysql_insert_id();
}
protected function _get_data() {
//$scrape['id'] = $this->get('id');
$scrape['name'] = $this->get('name');
$scrape['tags'] = $this->get('tags');
$scrape['stat_keys'] = $this->get('stat_keys');
$scrape['stat_values'] = $this->get('stat_values');
foreach($scrape['stat_values'] as $key => $value) {
$scrape['stat_values'][$key] = trim($scrape['stat_values'][$key]);
if(strpos($value,"<h5>Featured Product</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"<h5>Featured Company</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"<h5>Featured Type</h5>")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"sign in")) {
unset($scrape['stat_values'][$key]);
}
if(strpos($value,"/100")) {
unset($scrape['stat_values'][$key]);
}
}
if(sizeof($scrape['tags']) > 0 && is_array($scrape['tags'])) {
foreach($scrape['tags'] as $tag) {
$tag_array[$tag] = $tag_array[$tag] + 1;
}
$scrape['tags'] = $tag_array;
foreach($scrape['tags'] as $key => $tag_count) {
$scrape['tags'][$key] = $tag_count - 1;
}
}
$scrape['stat_values'] = array_merge(array(),$scrape['stat_values']);
return $scrape;
}
protected function _get_images() {
if (!empty($this->markup)){
preg_match_all('/<img([^>]+)\/>/i', $this->markup, $images);
return !empty($images[1]) ? $images[1] : FALSE;
}
}
protected function _get_links() {
if (!empty($this->markup)){
preg_match_all('/<a([^>]+)\>(.*?)\<\/a\>/i', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
protected function _get_id() {
if (!empty($this->markup)){
preg_match_all('/\/wine\/view\/([^`]*?)-/', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
protected function _get_grape() {
if (!empty($this->markup)){
preg_match_all('/ class="linked" style="font-size: 14px;">([^`]*?)<\/a>/', $this->markup, $links);
return !empty($links[1]) ? $links[1] : FALSE;
}
}
}
if($_GET['pass'] == "go") {
$crawl = new Crawler();
$crawl->go();
}
?>
So, you want to know how to write server-side code? Well, in theory you can write that in whatever you want. I also assure you it isn't "super-advanced".
You might find it easiest to get started with PHP. W3schools.com has a fine tutorial.
What you are describing is a crawler (e.g. Google).
Any language that has the ability to send HTTP requests and receive responses can do this (which is most languages).
If you don't care to code this thing from scratch, try downloading an open source crawler framework that will allow for custom plugins to parse the resulting HTML.
For your example, you would tell the crawler what site you want it to crawl (i.e. your weather site), add URI constraints if necessary, and create a custom plugin to parse the weather data out of the HTML it responds with. You can then save that data however you see fit.