I can't access variables created dynamically in a function or method of my objects in PHP. It is probably a matter of scope, but I do not know why this happens as in JavaScript when you declare a var inside a function you can still access it outside that function.
What I'm doing is this:
#code
...
$inputs = ['olympiad', 'test_type', 'year', 'level', 'country', 'test', 'answersheet'];
$Form = new Form;
$Form->addFields($inputs);
foreach (array_keys($Form->fields) as $key) {
${"$key"} = $Form->fields["$key"];
}
$olympiad->required(true)->type('select')->inValues($olyimpiadsArray)->label('Olmpíada')->errorMessage('some error message here');
$test_type->required(true)->type('select')->inValues($testTypeArray)->errorMessage('bla bla');
$level->required(true)->type('select')->inValues(['Nacional', 'Regional'])->label('Nível')->errorMessage('sample error message');
$year->required(true)->type('int')->range(1998, 2019)->label('Ano')->errorMessage('another error message');
$country->required(true)->type('string')->range(4, 64)->label('País')->errorMessage('these arent the real error messages');
$test->type('file')->label('Prova')->allowedExtensions(['pdf'])->errorMessage('bla bla');
$answersheet->type('file')->label('Gabarito')->allowedExtensions(['pdf'])->errorMessage('bla bla bla');
That works because the Fields are objects and they are passed as reference, so I can access these objects through the created variables inside the foreach and the Form will also be able to validate the Field objects.
I'm using the same foreach in many webpages, so it is quite awkward because I'm copying and pasting the code, again and again.
EXPECTED RESULTS
What do I want? I want to do this:
Class Form {
#code
...
public function create_vars_for_fields() {
foreach(array_keys($this->fields) as $key) {
${"$key"} = $this->fields["$key"];
}
return $this;
}
}
Then, on my PHP webpages I shoul be able to do this:
require_once 'Form.php';
$inputs = ['olympiad', 'test_type', 'year', 'level', 'country', 'test', 'answersheet'];
$Form = new Form;
$Form->addFields($inputs)->create_vars_for_fields();
#code
...
//here I should be able to access my variables, which are now objects of the class Fields
echo $test_type->value; //should echo the test type of the olympiad, which is equal to $_POST['test_type']
echo $country->value; //should echo the country of the olympad, which is equal to $_POST['country']
However, the code above throws many errors saying that these variables are undefined.
Notice: Undefined variable: olympiad in C:\xampp\htdocs\projects\phpFormBuilder\tests\TestValidation.php on line 8
Fatal error: Uncaught Error: Call to a member function required() on null in C:\xampp\htdocs\projects\phpFormBuilder\tests\TestValidation.php:8 Stack trace: #0 C:\xampp\htdocs\projects\phpFormBuilder\tests\AddTest.php(3): require_once() #1 {main} thrown in C:\xampp\htdocs\projects\phpFormBuilder\tests\TestValidation.php on line 8
Line 8 is the line I say $olympiad->required(true)
How can I access these variables by creating them dynamically in a function or method?
I finally found a smart, clear way to accomplish this! The solution uses extract built-in function.
Although I do not need it anymore because I'm using Laravel for validation, I still want to share the answer so it can help others.
SOLUTION
Class Form {
#code
...
public function getFieldsCompacted() {
$compactedFields = [];
foreach(array_keys($this->fields) as $key) {
$compactedFiels["$key"] = $this->fields["$key"];
}
return $compactedFields;
}
}
Then, on the code:
require_once '/path/to/Form.php';
$inputs = ['olympiad', 'test_type', 'year', 'level', 'test', 'answer_sheet'];
$Form = new Form;
$Form->addFields($inputs);
extract($Form->getFieldsCompacted());
This way I can do:
$olympiad->required(true)->type('select')->inValues($olyimpiadsArray)->label('Olimpíada')->errorMessage('some error message here');
$test_type->required(true)->type('select')->inValues($testTypeArray)->errorMessage('bla bla');
$level->required(true)->type('select')->inValues(['Nacional', 'Regional'])->label('Nível')->errorMessage('sample error message');
$year->required(true)->type('int')->range(1998, 2019)->label('Ano')->errorMessage('another error message');
$test->type('file')->label('Prova')->allowedExtensions(['pdf'])->errorMessage('bla bla');
$answersheet->type('file')->label('Gabarito')->allowedExtensions(['pdf'])->errorMessage('bla bla bla');
Instead of doing:
$Form->fields['olympiad']->required(true)->type('select')->inValues($olyimpiadsArray)->label('Olimpíada')->errorMessage('some error message here');
$Form->fields['test_type']->required(true)->type('select')->inValues($testTypeArray)->errorMessage('bla bla');
$Form->fields['level']->required(true)->type('select')->inValues(['National', 'State'])->label('Nível')->errorMessage('sample error message');
$Form->fields['year']->required(true)->type('int')->range(1998, 2019)->label('Ano')->errorMessage('another error message');
$Form->fields['test']->type('file')->label('Prova')->allowedExtensions(['pdf'])->errorMessage('bla bla');
$Form->fields['answersheet']->type('file')->label('Gabarito')->allowedExtensions(['pdf'])->errorMessage('bla bla bla');
Edit:
RiggsFolly pointed out the insecurity of using extract. I totally agree that using extract in $_POST and $_GET. However, this is not the case here because the variables to extract are defined as you can see in
$inputs = ['olympiad', 'test_type', 'year', 'level', 'test', 'answer_sheet'];. So, the extract will only extract these variables and it won't override other variables. Therefore, no risk in the code above.
Related
I am writing a simple router class which would allow you to execute a function when a route match is found. So, when you are defining routes, you would do something like this:
$message = 'Good morning!';
$router->addRoute('GET', 'welcome', function($message) {
echo $message;
});
Then, in the router class, this gets added to an array like:
public function addRoute($method, $pattern, $handler) {
$this->routes[$pattern] = ['method' => $method, 'handler' => $handler];
}
Once a match is found by comparing the pattern with the requested URL, I have:
return call_user_func($setting['handler']);
This gives me an error: Fatal error: Uncaught ArgumentCountError: Too few arguments to function
...so I tried using:
return call_user_func_array($setting['handler'], array($message));
...but this gives me: Notice: Undefined variable: message
How can I pass a function (including arguments, if existing) to execute within the router class using values stored on an array?
If you don't want to pass $message as an argument at call time, it should not be in the function parameter list. You're probably just looking to use the variable from the surrounding scope:
$message = 'Good morning!';
$router->addRoute('GET', 'welcome', function () use ($message) {
echo $message;
});
how to define function name (in PHP) using variable, like this?
$a='myFuncion';
function $a() {.......}
or like that?
The only way I know to give a fixed name to a function is to use eval, which I would not suggest.
More likely, what you want is to stuff a function IN a variable, and then just call that.
Try this:
$a = function() {
echo 'This is called an anonymous function.';
}
$a();
EDIT:
If you want to be accessible from other files, then use GLOBAL variable:
$GLOBALS['variable_name'] = 'my_func_123';
${$GLOBALS['variable_name']} = function() {
echo 'This is called an anonymous function.';
};
// Executing my_func_123()
${$GLOBALS['variable_name']}();
See also: http://php.net/manual/en/functions.anonymous.php
Trying to crate objects dynamically for a plug in system (work in progress)
heres my code using $this->module->load_module('test'); to use the method that creates the dynamic objects. Following code is the function that loads the class's and makes use of an auto loader, i have checked that its getting the correct file etc.
<?php
class BaseModule {
function __construct() {
}
function load_module($module){
echo 'Module = '.$module.'<br />';
$object_name = $module . "Controller";
$this->$$module = new $object_name();
}
}
Here is a test module that it would load when invoking $this->module->load_module('test'); and it creates the object outputting the test strings via echo statements. Heres the code for the test module that was constructed. Which should cause no problems as there is not really a solution but just an output string, but posted any way.
<?php
class testController {
function __construct() {
echo 'test controller from modules <br />';
}
}
However when running the page i am getting some errors can any one help out?
Notice: Undefined variable: test in
/Applications/MAMP/htdocs/tealtique/application/modules/BaseModule.php on line 11
Fatal error: Cannot access empty property in
/Applications/MAMP/htdocs/tealtique/application/modules/BaseModule.php on line 11
I am learning Zend Framework (2.0), and I'm stuck at creating forms.
Here is the code I used (Inside a controller):
use Zend\Form\Element;
use Zend\Form\Form;
...
public function indexAction()
{
$element = new Element\Text('name');
//Nothing else
}
It always gives a 505 error, but if I comment out the line "$element ..." then it works (so the problem must be there).
Can someone point out what I have overlooked?
Also, as I see it, there are too many ways to create a form. For example, I have tried:
private function getSignupForm() {
//Create Form
$form = new Zend_Form();
$form->setAction('success');
$form->setMethod('post');
$form->setAttrib('sitename', 'mysite');
//Add Elements
//Create Username Field.
$form->addElement('text', 'username');
$usernameElement = $form->getElement('username');
$usernameElement->setLabel('Username:');
$usernameElement->setOrder(1)->setRequired(true);
return $form;
}
This way, it worked, but that is not the way the tutorial says link. So in which way should I should write it?
Thanks.
I created a contact form on my classified ads website.
I use the following function to get the uploader email :
public function uploadermail()
{
return $this->User_id?$this->User->email:lang('anonymous');
}
It works fine and I get the result using an echo :
<?php echo $image->uploadermail(); ?>
Then I use a function to send the mail :
public static function sendmail_anon()
{
$form = new Form('sendmail_anon');
$form->field('email', 'text', array
(
'valid_email' => true
));
$form->field('message', 'textarea', array
(
'min_length' => 25
));
if($data = $form->validate())
{
$envoi = array
(
'message' => $data['message'],
'email' => $data['email']
);
mail($data['email'], lang('account_details'), lang('email_contact', $envoi), 'From: noreply#'.$_SERVER['HTTP_HOST']);
}
return $form;
}
The problem is that this is sending the mail to the e-mail from the form field.
I would like to replace $data['email'] and insert the uploadermail instead. I tried :
mail($image->uploadermail(), lang('account_det.....
And it returns the following error :
Fatal error: Call to a member function uploadermail() on a non-object
Is it possible to do and how should I writte it exactly ?
I tried :
mail($uploadermail,....
And it doesn't returns errors, but didn't received any mail, how can I check what exactly contains $uploadermail on the browser ?
This means that $image is not an class instance. So you cannot do $image->uploadermail().
You can check it out by doing: var_dump($image);
After posting your full code I see you are accessing that function from public static function sendmail_member():
mail($image?$image->uploadermail():$data['email'], lang('account_details'), lang('email_contact', $envoi), 'From: noreply#'.$_SERVER['HTTP_HOST']);
However $image is never declared (/ instantiated) in that scope. Upon further investigation I see that there is a method called uploadermail in the correct class which I guess you are trying to access.
So to access that method you should do:
self::uploadermail()
or
$this->uploadermail()
PS
You should really try to prevent using statics. Static stuff are basically globals and they tightly couple you code and it prevent the L in SOLID programming.
You should instantinate an object for $image before usage! e.g.
$image = new ...
or
$image = x.GetImage(...