I am dynamically creating a msword document in PHP using PHPDocx (free version).
I am having trouble get a table to centre align in the page. I have tried passing in the style parameters as stated in the documentation, but no joy.
Any ideas on how to fix this?
My current code is;
$docx = new CreateDocx();
$valuesTable = array(
array(
11,
12
),
array(
21,
22
),
);
$paramsTable = array(
'jc' => 'center',
'border' => 'single',
'border_sz' => 20
);
$docx->addTable($valuesTable, $paramsTable);
$docx->createDocx('example_table');
I had the same problem. If you looking at CreateTable source you can see that method for aligning generateJC() is never called so passing a 'jc' parameter has no effect (this is the same with most of the options).
You can override this creating a new class like:
class SmCreateTable extends CreateTable{
public function createTable()
{
$this->_xml = '';
$args = func_get_args();
if (is_array($args[0])) {
$this->generateTBL();
$this->generateTBLPR();
if(!empty($args[1]['jc'])){
$this->generateJC($args[1]['jc']);
}
$this->generateTBLW();
if (!empty($args[1]['border'])) {
$this->generateTBLBORDERS();
$this->generateTBLBOTTOM();
$this->generateTBLLEFT();
$this->generateTBLTOP();
$this->generateTBLRIGHT();
$this->generateTBLINSIDEH();
$this->generateTBLINSIDEV();
}
$this->generateTBLLOOK();
$this->generateTBLOVERLAP();
$intLine = 0;
foreach ($args[0] as $datDepth) {
$this->generateTR();
$intLine++;
foreach ($datDepth as $cont) {
$this->generateTC();
$this->generateP();
$this->generateR();
if ($args[1]['font'] != '') {
$this->generateRPR();
$this->generateRFONTS($args[1]['font']);
}
$this->generateT($cont);
}
$this->cleanTemplateR();
}
}
}
private function cleanTemplateR()
{
$this->_xml = preg_replace('/__GENERATETR__/', '', $this->_xml);
}
}
and then calling:
$table = new SmCreateTable();
$table->createTable($valuesTable, $paramsTable);
Related
I am auto loading php classes from different folders by using namespace.I use namespace and use to get the desired class name.But there happening a problem requiring the classes files as i am using new WP_Query() class within a class and that function also wants to include WP_Query() class.
Below is the code.. from plugin index.php
namespace WPSEVENT;
use WPSEVENT\includes\Shortcode;
spl_autoload_register(__NAMESPACE__ . '\\autoload');
function autoload($class = '') {
if (!strstr($class, 'WPSEVENT')) {
return;
}
$result = str_replace('WPSEVENT\\', '', $class);
$result = str_replace('\\', '/', $result);
require $result . '.php';
}
and the shortcode class in includes folder..
namespace WPSEVENT\includes;
/**
*
*/
class Shortcode
{
public static $instance;
public static function smartEventShortCode($atts){
$vars = extract(shortcode_atts(
array(
'columns' => 4,
'style' => 1,
'posts_per_page' => 1,
), $atts ));
$paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
$eventargs = array(
'posts_per_page' => $posts_per_page,
'post_type' => WP_SEVENT_SLUG,
'paged' => $paged,
);
$posts = new WP_Query($eventargs);
$html = '<div class="row">';
if($posts->have_posts()){
while ($posts->have_posts()) {
$posts->the_post();
switch ($style) {
case '1':
//$html .= self::getStyleOne( $columns, $postdata );
break;
}
}
}
$html .= '</div>';
return $html;
}
}
And the error i am getting
Fatal error: Class 'WPSEVENT\includes\WP_Query' not found
What i expect is to exclude the WP_Query class
Try:
new \WP_Query($eventargs);
Or alternatively you can set this at the top of your template (after declaring namespace):
use WP_Query;
More info here.
Basically, WP_Query is part of the Global namespace, if you don't tell PHP this, it will try to find the class (WP_Query) in the current namespace it's being called from.
On the backend of a PrestaShop site I'm using this function:
public function hookAjax($action, $id_product, $id_lang, $title, $descript, $order, $id = NULL)
{
/* various code*/
$this->context->smarty->assign(
array(
'block_define' => $this->getFormDesc($id_product)
)
);
return $this->context->smarty->fetch($this->local_path.'views/templates/hook/admin_extra_desc.tpl');
}
public function getFormDesc($id_product) {
$array = array();
foreach (Language::getLanguages() as $lang) {
/*various code*/
foreach($result as $k=> $r) {
$files = array();
$helper = new HelperImageUploader();
$helper->setMultiple(false)->setUseAjax(true)->setName('thumbnail_'.$r['id'].'_'.$r['id_lang'])->setFiles($files)->setMaxFiles(3)->setUrl('../modules/module-name/imgAjaxCall.php?');
$result[$k]['img-form'] = $helper->render();
$result[$k]['img'] = $result[$k]['img'] ? _PS_BASE_URL_.__PS_BASE_URI__.'modules/module-name/upload/'.$result[$k]['img'] : '';
}
$array[$lang["id_lang"]] = array(
'lang_data' => $lang,
'count' => count($result),
'data' => $result
);
}
return $array;
}
HookAjax is called by:
<?php
include(dirname(__FILE__).'/../../config/config.inc.php');
$context = Context::getContext();
$addDesc = Module::getInstanceByName('module-name');
echo $addDesc->hookAjax($_POST['action'],$_POST['id_prodotto'],$_POST['lang'],$_POST['title'], $_POST['text_desc'], NULL, $_POST['row']);
?>
But I struggle with this error:
Fatal error: Call to a member function addJs() on a non-object in {my_site}/classes/helper/HelperUploader.php on line 257
You need to include init.php in HookAjax after including config.inc.php so that controller is initialized in context.
include(dirname(__FILE__).'/../../init.php');
Note that this is just bad practice, respect the MVC and use proper controllers for your AJAX calls and data validation/processing in them, not inside main module class.
I would like to create the following using class syntax:
$resp = new stdclass;
$resp->CategoryListResp->category[0]->categoryId = 1;
$resp->CategoryListResp->category[0]->categoryName = "Spel";
$resp->CategoryListResp->category[0]->iconUri = "PictoSpel.png";
$resp->CategoryListResp->category[1]->categoryId = 2;
$resp->CategoryListResp->category[1]->categoryName = "Transport";
$resp->CategoryListResp->category[1]->iconUri = "PictoTransport.png";
Should be easy but I cannot find the syntax for this.
I will later output $resp in json format. I am aware I can also use arrays for this...
The json output shall be:
{"CategoryListResp":{"category":[{"categoryId":1,"categoryName":"Spel","iconUri":"PictoSpel.png"},{"categoryId":2,"categoryName":"Transport","iconUri":"PictoTransport.png"}]}}
You can also make your classes more explicit:
class Category {
public $categoryId = 0, $categoryName = '', $iconUri = '';
}
class Resp {
public $categoryListResp = null;
public function __construct() {
$this->categoryListResp = new CategoryListResp();
}
}
class CategoryListResp {
public $category = array();
}
$resp = new Resp();
$resp->categoryListResp->category[0]->categoryId = 1;
$resp->categoryListResp->category[0]->categoryName = "Spel";
$resp->categoryListResp->category[0]->iconUri = "PictoSpel.png";
// etc.
ADDED (based on henq's comment). To fully utilize the class concept you would need to add some methods to the classes. Then you would not use -> for arrays, but call the respective methods. E.g.
class Category {
public $categoryId = 0, $categoryName = '', $iconUri = '';
public function __construct($id, $name, $icon) {
$this->categoryId = $id;
$this->categoryName = $name;
$this->iconUri = $icon;
}
}
class Resp {
public $categoryListResp = null;
public function __construct() {
$this->categoryListResp = new CategoryListResp();
}
public function addCategory($index, $id, $name, $icon) {
$this->categoryListResp->addCategory($index, $id, $name, $icon);
}
}
class CategoryListResp {
public $category = array();
public function addCategory($index, $id, $name, $icon) {
$this->category[$index] = new Category($id, $name, $icon);
}
}
$resp = new Resp();
$resp->addCategory(0, 1, "Spel", "PictoSpel.png");
$resp->addCategory(1, 2, "Transport", "PictoTransport.png");
// etc
You can modify this concept according to your needs.
You're almost there already:
$resp = new stdClass();
$resp->CategoryListResp = new stdClass();
$resp->CategoryListResp->category[0]->categoryId = 1;
$resp->CategoryListResp->category[0]->categoryName = "Spel";
$resp->CategoryListResp->category[0]->iconUri = "PictoSpel.png";
$resp->CategoryListResp->category[1]->categoryId = 2;
$resp->CategoryListResp->category[1]->categoryName = "Transport";
$resp->CategoryListResp->category[1]->iconUri = "PictoTransport.png";
print_r(json_encode($resp));
/*
output:
{"CategoryListResp":{"category":[{"categoryId":1,"categoryName":"Spel","iconUri":"PictoSpel.png"},{"categoryId":2,"categoryName":"Transport","iconUri":"PictoTransport.png"}]}}
*/
Just send $resp to json_encode. Your code should work as is, however. It's better design to create class definitions for CategoryListResp and Category, rather than just using stdClass.
Arrays are the simpler way to go (as suggested by #felix-kling)
This is how the code ended up:
$resp = array(
'CategoryListResp' => array(
'category' => array(
array(
'categoryId' => 1,
'categoryName' => 'Spel',
'iconUri' => 'PictoSpel.png'
),
array(
'categoryId' => 2,
'categoryName' => 'Transport',
'iconUri' => 'PictoTransport.png'
),
),
),
);
print json_encode($resp);
Clean and simple.
Is there a way to instantiate a new PHP object in a similar manner to those in jQuery? I'm talking about assigning a variable number of arguments when creating the object. For example, I know I could do something like:
...
//in my Class
__contruct($name, $height, $eye_colour, $car, $password) {
...
}
$p1 = new person("bob", "5'9", "Blue", "toyota", "password");
But I'd like to set only some of them maybe. So something like:
$p1 = new person({
name: "bob",
eyes: "blue"});
Which is more along the lines of how it is done in jQuery and other frameworks. Is this built in to PHP? Is there a way to do it? Or a reason I should avoid it?
the best method to do this is using an array:
class Sample
{
private $first = "default";
private $second = "default";
private $third = "default";
function __construct($params = array())
{
foreach($params as $key => $value)
{
if(isset($this->$key))
{
$this->$key = $value; //Update
}
}
}
}
And then construct with an array
$data = array(
'first' => "hello"
//Etc
);
$Object = new Sample($data);
class foo {
function __construct($args) {
foreach($args as $k => $v) $this->$k = $v;
echo $this->name;
}
}
new foo(array(
'name' => 'John'
));
The closest I could think of.
If you want to be more fancy and just want to allow certain keys, you can use __set() (only on php 5)
var $allowedKeys = array('name', 'age', 'hobby');
public function __set($k, $v) {
if(in_array($k, $this->allowedKeys)) {
$this->$k = $v;
}
}
get args won't work as PHP will see only one argument being passed.
public __contruct($options) {
$options = json_decode( $options );
....
// list of properties with ternary operator to set default values if not in $options
....
}
have a looksee at json_decode()
The closest I can think of is to use array() and extract().
...
//in your Class
__contruct($options = array()) {
// default values
$password = 'password';
$name = 'Untitled 1';
$eyes = '#353433';
// extract the options
extract ($options);
// stuff
...
}
And when creating it.
$p1 = new person(array(
'name' => "bob",
'eyes' => "blue"
));
I've created several helper functions which I use when creating templates for Wordpress.
An example is this:
function the_related_image_scaled($w="150", $h="150", $cropratio="1:1", $alt="", $key="related" )
The problem is, if I only want to pass along the $alt parameter, I also have to populate $w, $h and $cropratio.
In one of my plugins, I use the following code:
function shortcode_display_event($attr) {
extract(shortcode_atts(array(
'type' => 'simple',
'parent_id' => '',
'category' => 'Default',
'count' => '10',
'link' => ''
), $attr));
$ec->displayCalendarList($data);
}
This allows me to call the function only using e.g.count=30.
How can I achieve the same thing in my own functions?
SOLUTION
Thanks to my name brother (steven_desu), I have come up with a solution that works.
I added a extra function (which I found on the net) to create value - pair from a string.
The code looks as follows:
// This turns the string 'intro=mini, read_more=false' into a value - pair array
function pairstr2Arr ($str, $separator='=', $delim=',') {
$elems = explode($delim, $str);
foreach( $elems as $elem => $val ) {
$val = trim($val);
$nameVal[] = explode($separator, $val);
$arr[trim(strtolower($nameVal[$elem][0]))] = trim($nameVal[$elem][1]);
}
return $arr;
}
function some_name($attr) {
$attr = pairstr2Arr($attr);
$result = array_merge(array(
'intro' => 'main',
'num_words' => '20',
'read_more' => 'true',
'link_text' => __('Read more')
), $attr);
extract($result);
// $intro will no longer contain'main' but will contain 'mini'
echo $intro;
}
some_name('intro=mini, read_more=false')
Info
With good feedback from Pekka, I googled and found some info regarding the Named Arguments and why it's not in PHP: http://www.seoegghead.com/software/php-parameter-skipping-and-named-parameters.seo
I would suggest using array_merge() and extract() at the beginning of your function, then passing parameters as arrays if this is a possibility.
function whatever($new_values){
$result = array_merge(array(
"var1" => "value1",
"var2" => "value2",
"var3" => "value3"
), $new_values);
extract($result);
echo "$var1, $var2, $var3";
}
whatever(array("var2"=>"new_value"));
The above will output:
value1, new_value, value3
it's a bit sloppy and uses more memory since it has to allocate the arrays, so it's the less efficient solution. But it does allow you to avoid redundancy. I'm sure a better method exists using magic meta-code, but I can't think of it off-hand.
Say this is your function:
function related_image_scaled($w="150", $h="150", $alt="", $key="related")
You can do this:
class ImageScaleParams {
public $w = 150;
public $h = 150;
public $cropratio = "1:1";
public $alt = "";
public $key = "related";
}
function related_image_scaled(ImageScaleParams $params) { ... }
Then call it like this:
$imgscale = new ImageScaleParams();
$imgscale.alt="New Alt";
related_image_scaled($imgscale);
You can also have various factories in ImageScaleParams such as:
class ImageScaleParams {
static function altFactory($alt) {
$imgscale = new ImageScaleParams();
$imgscale->alt = $alt;
return $imgscale;
}
}
Which you could call like this (equivalent to previous example):
related_image_scaled(ImageScaleParams::altFactory("New Alt"));
New Answer:
Could you not write the function using the extract function's default EXTR_OVERWRITE option?
function the_related_image_scaled($params) {
$w="150"; $h="150"; $cropratio="1:1"; $alt=""; $key="related";
extract($params);
//Do Stuff
}
Called with:
the_Related_image_scaled(array("alt"=>"Alt Text"));
You have the option of defaulting the parameters to null and only using them if they are not null:
function the_related_image_scaled($w=null, $h=null, $cropratio=null, $alt=null, $key = null) {
$output = //Get the base of the image tag
//including src leave a trailing space and don't close
if($w!==null) {
$output .= "width=\"$w\"";
}
//... Through all your parameters
return $output;
}
So only passing the alt parameter would look like:
echo the_related_image_scaled(null,null,null,$alt);