I'm trying to set some default values in my class but can't use gettext as an variable value
Why does this code give me an error?
class Test
{
private $defaultoptions = array('HideOwnPosts' => false,
'HideClickedLinks' => false,
'AutoCommentLinks' => false,
'AutoCommentText' => gettext('exampletext'),
'AutoOpenCount' => 5);
}
I just need the default value dependend on the users language i use gettext für i18n so i yould like to user ist here too.
http://codepad.org/PTlIelQ4
You cannot initiate a class member with a 'dynamic' result (gettext()). Only static values are allowed. If you need to use the result of a function to initialize a member, then you'll have to do it in the constructor, not the class definition.
Try this:
<?php
class Test
{
private $defaultoptions = array('HideOwnPosts' => false,
'HideClickedLinks' => false,
'AutoCommentLinks' => false,
'AutoCommentText' => false,
'AutoOpenCount' => 5);
public function __construct() {
$this->defaultoptions['AutoCommentText'] = gettext('exampletext');
}
}
Related
I have a class for configuration on my script and I implement the config. I then want to use the options as an object reference like the following, but not sure how to get it all the way to the final object field and also how to make it recognize sub arrays too
class Configuration {
public $cookies = array(
"cookie_prefix" => "site_",
"site_settings" => array(
"domain" => "somesite.com",
"https_only" => TRUE
),
"another_item" => "and some data too"
);
}
$config = new Configuration();
echo $config->cookies->cookie_prefix;
echo $config->cookies->site_settings->domain;
Right now it works if I do the following
echo $config->cookies['cookie_prefix'];
echo $config->cookies['site_settings']['domain'];
But I want it to be an object all the way down. Can't wrap my brain around this one for some reason?
I know this is easily done - I am just missing the way how...
I just passed the items in the __construct as json and its working the way I wanted now, duh.
public $cookies = array(
"cookie_prefix" => "site_",
"site_settings" => array(
"domain" => "somesite.com",
"https_only" => TRUE
),
"another_item" => "and some data too"
);
public function __construct() {
$this->cookies = json_decode(json_encode($this->cookies));
}
I have a private function to return an array of options, those options indicate a callback and other options such as template, form, etc. Here the code:
/**
* #return array
*/
private function options()
{
$options = [
'general' => [
'form' => GeneralConfigType::class,
'template' => 'general.html.twig',
'title' => 'Configuración General',
'ignoreFields' => ['slider', 'social'],
'uploadedFields' => [],
'callbacks' => ['generalData']
],
'business' => [
'form' => ConfigurationType::class,
'template' => 'business.html.twig',
'title' => 'Configuración de Empresa',
'ignoreFields' => [],
'uploadedFields' => ['image','favicon','login_icon','sidebar_icon'],
'callbacks' => ['businessImage']
],
];
return $options;
}
Now here is my doubt, in addition to indicate the function you have to execute in the key callback, Can I pass on the variables I'm going to need in that callback? I've tried several ways and they haven't worked.
Example:
Before:
'callbacks' => ['generalData']
After:
In this example I'm assigning the '$', but I could do it if the only string, I'm just looking for a way to pass to the callback the variables it needs and no more.
'callbacks' => ['generalData' => '$configurationData, $configuration, $form, $request']
And this code would be where everything would be executed in other method:
if (!empty($options[ 'callbacks' ])) {
foreach ($options[ 'callbacks' ] as $callback => $variables) {
$this->$callback($variables);
}
}
If I understand you correctly, you want to store the name of the variable in the array of options and then use that variable in the callback function.
When I've done this type of thing, I find it easier to just store the variable name as text and leave out the $ from the name stored in the array. I then use a variable variable when retrieving it.
Either way, I think you need a little more code on the execution side. One more loop:
if (!empty($options[ 'callbacks' ])) {
foreach ($options[ 'callbacks' ] as $callback => $variables) {
foreach($variables as $variable){ // extra loop to get the variables
$this->$callback[$$variable];
// This is where it gets tricky, and depends on how you wish to format.
// The variables are currently part of an array, thus the array notation
// above. By using the stored name only, and a variable variable, you
// should be able to get to the var you need
}
}
}
#jcarlosweb, what you need to do is very simple. The short answer is that it can be done using the [call_user_func_array()][1] method.
In the context of your example, the callbacks could be rearranges in the following way ...
'callbacks' => ['generalData' => [$configurationData, $configuration, $form, $request]
Basically, the array keys will be the name of the function to call, and the corresponding array values will be a array of the values of each parameter that is accepted but the callback function. Doing it this way is important because you need to capture the value of the parameters while they are in scope. And this will avoid using eval().
Using the callbacks can be as simple as ...
$options = options();
foreach ($options['callbacks'] as $callback => $params) {
$result = call_user_func_array($callback, $params);
// Do something with $result if necessary
}
I finally got it with the function compact http://php.net/manual/en/function.compact.php
Here's the code:
First I select the variables I need in my options:
'callbacks' => ['businessImage' => ['configurationData', 'configuration', 'form', 'request']]
Second I call the variables with compact, but I had to use extract here because if I didn't configurationData variable wasn't modified, which I don't understand since I had previously referenced it.
if (!empty($options[ 'callbacks' ])) {
foreach ($options[ 'callbacks' ] as $callback => $variables) {
$variables = compact($variables);
$this->$callback($variables);
extract($variables);
}
}
Third callback applied and referenced:
/**
* #param array $params
* #return array $configurationData
*/
private function businessImage(&$params)
{
extract($params,EXTR_REFS);
// more code here ......
$configurationData[ "image" ] = $originalImageName;
$configurationData[ "favicon" ] = $originalFaviconName;
$configurationData[ "login_icon" ] = $originalLoginIconName;
$configurationData[ "sidebar_icon" ] = $originalSidebarIconName;
return $configurationData;
}
This works correctly in my website, but as I said before I do not understand why I have to call back the function extract, if I have already passed it referenced in the same callback as you see in my last code.
My general test setup looks something like:
class MySeleniumTest extends PHPUnit_Extensions_SeleniumTestCase{
public static $browsers = array(
array(
'name' => 'Mozilla - Firefox',
'browser' => '*firefox',
'host' => 'localhost',
'port' => 4444,
'timeout' => 30000,
),
array(
'name' => 'Google - Chrome',
'browser' => '*googlechrome',
'host' => 'localhost',
'port' => 4444,
'timeout' => 30000,
)
);
//etc
}
And from here an individual test file looks something like:
class MyTest extends MySeleniumTest{
public function setUp(){
parent::setUp();
$this->setUser(1);
}
public function testPageTitle(){
//Login and open the test page.
$this->login(8);
$this->open('/test/page');
//Check the title.
$this->assertTitle('Test Page');
}
}
From here, when I run MyTest.php with PHPUnit, PHPUnit will automatically run each test case in MyTest.php. Furthermore, it runs each test on each of the specified browsers individually. What I want to be able to do is get information on the driver running a specific test case from within that test case. So something like:
public function testPageTitle(){
//Login and open the test page.
$this->login(8);
$this->open('/test/page');
//Check the title.
$this->assertTitle('Test Page');
$driver = $this->getDriver();
print($driver['browser']); //or something.
}
This however, does not work. And $this->getDrivers() just adds more drivers to the tests, and is only suppose to be used by the setup. Any ideas? Thanks!
Even though $this->drivers is an array there is always only one element in it. You can check that here. So
$this->drivers[0] contains informations about currently running browser and you can use $this->drivers[0]->getBrowser() to output browser name.
Example:
require_once 'MySeleniumTest.php';
class MyTest extends MySeleniumTest{
public function setUp(){
parent::setUp();
$this->setBrowserUrl('http://www.google.com/');
}
public function testPageTitle(){
$this->open('http://google.com');
echo "{$this->drivers[0]->getBrowser()}\n";
}
}
Outputs:
PHPUnit 3.7.18 by Sebastian Bergmann.
.*firefox
.*googlechrome
Time: 7 seconds, Memory: 3.50Mb
OK (2 tests, 0 assertions)
I'd like to assign anonymous functions to arrays in PHP inside of a class, but I keep stumbling over syntax errors.
class Stuff {
private $_preference_defaults = array(
'cookie' => true,
'session' => true,
'database' => true,
'filter' => function($input) { return true; },
'sanitizer' => function($input) { return $input; },
);
};
Will throw an unexpected T_FUNCTION syntax error, and it doesn't matter whether or not the array is static. I got desperate and tried the "old" way of doing it:
class Stuff {
private $_preference_defaults = array(
'cookie' => true,
'session' => true,
'database' => true,
'filter' => create_function('$input', 'return true;'),
'sanitizer' => create_function('$input', 'return $input;'),
);
};
And this led to an unexpected '(', expecting ')' syntax error. However, if I define the functions ahead of time, it does work:
class Stuff {
function _preference_default_filter($input) {
return true;
}
function _preference_default_sanitizer($input) {
return true;
}
private $_preference_defaults = array(
'cookie' => true,
'session' => true,
'database' => true,
'filter' => _preference_default_filter,
'sanitizer' => _preference_default_sanitizer,
);
};
And then I'm able to call those functions within a class method:
function do_stuff($foo) {
return $this->{$this->_preference_defaults['filter']}($foo);
}
Not only is this syntactically sour, in my head it wreaks of poor style and I can imagine this sort of trickery causing headaches in the future.
Am I not able to create an anonymous function at class (static) scope? (I'm thinking maybe because a valid Closure object cannot be created in that context?)
Is there a more... PHP... means to the same end? That is to say, is there a "better" way of assigning trivial default callbacks to array values in class scope? The final snippet I provided gets the job done for sure, but I'd prefer a solution that won't leave me asking the optometrist for a stronger prescription.
Am I not able to create an anonymous function at class (static) scope? (I'm thinking maybe because a valid Closure object cannot be created in that context?)
Yes, because the initial values of class attributes should be known in parsing step, while function call and anonymous function require runtime
Also see here to get the additional details: https://stackoverflow.com/a/9029556/251311
And cannot get your second question :-S
This indeed will not work. During the, lets say, declaration phase you can generally not do much fancy things.
However.. because your properties are just private, and not static.. simply declare everything in the constructor. Problem solved!
This syntax:
'sanitizer' => _preference_default_sanitizer,
Is really bad.. With E_NOTICE on you will actually find it coverts _preference_default_sanitizer to a string first, which is why this may work.
Just set the method name as string.
class Stuff {
private $_preference_defaults = array(
'cookie' => true,
'session' => true,
'database' => true,
'filter' => '_preference_default_filter',
'sanitizer' => '_preference_default_sanitizer',
);
function _preference_default_filter($input) {
return true;
}
function _preference_default_sanitizer($input) {
return true;
}
};
And then call by:
function do_stuff($foo) {
return $this->{$this->_preference_defaults['filter']}($foo);
}
Or
function do_stuff($foo) {
return call_user_func(array($this, $this->_preference_defaults['filter']), $foo);
}
I'm working on a shopping cart (Cart model). One of its protected properties is "_items", which holds an array of Product objects. They (Products) all get stored in DB for populating the session (using ZF, Zend_Session_SaveHandler_DbTable() etc.).
public function addItem(Model_Product $product, $qty)
{
$qty = (int) $qty;
$pId = $product->getId();
if ($qty > 0) {
$this->_items[$pId] = array('product' => $product, 'qty' => $qty);
} else {
// if the quantity is zero (or less), remove item from stack
unset($this->_items[$pId]);
}
// add new info to session
$this->persist();
}
In the controller, I grab a Product obj from DB with the ProductMapper and provide it to "addItem()":
$product1 = $prodMapper->getProductByName('cap');
$this->_cart->addItem($product1, 2);
getProductByName() returns a new populated Model_Product object.
I usually get the
Please ensure that the class definition "Model_Product" of the object you are trying to operate on was loaded _before_ ...
error message, a session dump obviously shows
['__PHP_Incomplete_Class_Name'] => 'Model_Product'
I know about the "declaring the class before serializing it". My problem is this: how can I declare the Product class in addItem(), if it's injected (first param) in the first place? Wouldn't a new declaration (like new Model_Product()) overwrite the param (original object) in addItem()? Must I declare it in the Cart model again?
Besides, I'll surely get a Cannot redeclare class Model_Product if I... redeclare it in Cart.
In ZF's bootstrap, the session was started before autoloading.
/**
* Make XXX_* classes available
*/
protected function _initAutoloaders()
{
$loader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'XXX',
'basePath' => APPLICATION_PATH
));
}
public function _initSession()
{
$config = $this->_config->custom->session;
/**
* For other settings, see the link below:
* http://framework.zend.com/manual/en/zend.session.global_session_management.html
*/
$sessionOptions = array(
'name' => $config->name,
'gc_maxlifetime' => $config->ttl,
'use_only_cookies' => $config->onlyCookies,
// 'strict' => true,
// 'path' => '/',
);
// store session info in DB
$sessDbConfig = array(
'name' => 'xxx_session',
'primary' => 'id',
'modifiedColumn' => 'modified',
'dataColumn' => 'data',
'lifetimeColumn' => 'lifetime'
);
Zend_Session::setOptions($sessionOptions);
Zend_Session::setSaveHandler(new Zend_Session_SaveHandler_DbTable($sessDbConfig));
Zend_Session::start();
}
When I was getting the errors I was talking about, the method declaration was the other way around: _initSession() was first, then _initAutoloaders() - and this was the exact order ZF was processing them.
I'll test some more, but this seems to work (and logical). Thanks for all your suggestions.