Creating default object from empty value- Code igniter - php

Hello I work on codeigniter and I try to eliminate warnings on my website, I block on:
$groups = array();
if ($bannished_groups) {
foreach ($bannished_groups as $k => $bannished_group) {
$groups[$k] = $this->group_model->GetGroupByID($bannished_group->groupid);
$groups[$k]->db = $bannished_group;
}
}
I have the error:
Creating default object from empty value
I tried to declare:
$groups[$k]->db = new stdClass();
but it does not work and i read the other answers but it does not help me ..

It seems like the method $this->group_model->GetGroupByID($bannished_group->groupid); don't always return an object, even if you think it does :-)
If it returns null, an empty string or false, you will get that error.
Just check it before you try and use it:
foreach ($bannished_groups as $k => $bannished_group) {
// Get the object
$obj = $this->group_model->GetGroupByID($bannished_group->groupid);
if (!is_object($obj)) {
// It's not an object, skip it and move on to the next
continue;
}
$groups[$k] = $obj;
$groups[$k]->db = $bannished_group;
}
This will make sure that your $groups-array only contains objects. If you still want to add it to the array regardless, just store the object directly in $groups[$k] instead of in the $obj-variable. The logic is the same, though.

Related

Calling methods on object gets 'call to member function on array' error

I inherited this project from my predecessor, and he was way overqualified. A lot of stuff he wrote goes over my head. But as far as vanilla php goes, I'm pretty confident, and can't for the life of me figure out why the application thinks the object I created is an array. Maybe I don't actually know anything. You tell me.
use via\zoom\Bulletin;
use via\zoom\DatabaseConnection;
require_once('includes/config.php');
require_once(CORE .'sql.php');
require_once(CORE . 'model.php');
require_once(CORE . 'bulletin.php');
// If we've passed the validation step we can guarantee we have a valid $active_user
validate();
//run if a page deletion has been requested
if (isset($_GET['delpage'])) {
$del = $_GET['delpage'];
$bulletin = new Bulletin;
$bulletin = Bulletin::get($del);
if(!empty($bulletin))
{
$bulletin->delete();
/*
So.
For some reason, the above object is cast as an array.
If you try to cast it as an object, it defaults to stdClass.
On the left we have a method complaining that it can't work outside of its class. Hard stop, array to method exception.
On the right we have an object with all the right data, but set to the wrong class, so it can't find the delete method at all. Hard stop, undefined method exception.
*/
//this is the workaround, pulled the script straight from the delete method in the model class
/*$dbh = DatabaseConnection::get();
$query_string = "DELETE FROM brochure_generator_bulletin WHERE id = $del";
try {
$dbh->query($query_string);
//return true;
} catch (\Exception $e) {
//return false;
}*/
}
header('Location: bulletins');
exit();
}
Here's the get method from the Bulletin class, extends Model--
public static function get( ...$ids )
{
$matches = parent::get( ...$ids );
foreach( $matches as &$match )
{
$match->content = json_decode( $match->content );
}
return $matches;
}
And here's the delete method from the Model Class:
public function delete()
{
if (isset($this->id)) {
$dbh = DatabaseConnection::get();
$query_string = "DELETE FROM {$this->table_name} WHERE id = \"{$this->id}\"";
try {
$dbh->query($query_string);
return true;
} catch (\Exception $e) {
return false;
}
}
return false;
}
What am I missing? Is he using a framework I'm not familiar with? I'm utterly grasping at straws here, and at this point my options are grab all the method scripts and stick them where they need to be inline, or just starting over from the ground up.
You don't need to create a new Bulletin object before using the static get() method, so you can remove this:
$bulletin = new Bulletin;
That $bulletin variable is immediately overwritten by the next line anyway.
$bulletin = Bulletin::get($del);
get() takes one or more ids and returns an array of one or more corresponding objects. You're giving it one id and expecting one object back, but it's still going to return that object inside an array. You just need to get the object out of the array so you can call its delete method.
if(!empty($bulletin))
{
$bulletin = reset($bulletin); // get the first item in the array
$bulletin->delete();
You could also review the model and see if it has a different method that returns a single object rather than an array of objects.

better way to avoid call to a member function

I need to know if there is a better way to avoid Call to a member function xxxx() on null
currently I'm coding as follows but it is cumbersome.
if($event->getForm()
&& $event->getForm()->getParent()
&& $event->getForm()->getParent()->getParent()
&& $event->getForm()->getParent()->getParent()->getData()
&& $event->getForm()->getParent()->getParent()->getData()->getComponente()
){
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 7 this is actually a catchable Error (if you're using hhvm it's a regular Exception):
try {
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
} catch (\Error $e) {
$componente = null;
}
if ($componente !== null) {
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 5 there is a workaround using intermediate variables and the and keyword instead of &&:
if (
$f = $event->getForm() and
$p = $f->getParent() and
$p2 = $p->getParent() and
$d = $p2->getData() and
$componente = $d->getComponente()
) {
$formModifier($f, $componente, $defaultComponente);
}
If you use && instead of and you'll get "undefined variable" notices and this workaround won't work.
Working examples: https://3v4l.org/0S6ps
no there is no way, but at least you can do some performance improvement
$form = $event->getForm();
if(!$form){
//do error handling
return;
}
$parent = $form->getParent();
if(!$parent){
//do error handling
return;
}
$p_parent = $parent->getParent();
if(!$p_parent){
//do error handling
return;
}
$data = $p_parent->getData();
if(!$data){
//do error handling
return;
}
$component = $data->getComponente();
...
this way you call each function only once and you can do better error handling
I think this is a great example of a bad code. By having a code like this you're breaking several rules and making your life much harder than it should be.
Your code is rigid, fragile, hard to understand and maintain etc.
Simpler is ALWAYS better.
If you can't make your $xx->getComponent() a proper object easily accessible without such ugly nested relationship, you should at least encapsulate the method into something appropriate and use that instead, so if anything changes, you don't have to go full mental and change it all over the place.
This class seems strange in it's creation, but if you are not extracting these methods dynamically using __call(), you can use method_exists() in a loop inside a function, something similar to:
function getMethodChain($class,$arr = ['getForm','getParent','getParent','getData','getComponente'])
{
# First check the object is set
if(!is_object($class))
return false;
# Loop intended method chain
foreach($arr as $method) {
# Check if the method exists in the current class or passed already
$useClass = (!isset($classPass))? $class : $classPass;
# Check if the method exists in the current class
if(is_object($useClass) && method_exists($useClass,$method)) {
# Assign this class/method to use next in the loop
$classPass = $useClass->{$method}();
}
else
return false;
}
# Just send back
return (isset($classPass))? $classPass : false;
}
The use would be something like:
# This will either be the data you expect or false
$componente = getMethodChain($event);

Amazon MWS (PHP) - Report Request API functions return without data, no error thrown

I am currently working with the Amazon MWS to integrate some features into wordpress via a plugin. I am using the client libraries provided by amazon found here:
https://developer.amazonservices.com/api.html?group=bde&section=reports&version=latest
Using these client libraries and the sample php files included I have set up my plugin to make two API calls. The first is requestReport
public function requestInventoryReport() {
AWI_Amazon_Config::defineCredentials(); // Defines data for API Call
$serviceUrl = "https://mws.amazonservices.com";
$config = array (
'ServiceURL' => $serviceUrl,
'ProxyHost' => null,
'ProxyPort' => -1,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebService_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
$config,
APPLICATION_NAME,
APPLICATION_VERSION);
$request = new MarketplaceWebService_Model_RequestReportRequest();
$request->setMerchant(MERCHANT_ID);
$request->setReportType('_GET_MERCHANT_LISTINGS_DATA_');
self::invokeRequestReport($service, $request);
}
private function invokeRequestReport(MarketplaceWebService_Interface $service, $request) {
try {
$response = $service->requestReport($request);
if ($response->isSetRequestReportResult()) {
// Print Out Data
}
} catch (MarketplaceWebService_Exception $ex) {
// Print Out Error
}
}
and the second is getReportRequestList which has code similar to the first function. I am able to run these functions without any errors. The issue that I am having is that $response->isSetRequestReportResult() returns false. From my understanding and looking into the response object, this would suggest that the response object does not have the result. (Upon printing out the response object I can see that the FieldValue of the result array is NULL.) The call, however, does not throw an error but neither does it have the result.
I did some digging through the code and found that the result does actually get returned from the api call but never gets set to the return object when the library attempts to parse it from XML. I've tracked the error down to this block of code (This code is untouched by me and directly from the amazon mws reports library).
private function fromDOMElement(DOMElement $dom)
{
$xpath = new DOMXPath($dom->ownerDocument);
$xpath->registerNamespace('a', 'http://mws.amazonaws.com/doc/2009-01-01/');
foreach ($this->fields as $fieldName => $field) {
$fieldType = $field['FieldType'];
if (is_array($fieldType)) {
if ($this->isComplexType($fieldType[0])) {
// Handle Data
} else {
// Handle Data
}
} else {
if ($this->isComplexType($fieldType)) {
// Handle Data
} else {
$element = $xpath->query("./a:$fieldName/text()", $dom);
$data = null;
if ($element->length == 1) {
switch($this->fields[$fieldName]['FieldType']) {
case 'DateTime':
$data = new DateTime($element->item(0)->data,
new DateTimeZone('UTC'));
break;
case 'bool':
$value = $element->item(0)->data;
$data = $value === 'true' ? true : false;
break;
default:
$data = $element->item(0)->data;
break;
}
$this->fields[$fieldName]['FieldValue'] = $data;
}
}
}
}
}
The data that should go into the RequestReportResult exists at the beginning of this function as a node in the dom element. The flow of logic takes it into the last else statement inside the foreach. The code runs its query and returns $element however $element->length = 13 in my case which causes it to fail the if statement and never set the data to the object. I have also looked into $element->item(0) to see what was in it and it appears to be a dom object itself matching the original dom object but with a bunch of empty strings.
Now, I'm new to working with the MWS and my gut feeling is that I am missing a parameter somewhere in my api call that is messing up how the data is returned and is causing this weird error, but I'm out of ideas at this point. If anyone has any ideas or could point me in the right direction, I would greatly appreciate it.
Thanks for your time!
** Also as a side note, Amazon Scratchpad does return everything properly using the same parameters that I am using in my code **
These works for me, check if you are missing anything.
For RequestReportRequest i am doing this:
$request = new MarketplaceWebService_Model_RequestReportRequest();
$marketplaceIdArray = array("Id" => array($pos_data['marketplace_id']));
$request->setMarketplaceIdList($marketplaceIdArray);
$request->setMerchant($pos_data['merchant_id']);
$request->setReportType($this->report_type);
For GetReportRequestList i am doing this:
$service = new MarketplaceWebService_Client($pos_data['aws_access_key'], $pos_data['aws_secret_access_key'], $pos_data['config'], $pos_data['application_name'], $pos_data['application_version']);
$report_request = new MarketplaceWebService_Model_GetReportRequestListRequest();
$report_request->setMerchant($pos_data["merchant_id"]);
$report_type_request = new MarketplaceWebService_Model_TypeList();
$report_type_request->setType($this->report_type);
$report_request->setReportTypeList($report_type_request);
$report_request_status = $this->invokeGetReportRequestList($service, $report_request, $report_requestID);

PHP # foreach warning

I have a PHP foreach from an array, the array is given to me by my DB provider via a soap web service so I cannot change the array I get. When there are no elements to return, I get an empty array, this results in
Warning: Invalid argument supplied for foreach()
the loop looks like
foreach (($point1['return']) as $val)
Where can I put an # to stop this warning, and if I cant, what I do I do to turn off php warnings.
Hiding the warning is not the right way. You should check whether it exists and is an array.
if (is_array($point1['return'])) {
foreach ($point1['return'] as $val) {
...
}
}
PHP is_array()
Actually, turning off warnings or using the # operator is not the right way to go 99% of the time.
Solve the problem instead of hiding it.
foreach() can handle not only arrays but also objects by either using the the default "all visible properties" implementation or a custom implementation via the traversable/iterator interface.
And a "DB provider via a soap web service" is something where I'd keep an eye on the possibility of (suddenly) having an object/iterator instead of a plain array.
So, if you're going to test the existence and data type before passing the variable to foreach, you should consider not only testing for is_array() but also for instanceof Traversable.
<?php
class Foo implements Iterator {
protected $v = 0;
public function current() { return $this->v; }
public function key() { return $this->v; }
public function next() { ++$this->v; }
public function rewind() { $this->v=0; }
public function valid() { return 10>$this->v; }
}
//$a = array(1,2,3,4);
$a = new Foo;
if( is_array($a) || $a instanceof Traversable ) {
foreach($a as $e) {
echo $e, "\n";
}
}
An empty array does not cause that error, the problem is that you are trying to iterate trough something that is not an array. You could add a check using is_array function.
Better to let errors display but check that the input is an array first. So you could wrap the foreach in an if, like this:
if ((is_array($point1)) && (is_array($point1['return']))) {
foreach (($point1['return']) as $val)
...
}
Check first for an array:
if(is_array($point1['return']))
{
...
}
You can also explicitly cast the argument to array:
foreach ((array) $point1['return'] as $val) {
Note: this still will issue undefined index, if there is no 'return' key in $point1
Check whether that is actually an array. with is_array(); !!
There's no need to suppress the warning.
As a matter of fact, It's not possible to suppress that invalid argument warning.
Paste this into your function file:
set_error_handler(function($errno, $errstr){
if(stristr($errstr,'Invalid argument supplied for foreach()')){
return true;
}
return false;
});

check if object exists in Cloud Files (PHP API)

I've just started working with the PHP API for Rackspace Cloud Files. So far so good-- but I am using it as sort of a poor man's memcache, storing key/value pairs of serialized data.
My app attempts to grab the existing cached object by its key ('name' in the API language) using something like this:
$obj = $this->container->get_object($key);
The problem is, if the object doesn't exist, the API throws a fatal error rather than simply returning false. The "right" way to do this by the API would probably be to do a
$objs = $this->container->list_objects();
and then check for my $key value in that list. However, this seems way more time/CPU intensive than just returning false from the get_object request.
Is there a way to do a "search for object" or "check if object exists" in Cloud Files?
Thanks
I sent them a pull request and hope it'll get included.
https://github.com/rackspace/php-cloudfiles/pull/35
My pull-request includes an example, for you it would be similar to this:
$object = new CF_Object($this->container, 'key');
if ($object->exists() === false) {
echo "The object '{$object->name}' does not exist.";
}
I have more general way to check if object exists:
try {
$this->_container->get_object($path);
$booExists = true;
} catch (Exception $e) {
$booExists = false;
}
If you dump the $object, you'll see that content_length is zero. Or, last modified will be a zero length string.
Example:
$object = new CF_Object($container, 'thisdocaintthere.pdf');
print_r($object->content_length);
There is also, deep in the dumped parent object, a 404 that will return, but it's private, so you'd need to some hackin' to get at it.
To see this, do the following:
$object = new CF_Object($container, 'thisdocaintthere.pdf');
print_r($object->container->cfs_http);
You'll see inside that object a response_status that is 404
[response_status:CF_Http:private] => 404
I know I'm a little late to the party, but hopefully this will help someone in the future: you can use the objectExists() method to test if an object is available.
public static function getObject($container, $filename, $expirationTime = false)
{
if ($container->objectExists($filename)) {
$object = $container->getPartialObject($filename);
// return a private, temporary url
if ($expirationTime) {
return $object->getTemporaryUrl($expirationTime, 'GET');
}
// return a public url
return $object->getPublicUrl();
}
// object does not exist
return '';
}
Use like...
// public CDN file
$photo = self::getObject($container, 'myPublicfile.jpg');
// private file; temporary link expires after 60 seconds
$photo = self::getObject($container, 'myPrivatefile.jpg', 60);
If you do not want to import opencloud to perform this check you can use the following:
$url = 'YOUR CDN URL';
$code = FALSE;
$options['http'] = array(
'method' => "HEAD",
'ignore_errors' => 1,
'max_redirects' => 0
);
$body = file_get_contents($url, NULL, stream_context_create($options));
sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);
if($code!='200') {
echo 'failed';
} else {
echo 'exists';
}

Categories