I am occasionally getting the PHP Fatal error: Call to undefined method stdClass::transition() in agent.php on line 25 (I marked line 25 in the code). This code is called often, so struggling to see why it is happening.
Here is the snippet of agent.php that calls the
function agent_exam_complete($exam){
$ce = $exam->educational();
$ce->exam_id = $exam->exam_id;
$ce->exam_grade = $exam->score;
$ce->exams_remaining -= 1;
$ce->exam_received_date = sql_now();
if($exam->status()=='passed'){
$ce->transition('passed');
}elseif($ce->exams_remaining <= 0){
$ce->transition('failed');
}
$ce->save();
if($ce->is_certification_completed($ce->certification_id, $ce->client_no)){
agent_certification_complete($ce->certification_id, $ce->client_no);
}
}
function agent_certification_complete($certification_id, $client_no){
$ce = ClientPurchase::find('first', array('conditions' => "certification_id = '$certification_id' and is_certification = 1 and client_no='$client_no'"));
$ce->certification_date = date('Y-m-d');
$ce->transition('passed'); **//Line 25**
$ce->save();
}
transition() is defined in another file and is called often. I've included a little bit of it's code just for flavor.
function transition($event_tag){
$old_status = $this->status;
$next_status = $this->next_status_for_transition($event_tag);
if($next_status==''){
return; }
$this->status = $next_status;
My question is, why am I only getting this error periodically and not all the time? What can I do to eliminate the error and subsequent blank screen for my clients? I've only noticed that it is happening to those with Firefox or Chrome.
Thanks in advance,
Jim
The object $ce that contains the function is being generated multiple times. I suppose this is so transition is customized for whatever object is called.
Why not create another object for re-useable functions? Consider expanding the function so that it is compatible with all objects that would use it.
$my = new functionClass;
class functionClass
{
function transition()
{
$old_status = $this->status;
$next_status = $this->next_status_for_transition($event_tag);
if($next_status==''){
return; }
$this->status = $next_status;
}
}
$my->transition( 'passed' );
Something like that would cut down on unpredictability and I believe may solve your problem.
Try this little snippet of code to see whats going on:
$ce = false;
$ce->certification_date = date('Y-m-d');
var_dump($ce);
In this case $ce get cast to an object of stdClass when you try to set a property (certification_date).
Now your code:
function agent_certification_complete($certification_id, $client_no){
$ce = ClientPurchase::find('first', array('conditions' => "certification_id = '$certification_id' and is_certification = 1 and client_no='$client_no'"));
//$ce is probably false or null
//it gets cast to a stdClass object
$ce->certification_date = date('Y-m-d');
//stdClass does not have a transition method; ERROR
$ce->transition('passed'); **//Line 25**
$ce->save();
}
So in your code, if find() is returning null or false, or maybe some other choice values, $ce gets cast to a stdClass object on the next line. Then that stdClass object does not have a transition() method so you get an error.
To fix this, either adjust your find method or check its return value and handle accordingly.
As to it happening only in certain browser, I think thats a false conclusion. If find() is calling a query, it probably only happens at certain times depending on the result of that query.
Related
I am subscribing to data from a MQTT broker with phpMQTT. I have successfully set up a pub / sub routine based on their basic implementation. I can echo the information just fine inside the procmsg() function.
However, I need to take the data I receive and use it for running a few database operations and such. I can't seem to get access to the topic or msg received outside of the procmsg() function. Using return as below seems to yield nothing.
<?php
function procmsg($topic, $msg){
$value = $msg * 10;
return $value;
}
echo procmsg($topic, $msg);
echo $value;
?>
Obviously I am doing something wrong - but how do I get at the values so I can use them outside the procmsg()? Thanks a lot.
I dont know about that lib, but in that code
https://github.com/bluerhinos/phpMQTT/blob/master/phpMQTT.php ,
its possible see how works.
in :
$topics['edafdff398fb22847a2f98a15ca3186e/#'] = array("qos"=>0, "function"=>"procmsg");
you are telling it that topic "edafdff398fb22847a2f98a15ca3186e/#" will have Quality of Service (qos) = 0, and an "event" called 'procmsg'.
That's why you later wrote this
function procmsg($topic,$msg){ ... }
so in the while($mqtt->proc()) this function will check everytime if has a new message (line 332 calls a message function and then that make a call to procmsg of Source Code)
thats are the reason why you cannot call in your code to procmsg
in other words maybe inside the procmsg you can call the functions to process message ej :
function procmsg($topic,$msg){
$value = $msg * 10;
doStuffWithDataAndDatabase($value);
}
Note that you can change the name of the function simply ej :
$topics['edafdff398fb22847a2f98a15ca3186e/#'] = array("qos"=>0, "function"=>"onMessage");
and then :
function onMessage($topic,$msg){
$value = $msg * 10;
doStuffWithDataAndDatabase($value);
}
Sorry for my english, hope this help !
I know this is common error and I have read all answer but my case looks different, at least as a PHP newbie so kindly don't decide action based on question subject.
I have a PHP code which working but I am trying to arrange it in appropriate functions, as in below code but I get following error Warning: Creating default object from empty value in /home/abc/vhosts/localhost/public/portfolio.php on line 16:
<?php
// configuration
require("../includes/config.php");
// prepare portfolio object
$portfolioObject = (object) ["portfolioSummaryArr" => [], "cashInHand" => ""];
function getCashInHand(){
// query database to get cash in hand
$rows = CS50::query("SELECT cash FROM users WHERE username = ?", $_SESSION["username"]);
// get first (and only) row
$row = $rows[0];
$portfolioObject->cashInHand = $row["cash"];
$portfolioObject->portfolioSummaryArr = [11, 22, 33, 44, 55];
}
getCashInHand();
?>
Now after reading all the answers and documentation I think I need some sort of object first so I did this and then I get this error Parse error: syntax error, unexpected '$myObject' (T_VARIABLE) in /home/abc/vhosts/localhost/public/portfolio.php on line 12. I trusted this because something similar is allowed in JS and it works, but guess in PHP isn't so my guess is that using objects created like this you cannot define or access function.
$myObject = new stdClass();
$myObject->demoFunction = function(){
echo "I am coming from demo function.";
}
$myObject->demoFunction();
To me things get more interesting because if I do as in below in my code just after require("../includes/config.php"); then it works and no error, but function definition and access as shown in my first code snippet doesn't work.
// Defining function
function whatIsToday(){
echo "Today is XXX";
}
// Calling function
whatIsToday();
It was just matter of time, I would say. I had to do some reading to understand leverage the object orientation of PHP. Below is how I could resolve all my PHP errors and warnings. Needless to say my favorite debugging methodology "print to screen/terminal", in case of PHP using echo helped a lot.
<?php
// configuration
require("../includes/config.php");
class portfolio{
public $portfolioObject;
public function __construct(){
echo "__construct()</br>";
$this->portfolioObject = new stdClass();
}
public function initialize(){
echo "initialize()";
$portfolioObject = (object) ["portfolioSummaryArr" => [], "cashInHand" => ""];
}
public function getCashInHand(){
// query database to get cash in hand
$rows = CS50::query("SELECT cash FROM users WHERE username = ?", $_SESSION["username"]);
// get first (and only) row
$row = $rows[0];
$this->portfolioObject->cashInHand = $row["cash"];
$this->portfolioObject->portfolioSummaryArr = [11, 22, 33, 44, 55];
}
public function setSessionObject(){
$_SESSION["portfolioSummaryResults"] = $this->portfolioObject;
}
}
$myPortfolio = new portfolio();
$myPortfolio->initialize();
$myPortfolio->getCashInHand();
$myPortfolio->setSessionObject();
render("portfolio/portfolio_results.php", ["title" => "Portfolio"]);
?>
Well I have a function getDaysTotal in my model say estimate.php.
If in my view.php if I use
echo $model->DaysTotal;
I get the value 3. But if I do it again
echo $model->DaysTotal;
Now I get 1. Any idea, why I am getting it like this.
This is happening for any function in estimate.php.
If I am using it for second time the result is weird.
Am I doing anything wrong here? How can I correct this?
Thanks.
Here is the code for getTotalDays function:
public function getDaysTotal() {
$this->discharge_date = strtotime($this->discharge_date);
$this->admission_date = strtotime($this->admission_date);
$datediff = ($this->discharge_date - $this->admission_date);
$fraction_days = ($datediff/(60*60*24));
if ($fraction_days < 1){
return 1;
}elseif(($datediff)%(60*60*24) < 10800){
$option2 = floor($datediff/(60*60*24));
return $option2;
}elseif(($datediff%86400) > 10800 && ($datediff%86400)<21600) {
$option3 = ceil($datediff/(60*60*24)*2)/2;
return $option3;
}elseif (($datediff%86400) >21600){
$option4= ceil($datediff/86400);
return $option4;
}
Your getter changes your object:
public function getDaysTotal() {
$this->discharge_date = strtotime($this->discharge_date);
$this->admission_date = strtotime($this->admission_date);
You should not to do it. On next call strtotime(int) returns false for both lines.
Try followed:
public function getDaysTotal() {
$discharge_date = strtotime($this->discharge_date);
$admission_date = strtotime($this->admission_date);
$datediff = ($discharge_date - $admission_date);
Used aux vars here, without any object state modifying.
It's funny that you're getting anything because "echo $var" might be a non-object.
<?php
$a = 6;
echo $a -> b;
?>
PHP Notice: Trying to get property of non-object.
IN PHP the right pointing arrow "->" is used to access the component parts of an object, in php it is similar to "::" or the humble "." in languages like java and the C family.
Without more context it is impossible to tell what exactly is happening in you're case but perhaps this page on the "->" will be helpful for you.
If that dosn't give you what you need here is a general PHP note card
i have some code like this:
function getAuthorizedPFComponents($pfState)
{
$authorizedPFComponents = new \stdClass();
$compTypeMap=array('platform'=>'pfAuthorizations','mainSite'=>'mainSiteAuthorizations','microSites'=>'microSiteAuthorizations','apps'=>'appAuthorizations');
foreach($compTypeMap as $compType=>$tagName)
{
$authorizationsNode=$this->pfAuthXMLDOM->getElementsByTagName($tagName)->item(0);
foreach($authorizationsNode->getElementsByTagName('authorizations') as $pfComponentAuthElem)
{
foreach($pfComponentAuthElem->getElementsByTagName('allow') as $allow)
{
switch($allow->getAttribute('orgCode'))
{
case 'K_ALL':
{
$authorizedPFComponents->$compType->{$pfComponentAuthElem->getAttribute('pfComponentCode')}->storeCode=$allow->getAttribute('storeCode');
}
}
It shows a warning:
Warning: Creating default object from empty value
The warning is traced back to the code under case K_ALL:
This was too long for a mere comment, so I'll remove it when it has outlived its usefulness.
First thing you should do is make the code simpler; there's a lot of stuff going on in that one statement:
$compCode = $pfComponentAuthElem->getAttribute('pfComponentCode');
$storeCode = $allow->getAttribute('storeCode');
And add debug code:
var_dump($authorizedPFComponents->$compType);
var_dump($authorizedPFComponents->$compType->$compCode);
$authorizedPFComponents->$compType->$compCode->storeCode = $storeCode;
Consider this code:
$x->y = 'test';
If $x is not defined, it will issue a warning:
Warning: Creating default object from empty value in xxx
The same goes for your chain of references:
$authorizedPFComponents->$compType->$compCode->storeCode
If any of those paths is empty, the next ->yyy will cause that warning.
How can I reset the expects() for a PHPUnit Mock?
I have a mock of the SoapClient that I would like to call multiple times within a test, resetting the expectations of each run.
$soapClientMock = $this->getMock('SoapClient', array('__soapCall'), array($this->config['wsdl']));
$this->Soap->client = $soapClientMock;
// call via query
$this->Soap->client->expects($this->once())
->method('__soapCall')
->with('someString', null, null)
->will($this->returnValue(true));
$result = $this->Soap->query('someString');
$this->assertFalse(!$result, 'Raw query returned false');
$source = ConnectionManager::create('test_soap', $this->config);
$model = ClassRegistry::init('ServiceModelTest');
// No parameters
$source->client = $soapClientMock;
$source->client->expects($this->once())
->method('__soapCall')
->with('someString', null, null)
->will($this->returnValue(true));
$result = $model->someString();
$this->assertFalse(!$result, 'someString returned false');
With a bit more of an investigation, it seems you just call expect() again.
However, the issue with the example is the usage of $this->once(). For the duration of the test, the counter associated with expects() can not be reset. To combat this, you have a couple of options.
The first option is to ignore the number of times it gets called with $this->any().
The second option is to target the call with the usage of $this->at($x). Remember that $this->at($x) is the number of times the mock object gets called, not the particular method, and starts at 0.
With my specific example, because the mock test is the same both times, and is only expected to be called twice, I can also use $this->exactly(), with only one expects() statement. i.e.
$soapClientMock = $this->getMock('SoapClient', array('__soapCall'), array($this->config['wsdl']));
$this->Soap->client = $soapClientMock;
// call via query
$this->Soap->client->expects($this->exactly(2))
->method('__soapCall')
->with('someString', null, null)
->will($this->returnValue(true));
$result = $this->Soap->query('someString');
$this->assertFalse(!$result, 'Raw query returned false');
$source = ConnectionManager::create('test_soap', $this->config);
$model = ClassRegistry::init('ServiceModelTest');
// No parameters
$source->client = $soapClientMock;
$result = $model->someString();
$this->assertFalse(!$result, 'someString returned false');
Kudos for this answer that assisted with $this->at() and $this->exactly()
You can clear mocks like this:
// Verify first
$mock->mockery_verify();
// and then overwrite with empty expectation directors
foreach(array_keys($mock->mockery_getExpectations()) as $method) {
$mock->mockery_setExpectationsFor($method, new Mockery\ExpectationDirector($method, $mock));
}