PHP function as parameter default - php

Take the following function for example:
private function connect($method, $target = $this->_config->db()) {
try {
if (!($this->_pointer = #fopen($target, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}
As you can see I inserted the function $this->_config->db() into the parameter $target as it's default value. I understand this is not the correct syntax and am just trying to explain my aim.
$this->_config->db() is a getter function.
Now I know I can use an anonymous function and call it via $target later, but I want $target to also accept direct string values.
How could I give it a default value of the whatever is returned by $this->_config->db() and still be able to overwrite it with a string value?

Why not accept NULL values by default (test with is_null()) and if so call your default function?

You can use is_callable() and is_string().
private function connect($method, $target = NULL) {
if (is_callable($target)) {
// We were passed a function
$stringToUse = $target();
} else if (is_string($target)) {
// We were passed a string
$stringToUse = $target;
} else if ($target === NULL) {
// We were passed nothing
$stringToUse = $this->_config->db();
} else {
// We were passed something that cannot be used
echo "Invalid database target argument";
return;
}
try {
if (!($this->_pointer = #fopen($stringToUse, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}

I would perform a check to see if a value was passed and call my function in a simple check inside the method:
private function connect($method, $target = '') {
try {
if ($target === '') {
$target = $this->_config->db()
}
if (!($this->_pointer = #fopen($target, $method))) {
throw new Exception("Unable to connect to database");
}
} catch (Exception $e) {
echo $e->getMessage();
}
}

Related

Codeigniter 3: Can't catch database error using try catch block

I'm working on an api, it handles the requests which comes from clients, then gets the response from server(developed using codeigniter 3) and forwards that back to client.
But, in case of any database errors, like duplicate id, or null values, the model class cannot handle that error to display a proper error message. I've tried the try catch block but not succeeded yet.
Here's the model:
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
throw new Exception("Database error:");
return false;
}
return TRUE;
} catch (Exception $e) {
log_message('error: ',$e->getMessage());
return;
}
}
One thing to mention, I've set db_debug to FALSE.
Any help would be appreciated.
As for CI 3, below code gets database error code and error message. db_debug is set to FALSE.
public function add() {
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
$this->db->trans_complete();
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable retrun statement !!!
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related errors. But it will include them, because this is more general.
log_message('error: ',$e->getMessage());
return;
}
}
Refer to documentation at https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
saying
If you need to get the last error that has occurred, the error() method will return an array containing its code and message.
It is a bit incomplete in my opinion because it does not show error code and error message in the example code.
I just lost an hour trying to figure out why I can't get the error in my code. You have to check for an error after each statement! Working solution:
function insertUpdate($data) {
$order = $data->order;
$order_products = $data->order_products;
$this->db->trans_start();
$order->user_id = $this->session->user_id;
$error = "OK";
if (!$this->db->insert('_order', $order)) {
$error = $this->db->error()["message"];
}
$id = $this->db->insert_id();
foreach ($order_products as $row) {
$row->order_id = $id;
if (!$this->db->insert('_order_product', $row)) {
$error = $this->db->error()["message"];
break;
}
}
$order_code = substr(md5($id), 0, 6);
if (!$this->db->where('order_id', $id)) {
$error = $this->db->error()["message"];
}
if (!$this->db->update('_order', ["order_code" => $order_code])) {
$error = $this->db->error()["message"];
}
$this->db->trans_complete();
return [
'result' => $error, 'order_code' => $order_code
];
}
Suggestion in above code
Remove line $this->db->trans_complete();
If we see $this->db->error() after completing transaction it will be always empty
Remove semicolon - log_message('error :',$e->getMessage());
return;
public function add()
{
try {
$this->db->trans_start(FALSE);
$this->db->insert('users', $preparedData);
// documentation at
// https://www.codeigniter.com/userguide3/database/queries.html#handling-errors
// says; "the error() method will return an array containing its code and message"
$db_error = $this->db->error();
if (!empty($db_error)) {
throw new Exception('Database error! Error Code [' . $db_error['code'] . '] Error: ' . $db_error['message']);
return false; // unreachable return statement !!!`enter code here`
}
return TRUE;
} catch (Exception $e) {
// this will not catch DB related `enter code here`errors. But it will include them, because this is more general.
log_message('error ',$e->getMessage());
return;
}
}

PDO PHP Update Script not working

I've searched on stackoverflow and other sources but I cant seem to find the issue that is preventing my PHP script from working.
Look at the echo_sql. It produces a healthy update statement which when run updates the database with no problem. Here is a sample:
update waste set waste_name=1 where id =82;
However, when the script is run, it does not apply changes to the database. Here is the script:
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
$sql->bind(':waste_name', $waste_name);
$sql->execute();
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}
}
Additional details:
errorCode() = 00000
DB Class:
class db
{
private $stmt;
private $dbc;
public function __construct()
{
$u = "root";
$p = "";
try {
$this->dbc = new PDO('mysql:host=127.0.0.1;dbname=wimsdb', $u, $p);
$this->dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$e->getMessage();
}
}
public function bind($param, $value, $type = NULL)
{
$this->stmt->bindParam($param, $value, $type);
}
public function beginTransaction()
{
return $this->dbc->beginTransaction();
}
public function rollBack()
{
return $this->dbc->rollBack();
}
public function endTransaction()
{
return $this->dbc->commit();
}
public function cancelTransaction()
{
return $this->dbc->rollBack();
}
public function execute()
{
try {
return $this->stmt->execute();
} catch (PDOException $e) {
return $e->errorInfo;
}
}
public function errorCode()
{
return $this->stmt->errorCode();
}
public function query($query)
{
$this->stmt = $this->dbc->prepare($query);
}
}
Please offer your suggestions on how this could be resolved.
You need to bind the :waste_id too:
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$sql->bind(':waste_name', $waste_name);
$sql->bind(':waste_id', $waste_id);
Any time you have an issue like this your error checking should return a meaningful message letting you know where the error is and likely what the error is. You should be able to check your error logs for details and/or output them to your screen during testing.
Add waste_id. To avoid missing parameters, I like putting the parameteers into the execute method. The bind method could be defined anywhere in the code so I had to look through your code and make sure waste_id binding wasn't defined somewhere else. When it's in the execute method, you can quickly see all parameters being defined there...it's also a tad more concise...but both have their uses.
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
//just because I like this syntax for being concise and clear :)
$sql->execute(array(
'waste_id' => $waste_id,
'waste_name' => $waste_name
));
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}

How to save embedded forms in symfony 1?

I have a form which represnts single answer object (this is standard propel generated form I have not changed much there only some validation rules) and another form that represents a collection of answers code as below:
class BbQuestionAnswersForm extends sfForm {
public function __construct($defaults = array(), $options = array(), $CSRFSecret = null) {
parent::__construct($defaults, $options, $CSRFSecret);
}
public function configure() {
if (!$questions = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need array of BbExamQuestion objects.');
}
if (!$taker = $this->getOption('taker')) {
throw new InvalidArgumentException('The form need BbExamtaker object.');
}
if (!$user = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need sfGuardUser object.');
}
foreach($questions as $question) {
$answer = new BbExamAnswer();
$answer->setBbExamQuestion($question);
$answer->setBbExamTaker($taker);
$answer->setCreatedBy($user);
$answer->setUpdatedBy($user);
$form = new BbExamAnswerForm($answer, array('question' => $question));
$this->embedForm($question->getId(), $form);
}
$this->widgetSchema->setNameFormat('solve[%s]');
}
}
Everything(validation, display) goes fine with this form until I try to save it. Part of action which trying to save the form:
...
$this->form = new BbQuestionAnswersForm(null, array('questions' => $this->questions, 'taker' => $this->taker, 'user' => $this->getUser()->getGuardUser()));
if($request->isMethod('post')) {
$this->form->bind($request->getParameter($this->form->getName()));
if($this->form->isValid()) {
if($this->form->save()) {
$this->getUser()->setFlash('success', 'Save goes fine.');
$this->redirect($this->generateUrl('#bb'));
} else {
$this->getUser()->setFlash('error', 'Upps an error occurred.');
}
}
}
When I send valid form I receive "Call to undefined method BbQuestionAnswersForm::save()" error.
I tried to write this method like this:
public function save() {
$conn = Propel::getConnection(ZlecPeer::DATABASE_NAME);
$conn->beginTransaction();
try{
foreach($this->getEmbeddedForms() as $form) {
$form->save();
}
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
echo 'upps something goes wrong';
die($e->getMessage());
return false;
}
return true;
}
but it doesnt work, I receive exception without any message.
What am I doing wrong, how to make save method work?
I believe your BbQuestionAnswersForm is extending the wrong object. It should extend BaseFormDoctrine or possibly BaseBbQuestionAnswersForm if you are using the framework correctly.
Edit: Just noticed you are using propel but it should be the same thing. Try:
class BbQuestionAnswersForm extends BaseBbQuestionAnswersForm
and less likely:
class BbQuestionAnswersForm extends BaseFormPropel
Save method should looks like this:
public function save($con = null) {
if (null === $con) {
$con = Propel::getConnection(BbExamAnswerPeer::DATABASE_NAME);
}
$con->beginTransaction();
try{
foreach($this->embeddedForms as $name => $form) {
if(!isset($this->values[$name]) || !is_array($this->values[$name])) {
continue;
}
if($form instanceof sfFormObject) {
$form->updateObject($this->values[$name]);
$form->getObject()->save($con);
$form->saveEmbeddedForms($con);
} else {
throw new Exception('Embedded form should be an instance of sfFormObject');
}
}
$con->commit();
} catch(Exception $e) {
$con->rollBack();
throw $e;
return false;
}
return true;
}

set was executed successfully in redis but get nothing

I'm using phpredis in my program, store something in the redis server, get them when the same request comes(in the same day), but I always get empty result. Can anyone give me some enlightenment? Here is the code of Cache class I'm using:
<?php
class Cache
{
public static function getInstance()
{
static $instance = null;
null == $instance && $instance = new self();
return $instance;
}
protected function __construct()
{
}
protected function getR()
{
static $r = NULL;
if (NULL == $r) {
$r = new Redis();
try {
$r->pconnect(HOST, PORT, 5);
} catch(Exception $ex) {
//log
try {
$api->connect(HOST, PORT, 5);
} catch (Exception $ex) {
//log
}
}
}
return $r;
}
public function getValue($key)
{
$result = array();
$r = $this->getR();
if(!empty($r)) {
try{
$result = $r->hKeys($key);
$r->setTimeout($keys, 86400);
} catch (Exception $ex){
//log
}
}
return $result; // return true
}
public function setValue($key, $value)
{
$result = false;
$r = $this->getR();
if(!empty($r)) {
try{
$result = $r->hMset($key, $value);
} catch (Exception $ex){
//log
}
}
}
}
?>
EDIT:
I checked the key-values with redis-cli, found something wired: the key-value data was stored in db 5 while I thought it should be in DB 0 by default without select statement, but the program retrieved db 0, of course nothing returned. Now I'm wondering why the data went to DB 5 given that I've not selected DB.
Finally, I've figured out what happend here. Before I stored my key–value pair, there was some code which also had communicated with Redis server and it had explicitly selected the DB 5, and the default DB of my redis connection was affected by last context, so my data was stored in DB 5. By coincidence, when I wanted to retrive my data, the last redis connection used DB 0, of course I got nothing.

PHP pass an object via a function

I have this function that returns a json object:
function getMyFbEvents() {
global $facebook;
try {
$fb_events = $facebook->api('/me/events/');
foreach ($fb_events["data"] as $fb_event_data) {
$event_info = json_decode(file_get_contents('https://graph.facebook.com/' . $fb_event_data['id'] . '/?access_token=' . $facebook->getAccessToken()));
return $event_info;
}
} catch (FacebookApiException $e) {
error_log($e);
$fb_events = null;
return null;
}
}
Now if I want to call that object from another page of the script by calling the relative function, how do I do it?
I mean if I want to loop now $event_info as if it I was inside that function and get each given data, is there a way?
Maybe it may sound a bit "too much" :)
First of instead of returning from within the loop you need to accumulate all of the values then return
function getMyFbEvents() {
global $facebook;
try {
$fb_events = $facebook->api('/me/events/');
$eventDetails = array();
foreach ($fb_events["data"] as $fb_event_data) {
$event_info = json_decode(file_get_contents('https://graph.facebook.com/' . $fb_event_data['id'] . '/?access_token=' . $facebook->getAccessToken()));
$eventDetails[] = $event_info;
}
return $eventDetails;
} catch (FacebookApiException $e) {
error_log($e);
$fb_events = null;
return null;
}
}
Then when you want to use it just say (make sure you include_once the file that implements getMyFbEvents if it is in a different php file.)
$events = getMyFbEvents();
forearch($events as $event){
echo $event->description;
}
On a side note using the global keyword is considered bad practice. A cleaner implementation would just pass in the $facebook variable as a parameter to the function
function getMyFbEvents($facebook) {
try {
//..... the rest of your function
Then to call just
$var = getMyFbEvents($facebook);

Categories