PHP - simplyfy the code - something like MVC part - php

Im .NET programmer, but totally new in PHP. Im fighting with this for hours.
I need to simplyfy data transfer from interface to database. I have something like this:
$default = new stdClass();
// default values - all of them should be set to default value
// some of them will be overwritten later, but only one of them
$default->{'val-string'} = ''; // default values start
$default->{'val-int'} = 0;
$default->{'val-float'} = 0;
$default->{'val-image'} = ' ';
$default->{'val-datetime'} = 0;
$default->{'val-boolean'} = false; // default values end
$container = array();
$row = clone $default;
$row->{'field_id'} = 1;
$row->{'field_name'} = $nameoffield1;
$row->{'val-string'} = 'Diffrent types are filled for diffrent rows';
$container[] = $row;
$row = clone $default;
$row->{'field_id'} = 2;
$row->{'field_name'} = $nameoffield2;
$row->{'val-int'} = $valueoffield2;
$container[] = $row;
$row = clone $default;
$row->{'field_id'} = 3;
$row->{'field_name'} = $nameoffield3;
$row->{'val-datetime'} = current_time();
$container[] = $row;
// there
// is
// a lot
// of these
//rows
$result = $database->insertContainer($db_session, $container);
At the end need something like that "pseudocode .NET mixed with php"
list_of_rows.AddItem(makeRow($field_id1, $name1, (int)$dataforint)));
list_of_rows.AddItem(makeRow($field_id2, $name2, (string)$dataforstring));
list_of_rows.AddItem(makeRow($field_id3, $name3, (date)$datafordate));
list_of_rows.AddItem(makeRow($field_id4, $name4, (boolean)$dataforboolean));
$result = $database->insertContainer($db_session, list_of_rows);
If overloading like this is not possible (or very complicated) in PHP - i will be happy if someone give me any better solution than mine code at the top.

This a possible approach. You can also use the __call method to achieve this. This is just a quick example. Either this, or you might use an ORM like propel to achieve something similair. It really depends on what the task is.
class Row_Builder {
protected $default = array();
public function __construct() {
$this->default['field_id'] = null;
$this->default['field_name'] = null;
$this->default['val-string'] = null;
$this->default['val-int'] = null;
$this->default['val-float'] = null;
$this->default['val-image'] = null;
$this->default['val-datetime'] = null;
$this->default['val-boolean'] = false;
return;
}
public function setValues() {
// we only need the fist argument in this case.
$params= func_get_arg(0);
if(isset($params)) {
foreach($params as $key => $value) {
if(array_key_exists($key,$this->default)) {
$this->default[$key] = $value;
}
}
}
}
public function __get($key) {
if(array_key_exists($key, $this->default)) {
return $this->default[$key];
}
}
}
$row = new Row_Builder;
$row->setValues(array('field_id' => 1, 'field_name' => 'some value', 'val-string' => 'here is a str value'));
print $row->field_name;

Related

PHP 7.4 Warning: Creating default object from empty value

The apache error logs are filling up with this. I don't want to suppress all errors though, and understand I need to create an object explicitly somewhere but the syntax escapes me.
Warning: Creating default object from empty value in
libraries/cegcore2/libs/helper.php on line 22
class Helper {
use \G2\L\T\GetSet;
var $view = null;
var $_vars = array();
var $data = array();
var $params = array();
function __construct(&$view = null, $config = []){
$this->view = &$view;
$this->_vars = &$view->_vars; // <---- Line 22
$this->data = &$view->data;
if(!empty($config)){
foreach($config as $k => $v){
$this->$k = $v;
}
}
}
}
The problem is that assuming view is null, you should not refer its items. You can do it like this:
function __construct(&$view = null, $config = []){
$this->view = &$view;
if ($view) {
$this->_vars = $view->_vars; // <---- Line 22
$this->data = $view->data;
}
if(!empty($config)){
foreach($config as $k => $v){
$this->$k = $v;
}
}
}

multiple calls to $stmt->bind_param

I'm in a situation where I want to build a code which gets $bindParam variable in this format:
$bindParams = [$type1 => $param1, $type2 => $param2, ... ]
I wanna build some code that dynamically adds that parameters to the prepared statement.
This is the code which I built so far :
$mysql = new mysqli("localhost", "root", "", "db1");
$stmt = $mysql->prepare($sql);
foreach($bindParams as $type => $data) {
$stmt->bind_param($type, $data);
}
$stmt->execute();
$result = $stmt->get_result();
// and after perhaps twiddling with the result set, but this is not the case .....
For your instance
$sql = "INSERT INTO table1 (name, age) VALUES (?,?);"
and
$bindParams = ["s" => "hello", "i" => 15]
This does not always have this structure and it can change to for example $bindParams = ["s" => "hello", "i" => 15, "d" => 22.5] and so the $sql changes respectively.
After the first time the compiler heads to $stmt->bind_param($type, $data); firefox flushes this error:
Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in D:\PHP\tr.php on line 23
I know PDO support that as stated here at the end of the page. but perhaps as you might expect Im not a fan of PDO so ;)
My other option is to use the eval() workarounds available in php but thats out of what I might think of.
Is there another way to do this?
I had the same problem, and found an answer much simplier:
$array_of_values = array( "Brasil", "Argentina" );
$types = "ss";
$mysqli_stmt->bind_param( $types, ...$array_of_values );
This is called "argument unpacking", and is available since PHP 5.6
http://php.net/manual/pt_BR/migration56.new-features.php
Sadly mysqli doesn't support this. Calling the function over and over again overwrites the values, so you're only binding one param when you clearly have more.
There's a couple of ways to get around this
Switch to PDO. You can make one bind per function call with that
Bind the params as one aggregate using call_user_func_array
$sqltype = '';
$sqldata = [];
foreach($bindParams as $type => $data) {
$sqltype .= $type;
$sqldata[] = &$data; // MUST be a reference
}
array_unshift($sqldata, $sqltype); // prepend the types
call_user_func_array([$stmt, 'bind_param'], $sqldata);
I use something like this to do dynamic procedure calls.
Example Call:
$mapi = new MySQLIAPI($con);
$mapi->BeginProc();
$mapi->AddParameter("user", $usern, "s");
$mapi->AddParameter("email", $email, "s");
$mapi->AddParameter("passwd", $pwd, "s");
$id = $mapi->CallProc("ij_create_user");
$id = $id[0];
if(isset($id['mysql_error']) || isset($id["error"])){
return "error";
}
return $id["id"];
Example Class:
class MySQLIAPI
{
private $con = null;
private $Variables = null;
private $values = null;
private $types = null;
private $vQu = null;
private $stmt = null;
function __construct($dbc)
{
$this->con = $dbc;
$this->Variables = [];
$this->values = [];
$this->types = [];
$this->vQu = [];
}
function BeginProc()
{
$this->stmt = $this->con->stmt_init(); // initialize statement
}
function AddParameter($key, $val, $type)
{
$this->Variables[] = "#" . $key;
$this->values[] = $val;
$this->types[] = $type;
$this->vQu[] = "?";
}
//KeyPair is v = the value, t = the type s or d
function CallProc($Proc) {
$out_var = null;
$call = "";
if(sizeof($this->values) > 0)
$call = "CALL ".$Proc."(".implode(",", (array)$this->vQu).")";
else
$call = "CALL ".$Proc."()";
if($this->stmt->prepare($call));//call stored procedure with database server session variable
{
if(sizeof($this->values) > 0) {
$params = array_merge(array(implode("", $this->types)), $this->values);
call_user_func_array(array($this->stmt, 'bind_param'), $this->refValues($params));
}
$this->stmt->execute();
$result = $this->stmt->get_result();
/* Error Checking */
$mySQLiError = mysqli_stmt_error($this->stmt);
if ($mySQLiError != "") {
$this->resetStmt();
$this->stmt->close();
$this->stmt = null;
return array('mysql_error' => $mySQLiError);
}
while ($row = $result->fetch_array(MYSQLI_ASSOC))
{
$out_var[] = $row;
}
$result->free();
while($this->stmt->more_results())
{
$this->stmt->next_result();
}
$this->resetStmt();
$this->stmt->close();
$this->stmt = null;
}
return $out_var;
}
private function refValues($arr)
{
if (strnatcmp(phpversion(), '5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach ($arr as $key => $value)
$refs[$key] =& $arr[$key];
return $refs;
}
return $arr;
}
private function resetStmt()
{
//Reset Params
$this->Variables = array();
$this->values = array();
$this->types = array();
$this->vQu = array();
}
}

Entity metadata wrapper

i'm getting error with metadata wrapper.
i have a field test => entity reference multiple which is a selection list.I get the following Error EntityMetadataWrapperException : Invalid data value given. Be sure it matches the required data type and format.
$account = entity_load_single('user', $user->uid);
$acc_wrapper = entity_metadata_wrapper('user', $account);
$list = $acc_wrapper->test->value();
$exists = FALSE;
if (!empty($list)) {
foreach ($list as $item) {
if ($item->nid == $form_state['storage']['node']->nid) {
$exists = TRUE;
break;
}
}
}
if (!$exists) {
if (!$list) {
$list = array();
$list[] = $form_state['storage']['node']->nid;
}
$acc_wrapper->test->set($list);
$acc_wrapper->save();
1rst quick tips
$account = entity_load_single('user', $user->uid);
$acc_wrapper = entity_metadata_wrapper('user', $account);
You don't need to load the entity unless you need it loaded after (Or it's already loaded). All you need is the id, and let entity_metadata_wrapper magic operate.
$acc_wrapper = entity_metadata_wrapper('user', $user->uid);
I think your error is here
if (!$list) {
$list = array();
$list[] = $form_state['storage']['node']->nid;
}
$list is always initiated because of "$list = $acc_wrapper->test->value();", so you never fullfill the condition, and then you are trying to set it back and save it (because you are missing a '}' )... Makes no sense...
Could try this version ?
$acc_wrapper = entity_metadata_wrapper('user', $user->uid);
$list = $acc_wrapper->test->value();
$exists = FALSE;
if (!empty($list)) {
foreach ($list as $item) {
if ($item->nid == $form_state['storage']['node']->nid) {
$exists = TRUE;
break;
}
}
}
if (!$exists && !$list) {
$list = array($form_state['storage']['node']->nid);
$acc_wrapper->test = $list;
$acc_wrapper->save();
}

I'm passing too many parameters

I'm passing a lot of parameters in a function
I want to know if its wrong what i am doing and if it is possible to put all those variables into an array and just call the array:
Here my function parameters:
function addjo($logo, $job_category, $job_name, $status, $localization, $job_type, $contract_type, $description)
My code to recognize all the variables.
if (isset($_POST['add_jo'])){
$job_category =$_POST['job_category'];
$description = $_POST['description'];
$job_name = $_POST['job_name'];
$logo = $_POST['logo'];
$status = $_POST['status'];
$localization = $_POST['localization'];
$job_type = $_POST['job_type'];
$contract_type = $_POST['contract_type'];
addjo($logo, $job_category, $job_name, $status, $localization, $job_type, $contract_type, $description);
}else{
$logo = NULL;
$job_category = NULL;
$job_name = NULL;
$status = NULL;
$localization = NULL;
$description = NULL;
$job_type = NULL;
$contract_type = NULL;
$check1 = NULL;
$check2 = NULL;
}
Is it possible to do something like this?
if(isset($_POST['mybutton'])){
array[](
$var1 = $_POST['var1'];
$var2 = $_POST['var2'];
);
function(callarrayhere);
else{
$var1 = null;
$var2 = null;
}
Thanks.
Since $_POST is already an array, just use it:
addjob($_POST);
And in addjob:
function addjob($input) {
// verify that array items are present and correct.
}
Exporting an array's values to individual variables is not only a waste of time and memory, but it also makes your code harder to read (where do these variables come from? It's not obvious they came from the same source array)
Of course it's possible:
if (isset($_POST['add_jo'])){
$a = array();
$a['job_category'] =$_POST['job_category'];
$a['description'] = $_POST['description'];
// and so on
$a['contract_type'] = $_POST['contract_type'];
addjo($a);
}
else
{
$a['job_category'] = null;
// and so on
}
And in function addjo you can display all values that way:
function addjo($a) {
foreach ($a as $k => $v) {
echo $k.' '.$v."<br />"
}
// or
echo $a['job_category'];
}
Yes it is possible to have an array as an argument to a function. Your syntax isn't quite right. This would do it:
function addjo($params){
echo $params['logo'];
echo $params['job_category'];
echo $params['job_name'];
}
Usage example:
$arr = array(
'logo' => $logo,
'job_category' => $job_category,
'job_name' => $job_name
);
addjo($arr);
You could also have default parameters for each of the array elements, or make them optional. See this answer for how to do that.

Need some help to determine the amount of recursive calls in PHP

I've got a, I think fairly easy question, but this is bugging me for a while now. So I figured, maybe I can get some help here.
Since recursive functions are always a bit tricky, and sometimes a bit unclear to me, I keep struggling to create a nice working solution to get my menudata.
In one of my classes I have this function, which gives me all menu-items recursively.
The thing I want is to determine at which recursion level a certain object was retrieved so I can create a nicely looking HTML output with indents for the levels of nesting.
public function GetObjectList($parentID = 0, $objectlist = null)
{
if(is_null($objectlist))
{
$objectlist = new ObjectList("Model_Navigation");
}
$query = MySQL::Query("SELECT * FROM `Navigation` WHERE `WebsiteID` = ".SITE_ID. " AND `LanguageID` = ".LANG_ID." AND `ParentID` = ".$parentID);
while($result = MySQL::FetchAssoc($query))
{
$object = new Model_Navigation();
$object->ID = $result["ID"];
$object->WebsiteID = $result["WebsiteID"];
$object->LanguageID = $result["LanguageID"];
$object->ParentID = $result["ParentID"];
$object->Name = $result["Name"];
$object->Page = Model_Page::GetObjectByID($result["PageID"]);
$object->ExternalURL = $result["ExternalURL"];
$object->Index = $result["Index"];
$object->Level = [here lies my problem];
$objectlist->Add($object);
self::GetObjectList($object->ID, $objectlist);
}
return $objectlist;
}
public function GetObjectList($parentID = 0, $objectlist = null, $level = 1)
{
if(is_null($objectlist))
{
$objectlist = new ObjectList("Model_Navigation");
}
$query = MySQL::Query("SELECT * FROM `Navigation` WHERE `WebsiteID` = ".SITE_ID. " AND `LanguageID` = ".LANG_ID." AND `ParentID` = ".$parentID);
while($result = MySQL::FetchAssoc($query))
{
$object = new Model_Navigation();
$object->ID = $result["ID"];
$object->WebsiteID = $result["WebsiteID"];
$object->LanguageID = $result["LanguageID"];
$object->ParentID = $result["ParentID"];
$object->Name = $result["Name"];
$object->Page = Model_Page::GetObjectByID($result["PageID"]);
$object->ExternalURL = $result["ExternalURL"];
$object->Index = $result["Index"];
$object->Level = $level;
$objectlist->Add($object);
self::GetObjectList($object->ID, $objectlist, $level+1);
}
return $objectlist;
}
Why don't you just add a parameter to the function call that stores the number of calls. At the first call just make that 0, increment the value inside the function and use it in the recursive call.

Categories