How to encode PHP object to nuSOAP response? - php

I'm building a simple WebService. I have a User PHP class and a webmethod getUser to retrieve a user's information.
I've declared a complexType and everything seems to work perfectly.
$server->wsdl->addComplexType('User',
'complexType','struct', 'all', '',
array( 'id' => array('name' => 'id', 'type' => 'xsd:int'),
'username' => array('name' => 'username','type' => 'xsd:string'),
'password' => array('name' => 'password','type' => 'xsd:string'),
'email' => array('name' => 'email','type' => 'xsd:string'),
'authority' => array('name' => 'authority','type' => 'xsd:int'),
'isActive' => array('name' => 'isActive','type' => 'xsd:int'),
'area' => array('name' => 'area','type' => 'xsd:string')
)
);
$server->register('ws_getUser',
array('user_id' => 'xsd:integer'),
array('user' => 'tns:User'),
$namespace,
"$namespace#ws_getUser",
'rpc',
'encoded',
'Retorna un usuario'
);
function ws_getUser($user_id){
return new soapval('return', 'tns:User', getUser($user_id));
}
However, on the getUser function I'm retrieving the user info as an assoc. array, not the User Object itself.
What I would like to do on getUser is to return a User instance instead, and have nuSOAP serialize it for me. Is this possible?
Edit: I've tried returning a new User() for testing purposes, but the response is
<user xsi:type="tns:User"/>

Guess I've found out an answer that may apply to this case here: http://www.php.net/manual/en/class.soapserver.php
If you want to return a custom object
array from a nusoap webservice, you
have to cast the objects to arrays
like so:
<?php
$users = array();
while($res = $db_obj->fetch_row())
{
$user = new user();
$user->Id = $res['id'];
$user->Username = $res['username'];
$user->Email = $res['email'];
$users[] = (array) $user;
}
return ($users);

Related

Elastica add documents overrides existing ones

When i try to add new documents to an index type , i loose existing documents which are overwritten by the new added ones . The problem can be related to the id of each added document ??
Here is the code :
$elasticaClient = new \Elastica\Client(array(
'host' => $this->container->getParameter('elastic_host'),
'port' => $this->container->getParameter('elastic_port')
));
$elasticaIndex = $elasticaClient->getIndex('app');
$elasticaIndex->create(
array(
'number_of_shards' => 4,
'number_of_replicas' => 1,
'analysis' => array(
'analyzer' => array(
'indexAnalyzer' => array(
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => array('lowercase', 'mySnowball')
),
'searchAnalyzer' => array(
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => array('standard', 'lowercase', 'mySnowball')
)
),
'filter' => array(
'mySnowball' => array(
'type' => 'snowball',
'language' => 'German'
)
)
)
),
true
);
$elasticaType = $elasticaIndex->getType('type');
$mapping = new \Elastica\Type\Mapping();
$mapping->setType($elasticaType);
$mapping->setParam('index_analyzer', 'indexAnalyzer');
$mapping->setParam('search_analyzer', 'searchAnalyzer');
$mapping->setProperties(array(
'id' => array('type' => 'string'),
'title' => array('type' => 'string'),
'duration' => array('type' => 'string'),
'start' => array('type' => 'string'),
'end' => array('type' => 'string'),
));
// Send mapping to type
$mapping->send();
$documents = array();
foreach($medias as $media) {
$id = uniqid() ;
$documents[] = new \Elastica\Document(
$id,
array(
'id' => $id,
'title' => $media['title'],
'duration' => $media['duration'],
'start' => $media['start'],
'end' => $media['end'],
)
);
}
$elasticaType->addDocuments($documents);
$elasticaType->getIndex()->refresh();
Please i need your help . Thank you
PHP does not recommend using uniqid for this use case. Since you are wanting a random, safe id, let Elasticsearch do it for you. The Elastica Document construct method notes that the id field is optional. So don't pass it and let Elasticsearch issue the id.
Several things
$elasticaIndex->create (....) you only have to enter it once. Index is unique after creating the index that you can comment or generate a different index and other things. I leave an example that works.
class PersistencyElastic
{
private $conection;
public function __construct()
{
$this->conection = new \Elastica\Client(['host' => '127.0.0.1', 'port' => 9200]);
}
public function save($ msg)
{
// $ msg is an array with whatever you want inside
$index = $this->conection->getIndex('googlephotos');
// This is the index I created, it's called googlephotos
// $index->create(array (), true);
$type = $index->getType('googlephotos');
$type->addDocument(new Document (uniqid ('id _', false), $msg, $type, $index));
$index->refresh();
}
}

filtering cakedc search results

i'm using cakeDC's search plugin in my app. can;t seem to figure out why the results are empty if i pass no value in the username field i'm searching but have the account type filter set to either admin or user For the record, having the filter set to all with the username field empty will output all the users in the system trying to replicate the behavior of searches having the account type filter set to all with an empty username search field for having the account type filter set to either 2 user types
here's the relevant code if needed:
controller
public $components = array('Paginator', 'Session','Search.Prg');
public $presetVars = array(
array('field' => 'username', 'type' => 'value'),
array('field' => 'account_type', 'type' => 'value'));
public function admin_index() {
$this->Prg->commonProcess();
$this->paginate = array(
'conditions' => $this->User->parseCriteria($this->passedArgs));
$this->set('users', $this->Paginator->paginate(),'session',$this->Session);
model
public $actsAs = array('Search.Searchable');
public $filterArgs = array( array('name' => 'username', 'type' => 'query', 'method' => 'filterName'),
array('name' => 'account_type', 'type' => 'value'),
);
public function filterName($data, $field = null) {
$nameField = '%' . $data['username'] . '%';
return array(
'OR' => array(
$this->alias . '.username LIKE' => $nameField,
));
}
view search form
<div><?php echo $this->Form->create('User', array(
'novalidate' =>true,'url' => array_merge(array('action' => 'index','admin'=> true), $this->params['pass'])
)); ?>
<?php
$account_types = array(
'' => __('All', true),
0 => __('admin', true),
1 => __('user', true),);
echo $this->Form->input('username', array('div' => false, 'empty' => true)); // empty creates blank option.
echo $this->Form->input('account_type', array('label' => 'account_type', 'options' => $account_types));
echo $this->Form->submit(__('Search', true), array('div' => false));
echo $this->Form->end();
?></div>
Try to put 'empty' and allowEmpty in username and account_type like this:
public $filterArgs = array( array('name' => 'username', 'type' => 'query', 'method' => 'filterName', 'empty'=>true, 'allowEmpty'=>true),
array('name' => 'account_type', 'type' => 'value','empty'=>true, 'allowEmpty'=>true),
);
I had this kind of behavior as well from CakeDC/search and this two configs saved me, hope it will do for you as well.
It's a good idea to check the queries being executed as well using DebugKit.Toolbar.

SOAP 4 set_relationship not working

After battling for getting more than 20 entries with get_entry_list, i'm now trying to use the SOAP API on SugarCRM 6.5 to set a relationship between two elements, created from a form on the user-land website.
The set_relationship method is described as following in the devs blog :
$response = set_relationship(session, module_name, module_id, link_field_name, related_ids, name_value_list, delete);
So here is the code which handles the request, assuming that another part of the code handles the security.
$values = array( 'id_frame' => $_POST['id_frame'],
'id_battery' => $_POST['id_battery'],
'reseller' => $_POST['reseller'],
'date_purchase' => $_POST['date_purchase'],
'products_versionning' => $_POST['product_purchased'],
'first_name' => $_POST['first_name'],
'last_name' => $_POST['name'],
'phone_home' => $_POST['phone'],
'email' => $_POST['email'],
'primary_address_street' => $_POST['address'],
'primary_address_street_2' => $_POST['address2'],
'primary_address_street_city' => $_POST['city'],
'primary_address_street_postalcode' => $_POST['zip'],
);
try{
$prod_register = $soapClient->set_entry(
$sessid,
'myco_product_register',
array( array('name' => 'id_frame', 'value' => $values['id_frame']),
array('name' => 'id_battery', 'value' => $values['id_battery']),
array('name' => 'date_purchase', 'value' => $values['date_purchase']),
array('name' => 'first_name', 'value' => $values['first_name']),
array('name' => 'last_name', 'value' => $values['last_name']),
array('name' => 'phone_home', 'value' => $values['phone_home']),
array('name' => 'email', 'value' => $values['email']),
array('name' => 'primary_address_street', 'value' => $values['primary_address_street']),
array('name' => 'primary_address_street_city', 'value' => $values['primary_address_street_city']),
array('name' => 'primary_address_street_postalcode','value' => $values['primary_address_street_postalcode']),
array('name' => 'description','value' => "Modèle : " . $values['products_versionning'] . "\nAcheté le " . $values['date_purchase'] . " à " . $values['reseller']),
)
);
$client = $soapClient->set_entry(
$sessid,
'Accounts',
array( array('name' => 'name', 'value' => $values['first_name'] . ' ' . $values['last_name']),
array('name' => 'billing_address_street', 'value' => $values['primary_address_street']),
array('name' => 'billing_address_city', 'value' => $values['primary_address_street_city']),
array('name' => 'billing_address_postalcode', 'value' => $values['primary_address_street_postalcode']),
)
);
$entry_id = $prod_register->id;
$relationship_parameters = array(
"module1" => "myco_product_register",
"module1_id" => array($entry_id),
"module2" => "myco_products_versionning",
"module2_id" => array($values['products_versionning'])
);
//Now i'm setting the relationships
$response = $soapClient->set_relationship($sessid, "myco_product_register", $entry_id,
'myco_products_versionning_id_c', $values['products_versionning'], array(), 0);
$response = $soapClient->set_relationship($sessid, "myco_product_register", $entry_id,
'myco_resellers_id_c', $values['reseller'], array(), 0);
Both set_entry requests work and return a working id, but no one of the relationships work ($responses contains a failed equal to 1). So that's not a connection problem or such.
Talking about the relationships, one guy from the devblog said that
there has to be a relationship between the two modules
there has to be at least one related field in the module which handle the relation, whose name you can find in the module's vardefs.php
and i have
A One-to-one relationship between the product_register module and both products_versionning and resellers
A related field in product_register for each related module.
What may i be missing ?
try checking the log file of SugarCRM, you should find some mistakes. I used this API to create a relationship between Contacts and Accounts, and working properly. On the logs might find the answer to the problem.
try {
$result = $this->soapClient->set_relationship($this->sessionId,
$accountModuleName, $accountId, $relationName, $contactsId);
$this->doEvent(self::EVENT_WS_OPERATION_CALL);
if ($result->created > 0 && $result->failed === 0) {
return true;
} else {
return false;
}

Zf2 How to pass arguments using filter class?

I would like to use SeparatorToSeparator() filter in zend framwork 2 to filter my data.How can I pass two arguments(setSearchSeparator and setReplacementSeparator) to the constructor?
$inputFilter->add(array(
'name' => 'supplierName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
array('name'=>"Word\SeparatorToSeparator"
),
));
Path:zendframework/bin/libary/Zend/Filter/Word/SeparatorToSeparator.php
class SeparatorToSeparator extends AbstractFilter
{
protected $searchSeparator = null;
protected $replacementSeparator = null;
/**
* Constructor
*
* #param string $searchSeparator Separator to search for
* #param string $replacementSeparator Separator to replace with
*/
public function __construct($searchSeparator = ' ', $replacementSeparator = '-')
{
$this->setSearchSeparator($searchSeparator);
$this->setReplacementSeparator($replacementSeparator);
}
Updated
$inputFilter->add(array(
'name' => 'supplierName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
array('name'=>'Word\SeparatorToSeparator',
'options' => array(
'search_separator' => 'a',
'replacement_separator' => 'b'
)
)
),
));
I got this error message:
Warning: preg_quote() expects parameter 1 to be string, array given in
C:\wamp\www\tebipdevelopment\vendor\zendframework\zendframework\library\Zend\Filter\Word\SeparatorToSeparator.php
on line 92
I've opened this line and I have printed the error message like this.
print_r($this->searchSeparator);
print_r($this->replacementSeparator);
Result
Array ( [search_separator] => a [replacement_separator] => b )
In that case the search_separator is equals to array instead of string
Note you don't need setters, but i've added them in anyway, the filter will try and use setters if they exist (setCamelCase() notation).
class SeparatorToSeparator extends AbstractFilter
{
protected $searchSeparator = null;
protected $replacementSeparator = null;
public function setSearchSeparator($val)
{
$this->searchSeparator = $val;
}
public function setReplacementSeparator($val)
{
$this->replacementSeparator = $val;
}
}
Now you can set the options:
$inputFilter->add(array(
'name' => 'supplierName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
array(
'name'=>"Word\SeparatorToSeparator"
'options' => array(
'search_separator' => 'bla',
'replacement_separator' => 'bla'
)
)
),
));
I've come up against this same issue, unlike other validators, the word validators don't accept an array of options, as you've found. The workaround I used was to just instantiate the word filter first, passing it the required constructor params, and then add that instance to the filters spec...
$wordFilter = new \Zend\Filter\Word\SeparatorToSeparator('a', 'b');
$inputFilter->add(array(
'name' => 'supplierName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
$wordFilter,
),
));

Deserialize WCF web service request in PHP

I have a WCF web service with a Login operation taking a company name, user name and password as the three parameters. I am trying to create a PHP client app to communicate with this service. No matter what I pass to the Login operation I get the following error:
OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'Login' and namespace ''. Found node type 'Element' with name 'parameters' and namespace ''
My client app:
<?php
try
{
$client = new SoapClient("https://somewhere.com/DataServiceRxPublic.svc?wsdl");
//$params = array(
// 'parameters' => array(
// 'Param' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//)));
//$params = array(
// 'Login' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//));
//$params = array(
// 'Login' => array(
// 'parameters' => array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//)));
//$params = array(
// array('Name' => 'loginCompany', 'Value' => 'XXX'),
// array('Name' => 'loginId', 'Value' => 'XXX'),
// array('Name' => 'loginPwd', 'Value' => 'XXX')
//);
$params = array(
'loginCompany' => 'XXX',
'loginId' => 'XXX',
'loginPwd' => 'XXX'
);
$obj->loginCompany = 'XXX';
$obj->loginId = 'XXX';
$obj->loginPwd = 'XXX';
//$result = $client->Login($obj);
//$result = $client->Login($params);
}
catch (Exception $e)
{
print_r($e);
}
}
?>
$params being the different array permutations I've based off several different examples online.
Any help is appreciated.
The error message is telling you that there should have been something named "Login", but was named "parameters".
Go get SoapUI and with your WSDL follow the steps I described here to debug what you are actually sending. If you cannot compare what the service expects vs. what you are sending, this will be way too much trial-and-error.
If you need more external help, we'd need the WSDL resource - without it, nobody knows which request structure is expected.
Turns out I needed to extend the SOAPClient and override the __doRequest() method to replace the mismatched soap headers.
I managed to fix this error by modifying service namespace on server side.
[ServiceContract(Name="Service", Namespace = "https://sample.eu")]
Namespace was empty before.

Categories