Can't generate XML through WSDLDocument.php (PHP SOAP) - php

I have a simple server/client SOAP interaction with a Shop class (shop.php) commented like this:
<?php
/**
* Class Shop
* Objective: Handling my shop
*
* #author Me
*/
require_once('config.php');
include("product.php");
include("fruit.php");
class Shop{
/**
* Returns a string with family's products concatenated
*
* #param string $familyId
* #return string
*
*/
public static function getFamilyProducts($familyId){
Now I puy my WSDLDocument.php next to my class (all files are in the same folder), and write my WSDLgenerator.php:
<?php
require_once('shop.php');
require_once('WSDLDocument.php');
$url = "http://localhost/Shop/server.php";
$uri = "http://localhost/Shop";
$wsdl = new WSDLDocument( "Shop", $url, $uri );
echo $wsdl->saveXml();
?>
My server is serving flawlessly to my client but here it is anyway if you want to check:
<?php
require_once('shop.php');
$uri = 'http://localhost/Shop';
$server = new SoapServer(null, array('uri' => $uri));
$server -> setClass('Shop');
$server -> handle();
?>
When I access WSDLGenerator.php it is printing "Class Shop Objective: Handling my shop" but nothing more. Browser's inspector is getting the class name and that lines:
<wsdl:service name="Shop">
<wsdl:documentation>Class Shop Objective: Handling my shop
</wsdl:documentation>
...
There are some calls to Shop ("ShopPortType", "ShopBinding", "ShopPort") but there's no signal of my functions and its parameters...

I FOUND THE PROBLEM! If the function is public static the XML just won't show (don't know why but that's it). Just change them to public.

Related

Magento2 Custom Widget Not Appearing

I created a module with a Custom Widget. When logging into the admin, going to content->widgets, creating an instance, and setting that instance to appear on the homepage, the widget appears as expected.
I have removed this instance and am now trying to create the widget by going to content->pages, editing the homepage -> content section, and selecting insert widget. I created a new instance of the widget and added some additional text into the homepage -> content section.
When I load the homepage the widget does not appear, though the rest of the text does appear.
The block for the widget is being called ( I tested this with a var_dump and exit).
The template is not being rendered however.
Here is my Block:
<?php
namespace MyNamespace\Slider\Block\Widget;
use Magento\Framework\View\Element\Template;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Block\Product\Context;
class Slider extends Template
{
protected $_template = "Yamazaki_Slider::widget/slider.phtml";
/**
* #var CollectionFactory
*/
protected $_productCollectionFactory;
/**
* #var CollectionFactory
*/
protected $_imageHelper;
/**
* #param Context $context
* #param CollectionFactory $productCollectionFactory
*/
public function __construct(Context $context, CollectionFactory $productCollectionFactory)
{
$this->_imageHelper = $context->getImageHelper();
$this->_productCollectionFactory = $productCollectionFactory;
parent::__construct($context);
}
/**
* Retrieve featured products collection
*/
public function getProducts()
{
$collection = $this->_productCollectionFactory->create();
return $collection->addAttributeToSelect('*')->addAttributeToFilter('is_featured','1');
}
}
and my Template:
<?php $imageBlock = $block->getLayout()->createBlock('Magento\Catalog\Block\Product\ListProduct'); ?>
<?php foreach($this->getProducts() as $product): ?>
<?php $productImage = $imageBlock->getImage($product, 'product_page_image_large'); ?>
<?php echo $productImage->toHtml(); ?>
<?php endforeach ?>
The other files in my module are:
etc/widget.xml:
<?xml version="1.0" encoding="UTF-8"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
<widget id="yamazaki_slider" class="MyNamespace\Slider\Block\Widget\Slider">
<label translate="true">My Image Slider</label>
<description>My Image Slider</description>
</widget>
</widgets>
module.xml and registration.php.
I do not have a etc/layout.xml file as I have noticed some widget/modules contain. Do I need this, or any other files?
Also, If I "Hide the Editor" inside content->pages->edit->content I see:
<p>{{widget type="MyNamespace\Slider\Block\Widget\Slider"}}</p>`
If I replace this with
{{block class="MyNamespace\Slider\Block\Widget\Slider" template="widget/slider.phtml"}}
The Content appears as expected
I managed to get the Block to Render
I had to add implements \Magento\Widget\Block\BlockInterface to MyNamespace\Slider\Block\Widget\Slider.
I'm not sure why this rendered, prior to adding the implements, using the first approach and not the second.
Magento is seriously lacking documentation!

Extending piwik to access all request data

To write a custom piwik plugin I'm following tutorial : http://piwik.org/blog/2014/09/create-widget-introducing-piwik-platform/
How can I access the request data that piwik receives within the plugin ?
Sample widget from above link :
class Widgets extends \Piwik\Plugin\Widgets
{
/**
* Here you can define the category the widget belongs to. You can reuse any existing widget category or define your own category.
* #var string
*/
protected $category = 'ExampleCompany';
/**
* Here you can add one or multiple widgets. You can add a widget by calling the method "addWidget()" and pass the name of the widget as well as a method name that should be called to render the widget. The method can be defined either directly here in this widget class or in the controller in case you want to reuse the same action for instance in the menu etc.
*/
protected function init()
{
$this->addWidget('Example Widget Name', $method = 'myExampleWidget');
$this->addWidget('Example Widget 2', $method = 'myExampleWidget', $params = array('myparam' => 'myvalue'));
}
/**
* This method renders a widget as defined in "init()". It's on you how to generate the content of the widget. As long as you return a string everything is fine. You can use for instance a "Piwik\View" to render a twig template. In such a case don't forget to create a twig template (eg. myViewTemplate.twig) in the "templates" directory of your plugin.
*
* #return string
*/
public function myExampleWidget()
{
$view = new View('#MyWidgetPlugin/myViewTemplate');
return $view->render();
}
}
How to access within the plugin the data piwik receives for each visitor request such as the request header fields ?
Access to a variable with name 'imageId':
$imageId = Common::getRequestVar('imageId');
About headers:
Piwik provides a list of headers methods through a ProxyHeaders class.
For now there are only two public static methods, that could be potentially interesting for you:
ProxyHeaders::getProxyClientHeaders, working with
'HTTP_CF_CONNECTING_IP',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
and ProxyHeaders::getProxyHostHeaders for
'HTTP_X_FORWARDED_HOST'
Both these methods call another one, which is private:
/**
* Get headers present in the HTTP request
*
* #param array $recognizedHeaders
* #return array HTTP headers
*/
private static function getHeaders($recognizedHeaders)
{
$headers = array();
foreach ($recognizedHeaders as $header) {
if (isset($_SERVER[$header])) {
$headers[] = $header;
}
}
return $headers;
}
Because method getHeaders is private and it actually doesn't do what you want, probably the easiest way would be just to read headers directly from $_SERVER.
It will work this way: if you have a header with name "my-test-header" and value "123":
$_SERVER['HTTP_MY_TEST_HEADER'] // returns "123"
"Content-Type" => 'application/x-www-form-urlencoded'
$_SERVER['HTTP_CONTENT_TYPE'] // returns "application/x-www-form-urlencoded"
etc.
One note about web servers, whether it's Apache or Nginx or any other one, the configuration really matters here, especially for a HTTP_X_FORWARDED_FOR header.

Prestashop 1.6 - How I can get the admin directory name dynamically?

I want to put my module in Prestashop market place, and make it standard everyone can use it. This plugin needs to know the admin directory name dynamically to do its service.
I have searched on the Internet a lot of times, but I didn't find a solution to this issue.
You can use _PS_ADMIN_DIR_ witch is set in [your_admin_dir]/index.php:
if (!defined('_PS_ADMIN_DIR_')) {
define('_PS_ADMIN_DIR_', getcwd());
}
This constant is only set when you're on an admin context. Your FrontOffice doesn't have knowledge of this directory and should not for obvious security reason.
There's also a getAdminLink method in class Link:
/**
* Use controller name to create a link
*
* #param string $controller
* #param bool $with_token include or not the token in the url
* #return string url
*/
public function getAdminLink($controller, $with_token = true)
{
$id_lang = Context::getContext()->language->id;
$params = $with_token ? array('token' => Tools::getAdminTokenLite($controller)) : array();
return Dispatcher::getInstance()->createUrl($controller, $id_lang, $params, false);
}
Example:
// Here we create a link to the dashboard without token
$this->context->link->getAdminLink(Tab::getClassNameById(1), false)

How to retrieve the current page from Zend_Navigation within a Controller Plugin

I am working on an Authentication Plugin using a Controller Plugin. I define my navigation config within the application.ini file, and then use that and the Database user records to dynamically load the ACL and apply it to Zend_Navigation. This bit works, as it successfully loads the menu and only displays the pages the user is allowed to see.
However, this doesn't stop the user from going to the page directly. What I want to do is identify when the user is going to a page they don't have access to within the Controller Plugin so I can redirect their request to the Authentication page.
I was thinking there must be a function to retrieve the current page from Zend_Navigation, but I can't find it... so maybe it doesn't exist.
Anyway, this is my full Controller Plugin. Anyone see a solution?
<?php
class Pog_Model_AuthPlugin extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $oRequest)
{
/**
* Load user
*/
$oAuth = Zend_Auth::getInstance();
$oDbUsers = new Pog_Model_DbTable_Users();
if (!$oAuth->hasIdentity())
{
$oUser = $oDbUsers->createRow();
$oUser->name = "guest";
$oUser->setReadOnly(true);
}
else
{
$oUser = $oAuth->getIdentity();
$oUser->setTable($oDbUsers);
}
/**
* Load ACL
*/
$oAcl = new Zend_Acl();
$oAcl->addRole($oUser->name);
/**
* Add current user privileges
*/
$oPrivileges = $oUser->getPrivileges();
foreach ($oPrivileges as $oPrivilege)
{
if (!$oAcl->has($oPrivilege->resource))
$oAcl->addResource($oPrivilege->resource);
$oAcl->allow($oUser->name, $oPrivilege->resource, $oPrivilege->privilege);
}
/**
* Load Navigation view helper
*/
$oViewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$oNavigation = $oViewRenderer->view->navigation();
/**
* Add remaining Navigation resources
*/
foreach ($oNavigation->getPages() as $oPage)
{
if (!is_null($oPage->getResource()) && !$oAcl->has($oPage->getResource()))
$oAcl->addResource($oPage->getResource());
}
/**
* Set ACL and Role
*/
$oNavigation->setAcl($oAcl)->setRole($oUser->name);
/**
* Check if use is allowed to be here
*/
...MAGIC GOES HERE...
}
}
I think that you should be able to get current navigation page as follows:
/**
* Load Navigation view helper
*/
$oViewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$oNavigation = $oViewRenderer->view->navigation();
/*#var $active array */
$active = $oNavigation->findActive($oNavigation->getContainer());
/*#var $activePage Zend_Navigation_Page_Mvc */
$activePage = $active['page'];
// example of getting page info
var_dump($activePage->getLabel(), $activePage->getController(), $activePage->getAction());
Hope this helps.
This is the solution I used, since I can't get Marcin's solution working in my setup for some reason.
I did some more thinking and thought of a nice simple solution to the problem. Rather than use the Navigation module to find the Active page, I find it myself. Since I am already iterating through the pages, it's a piece of cake to compare the Controller and Action - if these both match I have my Active page!
The new getPages() foreach loop looks like this:
$oCurrentPage = null;
foreach ($oNavigation->getPages() as $oPage)
{
/**
* Check for Current Page
*/
if ($oPage->getController() == $oRequest->getControllerName()
&& $oPage->getAction() == $oRequest->getActionName())
$oCurrentPage = $oPage;
/**
* Add Resource, if missing
*/
if (!is_null($oPage->getResource()) && !$oAcl->has($oPage->getResource()))
$oAcl->addResource($oPage->getResource());
}

PHP SOAP : How can I return objects from PHP using SOAP?

I need to send/return objects or array to/from PHP using SOAP. Any good links?
I am using Zend_Soap_Server и Zend_Soap_Client. I send/receive array of difficult structure.
At first create class with structure you want to receive.
<?php
/**
* Information about people
*/
class PeopleInformation
{
/**
* Name of ...
*
* #var string
*/
public $name;
/**
* Age of
* #var int
*/
public $age;
/**
* Array of family
*
* #var FamilyInformation[]
*/
public $family;
}
/**
* Information about his family
*/
class FamilyInformation
{
/**
* Mother/sister/bro etc
*
* #var string
*/
public $relation;
/**
* Name
* #var string
*/
public $name;
}
?>
Then create service to receive this data:
<?php
/**
* Service to receive SOAP data
*/
class SoapService
{
/**
*
* #param PeopleInformation $data
* #return string
*/
public function getUserData($data)
{
//here $data is object of PeopleInformation class
return "OK";
}
}
?>
Now create Zend_Soap_Server instance in controller by url http://ourhost/soap/:
<?php
//disable wsdl caching
ini_set('soap.wsdl_cache_enabled', 0);
ini_set('soap.wsdl_cache', 0);
$wsdl = $_GET['wsdl'];
//this generate wsdl from our class SoapService
if (!is_null($wsdl))
{
$autodiscover = new Zend_Soap_AutoDiscover('Zend_Soap_Wsdl_Strategy_ArrayOfTypeSequence');
$autodiscover->setClass('SoapService');
$autodiscover->handle();
}
//handle all soap request
else
{
$wsdlPath = 'http://ourhost/soap/?wsdl';
$soap = new Zend_Soap_Server($wsdlPath, array(
'cache_wsdl' => false
));
$soap->registerFaultException('Zend_Soap_Server_Exception');
$soap->setClass('SoapService');
$soap->handle();
}
?>
And now you get wsdl (http://ourhost/soap/?wsdl) with you structure and handle request in SoapService::getUserData. Input parametr in this method is object of PeopleInformation class
Basically you need to create a class map and pass it to your soap client. Yes it is a pain. I usually just have a method that maps the Soap Object name to PHP objects (i.e. Person => MY_Person) and only code the ones I need to by hand (i.e createdOn => DateTime).
class MY_WSHelper
{
protected static $ws_map;
public static function make_map()
{
if( ! self::$ws_map)
{
self::$ws_map = array();
//These will be mapped dynamically
self::$ws_map['Person'] = NULL;
self::$ws_map['Animal'] = NULL;
//Hard-coded type map
self::$ws_map['createdOn'] = DateTime;
self::$ws_map['modifiedOn'] = DateTime;
foreach(self::$ws_map as $soap_name => $php_name)
{
if($php_name === NULL)
{
//Map un-mapped SoapObjects to PHP classes
self::$ws_map[$soap_name] = "MY_" . ucfirst($soap_name);
}
}
}
return self::$ws_map;
}
}
Client:
$client = new SoapClient('http://someurl.com/personservice?wsdl',
array('classmap' => MY_WSHelper::make_map()));
$aperson = $client->getPerson(array('name' => 'Bob'));
echo get_class($aperson); //MY_Person
echo get_class($aperson->createdOn); //DateTime
http://php.net/manual/en/soapclient.soapclient.php
Papa Google points me to this Zend article with lots of good examples on both the client and server aspects of working with Soap (in particular PHP5's implementation of it). Looks like a good starting point.
If you're somewhat like me, and cringe at the thought of writing up a WSDL by hand, I'd recommend using WSHelper, which uses PHP's reflection classes to dynamically generate a WSDL for you. Definitely a time-saver
I replay to share my (bad) experience.
I've created a webservice using PHP ZendFramework2 (ZF2).
The server reply objects and array of objects, and until it taken string as input it worked well. I was using the ArrayOfTypeComplex strategy.
$_strategy = new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeComplex();
When I try to use an array of string as input I felt in a dark and unhappy valley until I found Ramil's answer, so I change strategy and all work right!
$_strategy = new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence();
if (isset($_GET['wsdl'])) {
$autodiscover = new \Zend\Soap\AutoDiscover($_strategy);
$autodiscover->setBindingStyle(array('style' => 'document'));
$autodiscover->setOperationBodyStyle(array('use' => 'literal'));
$autodiscover->setClass('Tracker\Queue\Service')
->setUri($_serverUrl);
echo $autodiscover->toXml();
}

Categories