Page 1 of 2

__PHP_Incomplete_Class Object question

Posted: Wed May 23, 2007 1:22 pm
by victorsk
Hello folks,

I have a serious problem trying to get a complete object. What I have is:

file class_foo.php

Code: Select all

class foo
{
     require_once "SOAP/Client.php"; 
    public $client;
     public $resp;
     function __construct($parameters)
     {
                  //split $parameters into variables to pass into SOAP request
                  $this->client->callSOAPMethod();
                  $this->client->callAnotherSOAPMethod();
                  $this->resp = $this->client->callSomeMoreSOAPMethods();
     }
 
     function getResponse()
     {
            return $this->resp;
     }

     function getClient()
     {
            return $this->client;
     }
}

file1.php
{
 include 'class_foo.php';
          session_start();
          $obj = new foo($parameters_from_html);
          $_SESSION['sobject'] = $obj;
        
        //THIS WORKS FINE
         processObject($obj->getResponse());
}

file2.php
{
    include 'class_foo.php';
   session_start();
    $obj = $_SESSION['sobject'];

    //THIS CREATES __PHP_Incomplete_Class Object
   print_r($obj->getClient());

   //THIS DOES *NOT* CREATE Incomplete_Class Object and works fine

  print_r($obj->getResponse());
}
Please, help me, I have no idea why I am getting Incomplete_Class Object for one function call and not the other. I tried serialize/unserialize - didn't work. I am not familiar with all the PHP incricacies. Please help me.

Thank you,
Victor.

Posted: Wed May 23, 2007 1:39 pm
by aaronhall

Code: Select all

require_once "SOAP/Client.php";
should either be outside of the class or inside the class's __construct method. Your files aren't wrapped in curly brackets, are they?

Posted: Wed May 23, 2007 1:49 pm
by victorsk
Hi, it is outside of my class in the original code, sorry for putting it there in the example.

Posted: Wed May 23, 2007 1:53 pm
by aaronhall
foo::client isn't being set before it's referenced... it looks like you're expecting it to be a soap object.

Posted: Wed May 23, 2007 2:05 pm
by victorsk
Hi,

Thank you so much for replying. When I do the follwing in my file1.php:

Code: Select all

$obj = new foo($html_parameters);
        $_SESSION['sobject'] = $obj;    
        echo '<pre>';
        print_r($_SESSION['sobject']->getClient());
        echo '</pre>';
I get the right printout:

Code: Select all

WebService_WebService_WebServiceSoap Object
(
    [_endpoint] => http://cws.globaltsg.com/TSGWebServices/WebService.asmx
    [_portName] => 0
    [_endpointType] => 
    [xml] => 2007-05-23T15:00:55.5625-04:002007-05-23T15:00:57.375-04:006321334170ConquestVacationsCVYVRCUN2007-07-22T00:00:002007-07-29T00:00:007YVRCUNDOSDOS PLAYAS CUN   ROOM   AI2007-07-22T07:00:002007-07-22T14:35:00TS7002007-07-29T16:05:002007-07-29T20:20:00TS701AllInclusiveDoubleUserDefinedUndefinedHotel Room10000trueHotel Dos PlayasCUNSet in tropical gardens, this quiet beachside resort offers a casual, relaxed atmosphere and great value.

Location:
Directly on the beach in the hotel zone, minutes from the Isla Mujeres dock for the ferry. 15 minutes from downtown, walking distance to Cancun's popular bar Fat Tuesday's, and 35 minutes from the airportOffrant tranquilité et relaxation ainsi qu'une excellente valeur, Dos Playas est assuré de plaire aux personnes qui ont le coeur jeune.2.5BeachFrontHoneymoonSuiteScubaDivingTennishttp://images.globaltsg.com/Images/SuperDef/313/313_00.jpgTourProviderInformationhttp://www.conquestvacations.com/hotels/DSOP.htmlEnglishfalse11581158CADCADUnknown273.9273.9CADCADUnknownTotal1431.91431.9CADCADUnknowntrue1Adult1ConquestVacationsCVYVRCUN2007-07-22T00:00:002007-07-29T00:00:007YVRCUNETSEL TUKAN CONDOTL STDRM  AI2007-07-22T07:00:002007-07-22T14:35:00TS7002007-07-29T16:05:002007-07-29T20:20:00TS701AllInclusiveDoubleUserDefinedUndefinedStandard Room10000trueEl Tukan Condotel VillasCUNThis hotel is set around a huge lush garden with a pool, winding flagstone paths, and a cenote - or natural underground pool.Cet hôtel est à l'entour d'un immense jardin luxuriant avec piscine, ainsi qu'une piscine naturelle intérieure.3BeachFrontHoneymoonSuiteKitchenetteScubaDivingWeddinghttp://images.globaltsg.com/Images/SuperDef/218/218_00.jpgTourProviderInformationhttp://www.conquestvacations.com/hotels/ETUK.htmlEnglishfalse11881188CADCADUnknown273.9273.9CADCADUnknownTotal1461.91461.9CADCADUnknowntrue1Adult
    [wire] => 
    [_last_request] => 
    [_last_response] => 
    [_options] => Array
        (
            [trace] => 
            [input] => parse
            [result] => parse
            [parameters] => 
            [namespace] => http://ws.globaltsg.com/TSGWebServices
            [soapaction] => http://ws.globaltsg.com/TSGWebServices/SearchTourPackages
            [style] => document
            [use] => literal
        )

    [_encoding] => UTF-8
    [headersIn] => Array
        (
            [StatusHeader] => stdClass Object
                (
                    [serverRequestStartTime] => 2007-05-23T15:00:55.5625-04:00
                    [serverRequestEndTime] => 2007-05-23T15:00:57.375-04:00
                    [serverVersion] => 6321
                    [internalRequestId] => 33417
                )

        )

    [_proxy_params] => Array
        (
            [timeout] => 360
        )

    [_soap_transport] => SOAP_Transport_HTTP Object

...
But, in file2.php I get an Incomplete Object error :-(

I don't understand why file1.php is different from file2.php in that it gets return of the right $client but not file2.php. How can I make $client work in file2.php also?

Thank you,
Victor.

Posted: Wed May 23, 2007 6:09 pm
by volka
Works without errors,warning,etc :

Code: Select all

<?php // class_foo.php
require_once 'SOAP/Client.php';

class foo {
	public $client;
	public $resp;
	
	function __construct($parameters)	{
		$this->client = new SOAP_Client('http://www.compkarori.com/wsdl/discordian.wsdl');
		$this->client->setOpt('trace', 'true');
		$this->resp = $this->client->call('Discordian', $parameters);
	}
}

Code: Select all

<?php // test.php
error_reporting(E_ALL);
ini_set('display_errors', true);
require 'class_foo.php';
session_start();

$_SESSION['sobject'] = new foo(array('year'=>2007, 'month'=>5, 'day'=>24));
?>
<html>
	<head><title>session test #1</title></head>
	<body>
		<pre>resp: <?php print_r($_SESSION['sobject']->resp); ?></pre>
		<pre>session-id: <?php echo session_id(); ?></pre>
		<a href="test2.php">test2</a>
	</body>
</html>

Code: Select all

<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
require 'class_foo.php';
session_start();
?>
<html>
	<head><title>session test #2</title></head>
	<body>
		<pre>resp: <?php print_r($_SESSION['sobject']->resp); ?></pre>
		<pre>class: <?php echo get_class($_SESSION['sobject']->client); ?></pre>
		<pre>session-id: <?php echo session_id(); ?></pre>
		<a href="test2.php">test2</a>
	</body>
</html>

Posted: Wed May 23, 2007 7:00 pm
by victorsk
Hi Volka,

I am deeply grateful for your assistance. I tried your example and it works. The sad thing is that my situation requires a user to use SOAP lLogin method which sends a session cookie with which other API calls are possible. I am not sure if there is a way to do this using

Code: Select all

$this->client = new Soap_Client("http://cws.globaltsg.com/TSGWebServices/WebService.asmx?WSDL");
Because I am using getProxy() call like this:

Code: Select all

<?php // class_foo.php
require_once 'SOAP/Client.php';

class foo {
        public $client;
        public $resp;
        public $conn;

        function __construct($parameters)
        {
                $wsdl = 'http://cws.globaltsg.com/TSGWebServices/WebService.asmx?WSDL';
                $this->conn = new SOAP_Wsdl($wsdl, array("timeout" => 360));
                $params = Array(
                                 'agencyId'=> new Soap_Value( 'agencyId', 'string', "XXX" ),
                                 'userName'=> new Soap_Value( 'userName', 'string', 'XXXXXXX'),
                                 'userPassword'=> new Soap_Value( 'userPassword', 'string', 'XXXXXXXXX')
                               );

                $soapheader1 = new Soap_Header("StatusHeader", "object",
                                  array(
                                        "clientHostAddress" => new Soap_Value( "clientHostAddress", "string", "127.0.0.1" ),
                                        "serverRequestStartTime" => new Soap_Value("serverRequestStartTime", "string","2007-05-21T10:35:00"),
                                        "serverRequestEndTime" => new Soap_Value("serverRequestEndTime", "string","2007-05-21T10:35:00"),
                                        "serverVersion" => new Soap_Value("serverVersion", "string","0"),
                                        "internalRequestId" => new Soap_Value("internalRequestId", "int", 0)
                                       ), 1, '');

                $this->client = $this->conn->getProxy();    
                $this->client->setDefaultNamespace("http://ws.globaltsg.com/TSGWebServices" );
                $this->client->addHeader($soapheader1);

                $this->client->Login( new SOAP_Value( 'request', "object", $params ) );        
                $this->resp = $this->client->GetAgencyFunctionalities();
        }
}
To fully test it I'd need to give out user id, agency id, and password publicly which I am reluctant to do. Would you allow me to send it to you in private. I really need this to be solved because this is for work.

Again, the problem I get with this is that I don't think that $client variable gets fully created as an object but this is the only way I know how to use calls to getProxy() to get session cookie and make API calls. But then if you just plug in this code into the class_foo.php file then it will say that session class in Incomplete_Object.

Please, help me with this.

Thank you,
Victor.

Posted: Wed May 23, 2007 8:07 pm
by volka
If you still have an __PHP_Incomplete_Class in _SESSION, the class foo or the class SOAP_Client wasn't present when session_start() has been called.
You need to check the include/session_start order again. First include or require, then session_start.

Posted: Wed May 23, 2007 8:20 pm
by victorsk
volka wrote:If you still have an __PHP_Incomplete_Class in _SESSION, the class foo or the class SOAP_Client wasn't present when session_start() has been called.
You need to check the include/session_start order again. First include or require, then session_start.
Hi Volka,

Yes, exactly, class SOAP_Client is not in my class_foo.php, I am using SOAP_Wsdl() instead then using its object to call getProxy() and create $client session object like this:

Code: Select all

$wsdl = 'http://cws.globaltsg.com/TSGWebServices/WebService.asmx?WSDL';
$this->conn = new SOAP_Wsdl($wsdl, array("timeout" => 360)); //INSTEAD OF SOAP_Client()
$this->client = $this->conn->getProxy();
I need to use a call to getProxy() to get Session Id and other information necessary for subsequent API calls. Do you know how I can use getProxy() with Soap_Client()? That will solve my problem I think.

Thank you for helping me out on this one.

Victor.

Posted: Wed May 23, 2007 8:27 pm
by volka
I have no idea how PEAR::SOAP works. And it doesn't matter. If you get an __PHP_Incomplete_Class the definition for this class wasn't present when session_start has been called, no matter which class.
Clear your session directory (in case of doubt echo ini_get('session_save_path'); tells you which directory) to get rid of all session data.
Then replace session_start() by

Code: Select all

error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('unserialize_callback_func', 'mycallback');
function mycallback($classname)
{
	echo 'undefined class: ', $classname, "<br />\n";
	if ( function_exists('debug_print_backtrace') ) {
		echo '<pre>backtrace: '; debug_print_backtrace(); echo "</pre>\n";
	}
	echo '<pre>included: '; get_included_files(); echo "</pre>\n";
}
session_start();
in both main script files and try again.


and replace $this->client = $this->conn->getProxy(); by

Code: Select all

$this->client = $this->conn->getProxy();
echo '<div> Debug, client class: ', get_class($this->client), "</div>\n";

Posted: Thu May 24, 2007 10:04 am
by victorsk
Hi,

I've add all the suggestions and I've got these messages:

Code: Select all

undefined class: WebService_WebService_WebServiceSoap

backtrace: #0  mycallback(WebService_WebService_WebServiceSoap)
#1  session_start() called at [/var/www/html/test/checkTourAvailability.php]

included:
Any Ideas?
Thank you,
Victor.

Posted: Thu May 24, 2007 10:55 am
by volka
Looks like getProxy() creates a new, specialized class from the wsdl.
I have no idea how you can make this class definition persistent. You can re-create the class by creating a new (dummy) SOAP_WSDL from same wsdl and calling getProxy() prior to session_start().
Have you tried SOAP_Client instead?

Posted: Thu May 24, 2007 11:09 am
by victorsk
volka wrote:Looks like getProxy() creates a new, specialized class from the wsdl.
I have no idea how you can make this class definition persistent. You can re-create the class by creating a new (dummy) SOAP_WSDL from same wsdl and calling getProxy() prior to session_start().
Have you tried SOAP_Client instead?
Yes, I did, but trouble is that I wasn't able to use getProxy() then. I have another idea. In file1.php I can, in fact, get the complete object definition of WSDL $client *BUT* it has to be in file2.php which it doesn't work. So my idea is this:

1. Get value of $client from file1 using:

Code: Select all

$obj = new class_foo($parameters_from_html);
$client = $obj->getClient();
2. Store the value of existing $client object in the database with sessionId as key and $client object's value as text:

Code: Select all

mysql_query('insert into client values("'.print_r($obj->getClient()).'")'); or
mysql_query('insert into client values("'.var_dump($obj->getClient()).'")');
3. Make file2.php get the object's values using commonly-shared sessionId() which I saw they have as key

My question: will this implementation work?

Thank you,
Victor.

Posted: Thu May 24, 2007 11:24 am
by victorsk
Alright, I just tried placing print_r or var_dump results into database but all I got was object's printout on a screen and value 1 in the table. Is it possible to store PHP object in a database and then retrieve it with PHP?

Thank you,
Victor.

Posted: Thu May 24, 2007 11:26 am
by volka
victorsk wrote:Yes, I did, but trouble is that I wasn't able to use getProxy() then.
Why do you need getProxy() ?
victorsk wrote:Is it possible to store PHP object in a database and then retrieve it with PHP?
The exact same problem as with the session data, the class definintion must be present when the object is restored.