How to create RESTfull webservice in Zend framework? - zend-framework

I am new for zend.i need to create web-service in zend using Zend_Json_Server with JSON responce. I have define api controller here..
<?php
class ApiController extends Zend_Controller_Action
{
public function init()
{ }
public function indexAction()
{ }
public function restAction()
{
// disable layouts and renderers
$this->getHelper('viewRenderer')->setNoRender ( true );
// initialize REST server
$server = new Zend_Json_Server();
// set REST service class
$server->setClass('Test_Return');
// handle request
if ('GET' == $_SERVER['REQUEST_METHOD']) {
$server->setTarget('/json-rpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smd = $server->getServiceMap();
// Set Dojo compatibility:
// $smd->setDojoCompatible(true);
header('Content-Type: application/json');
echo $smd;
}
$server->handle();
}
}
?>
And Test_Return define in Library/Test
Test_Return code is here..
<?php
class Test_Return {
public function add($x, $y)
{
return $x + $y;
}
public function subtract($x, $y)
{
return $x - $y;
}
public function multiply($x, $y)
{
return $x * $y;
}
public function divide($x, $y)
{
return $x / $y;
}
} ?>
How can call particular expression.

As describe in here on your index you create an instance of the zend_rest_server add your methods and run it. The methods should be specified in the url. I sugest you chose zend 2 for better implementation

The Zend_Json_Server initialization should be in your public/index.php
defined('APPLICATION_PATH') ||
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
defined('APPLICATION_ENV') ||
define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/libs',
get_include_path(),
)));
require_once 'Zend/Application.php';
$application = new Zend_Application(
APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$application->getBootstrap()->bootstrap();
// Instantiate server ...
$server = new Zend_Json_Server();
include_once APPLICATION_PATH . '/Calculator.php';
$server->setClass(new Calculator());
if ('GET' == $_SERVER['REQUEST_METHOD'])
{
// Indicate the URL endpoint, and the JSON-RPC version used:
$server->setTarget('/api/1.0/jsonrpc.php')->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
// Grab the SMD
$smd = $server->getServiceMap();
// Return the SMD to the client
header('Content-Type: application/json');
echo $smd;
return;
}
$server->handle();
$application->bootstrap()->run();
With curl on the command line you wont see anything ;-). This frustrated me a bit.
curl -H "Content-Type: application/json" -d '{"method":"add","x":5,"y":10}' http://zend.rest.server/api/1.0/jsonrpc.php
On the browser you can use this jQuery plugin
app = jQuery.Zend.jsonrpc({url: '/api/1.0/jsonrpc'});
app.add(5, 5);
{"result":10,"id":"1","jsonrpc":"2.0"}
You maybe want to follow the steps as describe here.
I suggest that you apgrade your version of zend if you can as zend2.X.X has better support for rest services.

Related

Slim 4 get all routes into a controller without $app

I need to get all registed routes to work with into a controller.
In slim 3 it was possible to get the router with
$router = $container->get('router');
$routes = $router->getRoutes();
With $app it is easy $routes = $app->getRouteCollector()->getRoutes();
Any ideas?
If you use PHP-DI you could add a container definition and inject the object via constructor injection.
Example:
<?php
// config/container.php
use Slim\App;
use Slim\Factory\AppFactory;
use Slim\Interfaces\RouteCollectorInterface;
// ...
return [
App::class => function (ContainerInterface $container) {
AppFactory::setContainer($container);
return AppFactory::create();
},
RouteCollectorInterface::class => function (ContainerInterface $container) {
return $container->get(App::class)->getRouteCollector();
},
// ...
];
The action class:
<?php
namespace App\Action\Home;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Response;
use Slim\Http\ServerRequest;
use Slim\Interfaces\RouteCollectorInterface;
final class HomeAction
{
/**
* #var RouteCollectorInterface
*/
private $routeCollector;
public function __construct(RouteCollectorInterface $routeCollector)
{
$this->routeCollector = $routeCollector;
}
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
{
$routes = $this->routeCollector->getRoutes();
// ...
}
}
This will display basic information about all routes in your app in SlimPHP 4:
$app->get('/tests/get-routes/', function ($request, $response, $args) use ($app) {
$routes = $app->getRouteCollector()->getRoutes();
foreach ($routes as $route) {
echo $route->getIdentifier() . " → ";
echo ($route->getName() ?? "(unnamed)") . " → ";
echo $route->getPattern();
echo "<br><br>";
}
return $response;
});
From there, one can use something like this to get the URL for a given route:
$routeParser = \Slim\Routing\RouteContext::fromRequest($request)->getRouteParser();
$path = $routeParser->urlFor($nameofroute, $data, $queryParams);
With the following caveats:
this will only work for named routes;
this will only work if the required route parameters are provided -- and there's no method to check whether a route takes mandatory or optional route parameters.
there's no method to get the URL for an unnamed route.

Slim 3 - replacement for isPost()?

In Slim 2, I would do this,
$app->map('/login', function () use ($app) {
// Test for Post & make a cheap security check, to get avoid from bots
if ($app->request()->isPost() && sizeof($app->request()->post()) >= 2) {
//
}
// render login
$app->render('login.twig');
})->via('GET','POST')->setName('login');
But in Slim 3,
// Post the login form.
$app->post('/login', function (Request $request, Response $response, array $args) {
// Get all post parameters:
$allPostPutVars = $request->getParsedBody();
// Test for Post & make a cheap security check, to get avoid from bots
if ($request()->isPost() && sizeof($allPostPutVars) >= 2) {
///
}
});
I get this error,
Fatal error: Function name must be a string in C:...
Obviously that isPost() is deprecated, so what should I use instead in Slim 3 for isPost's replacement?
In Slim 4, there's no such helper and so the syntax gets longer (like a lot of Slim 4 stuff):
$request->getMethod() === 'POST'
According to documentation and comments, Slim supports these proprietary methods:
$request->isGet()
$request->isPost()
$request->isPut()
$request->isDelete()
$request->isHead()
$request->isPatch()
$request->isOptions()
Here it is an example of usage:
<?php
require 'vendor/autoload.php';
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
$app = new \Slim\App;
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH', 'OPTIONS'], '/', function (ServerRequestInterface $request, ResponseInterface $response) {
echo "isGet():" . $request->isGet() . "<br/>";
echo "isPost():" . $request->isPost() . "<br/>";
echo "isPut():" . $request->isPut() . "<br/>";
echo "isDelete():" . $request->isDelete() . "<br/>";
echo "isHead():" . $request->isHead() . "<br/>";
echo "isPatch():" . $request->isPatch() . "<br/>";
echo "isOptions():" . $request->isOptions() . "<br/>";
return $response;
});
$app->run();

Zend framework 2 - standalone forms

Is it possible to use the ZF2 forms a as standalone component? This was possible with ZF1, but I can't figure it out with ZF2.
I can create a form and a validator, but can't figure out how to render the form:
$form = new AddressBookForm('address_book'); \\ extends Zend\Form\Form
if ($this->input->isPost()) {
$validator = new AddressBookValidator(); \\ implements Zend\InputFilter\InputFilterAwareInterface
$form->setInputFilter($validator->getInputFilter());
$form->setData($this->input->getPost());
if ($form->isValid()) {
echo 'valid'; exit;
}
}
// Render form somehow here???
I tried creating a view, but couldn't figure out how to give it the view helpers. Thanks.
I have a basic solution, that seems to do the job
$zfView = new \Zend\View\Renderer\PhpRenderer();
$plugins = $zfView->getHelperPluginManager();
$config = new Zend\Form\View\HelperConfig;
$config->configureServiceManager($plugins);
and then render the form
echo $zfView->form()->openTag($form);
echo $zfView->formRow($form->get('name'));
echo $zfView->formSubmit( $form->get('submit'));
echo $zfView->form()->closeTag();
Checkout this blog.
Form Render in View file
you can do simply by zend framework form view helper.
$form = $this->form;
$form->prepare();
$this->form()->render($form);
#CodeMonkey's method is a good one but the code is incomplete. I cobbled together a working example from his and other answers I found with partial code.
<?php
/*
* #author Carl McDade
*
* #since 2012-06-11
* #version 0.2
*
*/
namespace zftest;
$path = DOCROOT .'/_frameworks/zf/ZendFramework-2.2.2/library';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
require_once($path . '/Zend/Loader/StandardAutoloader.php');
use Zend\Loader;
use Zend\Http\Request;
use Zend\Http\Client;
use Zend\Captcha;
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\Form\Form;
use Zend\Form\FormInterface;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Form\View\Helper;
use \Common;
class zftest{
function __construct()
{
spl_autoload_register(array($this, '_zftest_autoload'));
}
function _zftest_autoload($class)
{
//
$loader = new \Zend\Loader\StandardAutoloader(array('autoregister_zf' => true));
$loader->registerNamespaces(array('Zend'));
// finally send namespaces and prefixes to the autoloader SPL
$loader->register();
return;
}
function zftest()
{
$uri = 'http://maps.google.com/maps/api/geocode/json';
$address = urlencode('berlin');
$sensor = 'false';
$request = new Request();
$request->setUri($uri);
$request->setMethod('GET');
$client = new Client($uri);
$client->setRequest($request);
$client->setParameterGet(array('sensor'=>$sensor,'address'=>$address));
$response = $client->dispatch($request);
if ($response->isSuccess()) {
print 'Your Request for:<pre>' . print_r($address, 1) . '</pre>';
print '<pre>' . print_r($response->getBody(), 1) . '</pre>';
}
}
function zfform()
{
// Zend Framework 2 form example
$name = new Element('name');
$name->setLabel('Your name');
$name->setAttributes(array(
'type' => 'text'
));
$email = new Element\Email('email');
$email->setLabel('Your email address');
$subject = new Element('subject');
$subject->setLabel('Subject');
$subject->setAttributes(array(
'type' => 'text'
));
$message = new Element\Textarea('message');
$message->setLabel('Message');
$captcha = new Element\Captcha('captcha');
$captcha->setCaptcha(new Captcha\Dumb());
$captcha->setLabel('Please verify you are human');
$csrf = new Element\Csrf('security');
$send = new Element('send');
$send->setValue('Submit');
$send->setAttributes(array(
'type' => 'submit'
));
$form = new Form('contact');
$form->add($name);
$form->add($email);
$form->add($subject);
$form->add($message);
$form->add($captcha);
$form->add($csrf);
$form->add($send);
$nameInput = new Input('name');
// configure input... and all others
$inputFilter = new InputFilter();
// attach all inputs
$form->setInputFilter($inputFilter);
$zfView = new \Zend\View\Renderer\PhpRenderer();
$plugins = $zfView->getHelperPluginManager();
$config = new \Zend\Form\View\HelperConfig;
$config->configureServiceManager($plugins);
$output = $zfView->form()->openTag($form) . "\n";
$output .= $zfView->formRow($form->get('name')) . "<br />\n";
$output .= $zfView->formRow($form->get('captcha')) . "<br />\n";
$output .= $zfView->formSubmit( $form->get('send')) . "<br />\n";
$output .= $zfView->form()->closeTag() . "\n";
echo $output;
}
}
?>
You can use the Zend\Form\View\Helper view helpers to render the form inside a view.
Example: (view context)
My Form:
<?php echo $this->form()->openTag($this->form); ?>
<?php echo $this->formCollection($this->form); ?>
<?php echo $this->form()->closeTag($this->form); ?>
Note that $this->form is the $form variable assigned to the view. Also, view helpers are always available in views as far as they are registered as invokables (this is always true for built-in helpers).
This would render all elements inside a <form ...> ... </form> tag.
Check the other view helpers for further information.
Also, see the example docs: http://zf2.readthedocs.org/en/latest/modules/zend.form.quick-start.html
There's a lot more you can do with this.
None of the simpler answers helped me since I did not have Service Manager set up nor the View Helper methods.
But in a hurry this worked for me:
$checkbox = new Element\Checkbox('checkbox');
$checkbox->setLabel('Label');
$checkbox->setCheckedValue("good");
$checkbox->setUncheckedValue("bad");
$form = new FormCheckbox();
echo $form->render($checkbox);

How do I combine Zend_Ath, Zend_Acl and partialview for the authentication and resource control

According to Randomness will get you everywhere.
Ryan’s Blog
the action stack component of Zend Framework is un-needed and that a partial view can be combined with Zend_Acl and Zend_Auth for the purpose of authenticating and controlling resources.
I have not been able to find any suitable example on google about how its done. Will be glad is someone will be kind to show me how to implement this. Thanks
Here you go:
You could use the combination of Zend_Auth and Zend_Acl. To extend the other answers I give a short example of how you can manage authentication using zend framework:
First you need to setup a plugin to predispatch all requests and check if the client is allowed to access certain data. This plugin might look like this one:
class Plugin_AccessCheck extends Zend_Controller_Plugin_Abstract {
private $_acl = null;
public function __construct(Zend_Acl $acl) {
$this->_acl = $acl;
}
public function preDispatch(Zend_Controller_Request_Abstract $request) {
//get request information
$module = $request->getModuleName ();
$resource = $request->getControllerName ();
$action = $request->getActionName ();
try {
if(!$this->_acl->isAllowed(Zend_Registry::get('role'),
$module . ':' . $resource, $action)){
$request->setControllerName ('authentication')
->setActionName ('login');
}
}catch(Zend_Acl_Exception $e) {
$request->setControllerName('index')->setActionName ('uups');
}
}
}
So every user type has certain permissions that you define in your acl library. On every request you check if the user is allowed to access a resource. If not you redirect to login page, else the preDispatch passes the user to the resource.
In Zend_Acl you define roles, resources and permission, that allow or deny access, e.g.:
class Model_LibraryAcl extends Zend_Acl {
public function __construct() {
$this->addRole(new Zend_Acl_Role('guests'));
$this->addRole(new Zend_Acl_Role('users'), 'guests');
$this->addRole(new Zend_Acl_Role('admins'), 'users');
$this->add(new Zend_Acl_Resource('default'))
->add(new Zend_Acl_Resource('default:authentication'), 'default')
->add(new Zend_Acl_Resource('default:index'), 'default')
->add(new Zend_Acl_Resource('default:error'), 'default');
$this->allow('guests', 'default:authentication', array('login'));
$this->allow('guests', 'default:error', 'error');
$this->allow('users', 'default:authentication', 'logout');
}
}
Then you have to setup acl and auth in your bootstrap file:
private $_acl = null;
protected function _initAutoload() {
//...your code
if (Zend_Auth::getInstance()->hasIdentity()){
Zend_Registry::set ('role',
Zend_Auth::getInstance()->getStorage()
->read()
->role);
}else{
Zend_Registry::set('role', 'guests');
}
$this->_acl = new Model_LibraryAcl ();
$fc = Zend_Controller_Front::getInstance ();
$fc->registerPlugin ( new Plugin_AccessCheck ( $this->_acl ) );
return $modelLoader;
}
Finally in your authentication controller you have to use a custom auth adapter and setup actions for login and logout:
public function logoutAction() {
Zend_Auth::getInstance ()->clearIdentity ();
$this->_redirect ( 'index/index' );
}
private function getAuthAdapter() {
$authAdapter = new Zend_Auth_Adapter_DbTable (
Zend_Db_Table::getDefaultAdapter ());
$authAdapter->setTableName('users')
->setIdentityColumn('email')
->setCredentialColumn ('password')
->setCredentialTreatment ('SHA1(CONCAT(?,salt))');
return $authAdapter;
}
In your login action you need to pass login data to the auth adapter which performs the authentication.
$authAdapter = $this->getAuthAdapter ();
$authAdapter->setIdentity ( $username )->setCredential ( $password );
$auth = Zend_Auth::getInstance ();
$result = $auth->authenticate ( $authAdapter );
if ($result->isValid ()) {
$identity = $authAdapter->getResultRowObject ();
if ($identity->approved == 'true') {
$authStorage = $auth->getStorage ();
$authStorage->write ( $identity );
$this->_redirect ( 'index/index' );
} else {
$this->_redirect ( 'authentication/login' );
}
And that's all. I recommend you this HOW TO on youtube on zend auth and zend acl.
You may find the following articles on Action Helpers useful, I recommend browsing the sites if any are new to you as they also have articles on implementing Zend_Auth:
Using Action Helpers To Implement Re-Usable Widgets by Matthew Weier O'Phinney
Introducing Action Helpers by Jon Lebensold
Using Action Helpers in Zend Framework by Rob Allen
ZF Reference Guide: Action Helpers Official Documentation

Sending a SOAP message with PHP

what I'm trying to do is send a load of values captured from a form to a CRM system with SOAP and PHP. I've been reading up on SOAP for a while and I don't understand how to go about doing so, does anybody else know?
In order to do this it might be easiest to download a simple soap toolkit like 'NuSOAP' from sourceforge.
And then you would code something like the following (example submission of ISBN number):
<?php
// include the SOAP classes
require_once('nusoap.php');
// define parameter array (ISBN number)
$param = array('isbn'=>'0385503954');
// define path to server application
$serverpath ='http://services.xmethods.net:80/soap/servlet/rpcrouter';
//define method namespace
$namespace="urn:xmethods-BNPriceCheck";
// create client object
$client = new soapclient($serverpath);
// make the call
$price = $client->call('getPrice',$param,$namespace);
// if a fault occurred, output error info
if (isset($fault)) {
print "Error: ". $fault;
}
else if ($price == -1) {
print "The book is not in the database.";
} else {
// otherwise output the result
print "The price of book number ". $param[isbn] ." is $". $price;
}
// kill object
unset($client);
?>
This code snippet was taken directly from, which is also a good resource to view
http://developer.apple.com/internet/webservices/soapphp.html
Hope this helps.
You probably found a solution since then - but maybe the following helps someone else browsing for this:
soap-server.php:
<?php
class MySoapServer {
public function getMessage ()
{
return "Hello world!";
}
public function add ($n1,$n2)
{
return $n1+n2;
}
}
$option = array ('uri' => 'http://example.org/stacky/soap-server');
$server = new SoapServer(null,$option);
$server->setClass('MySoapServer');
$server->handle();
?>
and soap-client.php
<?php
$options = array ('uri' => 'http://example.org/stacky/soap-server',
'location' => 'http://localhost/soap-server.php');
$client = new SoapClient(null,$options);
echo $client ->getMessage();
echo "<br>";
echo $client ->add(41,1);
?>