Simple, async SOAP webservice client, built on top of ReactPHP.

Overview

clue/reactphp-soap

CI status installs on Packagist

Simple, async SOAP web service client library, built on top of ReactPHP.

Most notably, SOAP is often used for invoking Remote procedure calls (RPCs) in distributed systems. Internally, SOAP messages are encoded as XML and usually sent via HTTP POST requests. For the most part, SOAP (originally Simple Object Access protocol) is a protocol of the past, and in fact anything but simple. It is still in use by many (often legacy) systems. This project provides a simple API for invoking async RPCs to remote web services.

  • Async execution of functions - Send any number of functions (RPCs) to the remote web service in parallel and process their responses as soon as results come in. The Promise-based design provides a sane interface to working with out of order responses.
  • Async processing of the WSDL - The WSDL (web service description language) file will be downloaded and processed in the background.
  • Event-driven core - Internally, everything uses event handlers to react to incoming events, such as an incoming RPC result.
  • Lightweight, SOLID design - Provides a thin abstraction that is just good enough and does not get in your way. Built on top of tested components instead of re-inventing the wheel.
  • Good test coverage - Comes with an automated tests suite and is regularly tested against actual web services in the wild.

Table of contents

Support us

We invest a lot of time developing, maintaining and updating our awesome open-source projects. You can help us sustain this high-quality of our work by becoming a sponsor on GitHub. Sponsors get numerous benefits in return, see our sponsoring page for details.

Let's take these projects to the next level together! 🚀

Quickstart example

Once installed, you can use the following code to query an example web service via SOAP:

<?php

require __DIR__ . '/vendor/autoload.php';

$browser = new React\Http\Browser();
$wsdl = 'http://example.com/demo.wsdl';

$browser->get($wsdl)->then(function (Psr\Http\Message\ResponseInterface $response) use ($browser) {
    $client = new Clue\React\Soap\Client($browser, (string)$response->getBody());
    $api = new Clue\React\Soap\Proxy($client);

    $api->getBank(array('blz' => '12070000'))->then(function ($result) {
        var_dump('Result', $result);
    });
});

See also the examples.

Usage

Client

The Client class is responsible for communication with the remote SOAP WebService server. It requires the WSDL file contents and an optional array of SOAP options:

$wsdl = '<?xml …';
$options = array();

$client = new Clue\React\Soap\Client(null, $wsdl, $options);

This class takes an optional Browser|null $browser parameter that can be used to pass the browser instance to use for this object. If you need custom connector settings (DNS resolution, TLS parameters, timeouts, proxy servers etc.), you can explicitly pass a custom instance of the ConnectorInterface to the Browser instance and pass it as an additional argument to the Client like this:

$connector = new React\Socket\Connector(array(
    'dns' => '127.0.0.1',
    'tcp' => array(
        'bindto' => '192.168.10.1:0'
    ),
    'tls' => array(
        'verify_peer' => false,
        'verify_peer_name' => false
    )
));

$browser = new React\Http\Browser($connector);
$client = new Clue\React\Soap\Client($browser, $wsdl);

The Client works similar to PHP's SoapClient (which it uses under the hood), but leaves you the responsibility to load the WSDL file. This allows you to use local WSDL files, WSDL files from a cache or the most common form, downloading the WSDL file contents from an URL through the Browser:

$browser = new React\Http\Browser();

$browser->get($url)->then(
    function (Psr\Http\Message\ResponseInterface $response) use ($browser) {
        // WSDL file is ready, create client
        $client = new Clue\React\Soap\Client($browser, (string)$response->getBody());

        // do something…
    },
    function (Exception $e) {
        // an error occured while trying to download the WSDL
    }
);

The Client constructor loads the given WSDL file contents into memory and parses its definition. If the given WSDL file is invalid and can not be parsed, this will throw a SoapFault:

try {
    $client = new Clue\React\Soap\Client(null, $wsdl);
} catch (SoapFault $e) {
    echo 'Error: ' . $e->getMessage() . PHP_EOL;
}

Note that if you have an old version of ext-xdebug < 2.7 loaded, this may halt with a fatal error instead of throwing a SoapFault. It is not recommended to use this extension in production, so this should only ever affect test environments.

The Client constructor accepts an array of options. All given options will be passed through to the underlying SoapClient. However, not all options make sense in this async implementation and as such may not have the desired effect. See also SoapClient documentation for more details.

If working in WSDL mode, the $options parameter is optional. If working in non-WSDL mode, the WSDL parameter must be set to null and the options parameter must contain the location and uri options, where location is the URL of the SOAP server to send the request to, and uri is the target namespace of the SOAP service:

$client = new Clue\React\Soap\Client(null, null, array(
    'location' => 'http://example.com',
    'uri' => 'http://ping.example.com',
));

Similarly, if working in WSDL mode, the location option can be used to explicitly overwrite the URL of the SOAP server to send the request to:

$client = new Clue\React\Soap\Client(null, $wsdl, array(
    'location' => 'http://example.com'
));

You can use the soap_version option to change from the default SOAP 1.1 to use SOAP 1.2 instead:

$client = new Clue\React\Soap\Client(null, $wsdl, array(
    'soap_version' => SOAP_1_2
));

You can use the classmap option to map certain WSDL types to PHP classes like this:

$client = new Clue\React\Soap\Client(null, $wsdl, array(
    'classmap' => array(
        'getBankResponseType' => BankResponse::class
    )
));

The proxy_host option (and family) is not supported by this library. As an alternative, you can configure the given $browser instance to use an HTTP proxy server. If you find any other option is missing or not supported here, PRs are much appreciated!

All public methods of the Client are considered advanced usage. If you want to call RPC functions, see below for the Proxy class.

soapCall()

The soapCall(string $method, mixed[] $arguments): PromiseInterface<mixed, Exception> method can be used to queue the given function to be sent via SOAP and wait for a response from the remote web service.

// advanced usage, see Proxy for recommended alternative
$promise = $client->soapCall('ping', array('hello', 42));

Note: This is considered advanced usage, you may want to look into using the Proxy instead.

$proxy = new Clue\React\Soap\Proxy($client);
$promise = $proxy->ping('hello', 42);

getFunctions()

The getFunctions(): string[]|null method can be used to return an array of functions defined in the WSDL.

It returns the equivalent of PHP's SoapClient::__getFunctions(). In non-WSDL mode, this method returns null.

getTypes()

The getTypes(): string[]|null method can be used to return an array of types defined in the WSDL.

It returns the equivalent of PHP's SoapClient::__getTypes(). In non-WSDL mode, this method returns null.

getLocation()

The getLocation(string|int $function): string method can be used to return the location (URI) of the given webservice $function.

Note that this is not to be confused with the WSDL file location. A WSDL file can contain any number of function definitions. It's very common that all of these functions use the same location definition. However, technically each function can potentially use a different location.

The $function parameter should be a string with the the SOAP function name. See also getFunctions() for a list of all available functions.

assert('http://example.com/soap/service' === $client->getLocation('echo'));

For easier access, this function also accepts a numeric function index. It then uses getFunctions() internally to get the function name for the given index. This is particularly useful for the very common case where all functions use the same location and accessing the first location is sufficient.

assert('http://example.com/soap/service' === $client->getLocation(0));

When the location option has been set in the Client constructor (such as when in non-WSDL mode) or via the withLocation() method, this method returns the value of the given location.

Passing a $function not defined in the WSDL file will throw a SoapFault.

withLocation()

The withLocation(string $location): self method can be used to return a new Client with the updated location (URI) for all functions.

Note that this is not to be confused with the WSDL file location. A WSDL file can contain any number of function definitions. It's very common that all of these functions use the same location definition. However, technically each function can potentially use a different location.

$client = $client->withLocation('http://example.com/soap');

assert('http://example.com/soap' === $client->getLocation('echo'));

As an alternative to this method, you can also set the location option in the Client constructor (such as when in non-WSDL mode).

withHeaders()

The withHeaders(array $headers): self method can be used to return a new Client with the updated headers for all functions. This allows to set specific headers required by some SOAP endpoints, like for authentication, etc.

$client = $client->withHeaders([new SoapHeader(...)]);

Proxy

The Proxy class wraps an existing Client instance in order to ease calling SOAP functions.

$proxy = new Clue\React\Soap\Proxy($client);

Note that this class is called "Proxy" because it will forward (proxy) all method calls to the actual SOAP service via the underlying Client::soapCall() method. This is not to be confused with using a proxy server. See Client documentation for more details on how to use an HTTP proxy server.

Functions

Each and every method call to the Proxy class will be sent via SOAP.

$proxy->myMethod($myArg1, $myArg2)->then(function ($response) {
    // result received
});

Please refer to your WSDL or its accompanying documentation for details on which functions and arguments are supported.

Promises

Issuing SOAP functions is async (non-blocking), so you can actually send multiple RPC requests in parallel. The web service will respond to each request with a return value. The order is not guaranteed. Sending requests uses a Promise-based interface that makes it easy to react to when a request is fulfilled (i.e. either successfully resolved or rejected with an error):

$proxy->demo()->then(
    function ($response) {
        // response received for demo function
    },
    function (Exception $e) {
        // an error occured while executing the request
    }
});

Cancellation

The returned Promise is implemented in such a way that it can be cancelled when it is still pending. Cancelling a pending promise will reject its value with an Exception and clean up any underlying resources.

$promise = $proxy->demo();

Loop::addTimer(2.0, function () use ($promise) {
    $promise->cancel();
});

Timeouts

This library uses a very efficient HTTP implementation, so most SOAP requests should usually be completed in mere milliseconds. However, when sending SOAP requests over an unreliable network (the internet), there are a number of things that can go wrong and may cause the request to fail after a time. As such, timeouts are handled by the underlying HTTP library and this library respects PHP's default_socket_timeout setting (default 60s) as a timeout for sending the outgoing SOAP request and waiting for a successful response and will otherwise cancel the pending request and reject its value with an Exception.

Note that this timeout value covers creating the underlying transport connection, sending the SOAP request, waiting for the remote service to process the request and receiving the full SOAP response. To use a custom timeout value, you can pass the timeout to the underlying Browser like this:

$browser = new React\Http\Browser();
$browser = $browser->withTimeout(10.0);

$client = new Clue\React\Soap\Client($browser, $wsdl);
$proxy = new Clue\React\Soap\Proxy($client);

$proxy->demo()->then(function ($response) {
    // response received within 10 seconds maximum
    var_dump($response);
});

Similarly, you can use a negative timeout value to not apply a timeout at all or use a null value to restore the default handling. Note that the underlying connection may still impose a different timeout value. See also the underlying timeouts documentation for more details.

Install

The recommended way to install this library is through Composer. New to Composer?

This project follows SemVer. This will install the latest supported version:

$ composer require clue/soap-react:^2.0

See also the CHANGELOG for details about version upgrades.

This project aims to run on any platform and thus only requires ext-soap and supports running on PHP 7.1+.

Tests

To run the test suite, you first need to clone this repo and then install all dependencies through Composer:

$ composer install

To run the test suite, go to the project root and run:

$ php vendor/bin/phpunit

The test suite also contains a number of functional integration tests that rely on a stable internet connection. If you do not want to run these, they can simply be skipped like this:

$ php vendor/bin/phpunit --exclude-group internet

License

This project is released under the permissive MIT license.

Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

Comments
  • SoapFault caused by data uri transformation

    SoapFault caused by data uri transformation

    Here is my code that reproduces the problem:

    $loop = \React\EventLoop\Factory::create();
    $browser = new \React\Http\Browser($loop);
    $wsdl = 'https://katastr.cuzk.cz/dokumentace/ws28/wsdp/ciselnik_v28.wsdl';
    
    $browser->get($wsdl)->then(
    	function (\Psr\Http\Message\ResponseInterface $response) use ($browser): void {
    		$client = new \Clue\React\Soap\Client($browser, (string) $response->getBody(), ['exceptions' => true]);
    
    		$client->soapCall('SeznamObci', [['kde' => ['nazevObce' => ['obsahuje' => 'Praha']]]])
    			->then(
    				function ($result): void {
    					var_dump($result);
    				},
    				function (\Throwable $error): void {
    					echo 'ERROR 1' . PHP_EOL;
    					var_dump(get_class($error));
    					var_dump($error->getMessage());
    				}
    			);
    	}
    )->then(
    	null,
    	function (\Throwable $error): void {
    		echo 'ERROR 2' . PHP_EOL;
    		var_dump(get_class($error));
    		var_dump($error->getMessage());
    	}
    );
    
    $loop->run();
    

    It ends with this error:

    ERROR 2
    string(9) "SoapFault"
    string(83) "SOAP-ERROR: Parsing Schema: can't import schema from 'data://text/ciselnik_v28.xsd'"
    

    From what I found out the problem is somehow caused by using a data uri with the wsdl file's content's instead of the original uri.

    If I hack \Clue\React\Soap\Client::__construct() by replacing the linked line with this:

    $wsdl = 'https://katastr.cuzk.cz/dokumentace/ws28/wsdp/ciselnik_v28.wsdl';
    

    then I get the expected error (I didn't provide authentication header):

    ERROR 1
    string(9) "SoapFault"
    string(66) "Error on verifying message against security policy Error code:1000"
    

    What is the purpose of transforming the original wsdl file into a data uri? Any idea why it fails in this case?

    help wanted question 
    opened by enumag 8
  • Get request in response

    Get request in response

    Could it be possible to get the last request in the response of the method call? Same way that SoapClient::__getLastRequest does.

    $api->myMethod($data)->then(
       function ($response){
          // get last request		
       },
       function (Exception $e){
                        
       }
    );
    
    help wanted question new feature 
    opened by francarmona 7
  • Added the possibility to override the webservice location

    Added the possibility to override the webservice location

    Allows to use a custom request-target for soap requests. Based on work from @floriansimon1 in #7.

    I rebased on master, fixed the unit tests and renamed withTarget() to withRequestTarget(). I think this name is better (same name is used in PSR-7: RequestInterface::withRequestTarget()).

    new feature 
    opened by pascal-hofmann 4
  • Support additional SOAP headers

    Support additional SOAP headers

    Hi. How can I set this code?

    $client = new SoapClient($wsdlPath, $options);
    $client->__setSoapHeaders(
                new SoapHeader(
                    'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
                    'Security',
                    new SoapVar($xml, XSD_ANYXML),
                    true
                )
            );
    
    help wanted new feature 
    opened by snezhkoigor 2
  • Improve test suite

    Improve test suite

    The test suite currently only consists of functional tests which send actual SOAP requests against a public SOAP API.

    This means that our test suite is useless if this webservice should (ever) be down.

    We should look into adding proper unit tests and perhaps another functional test case.

    help wanted maintenance 
    opened by clue 2
  • React Soap does not passes the arguments

    React Soap does not passes the arguments

    My client code is:

    var_dump($method, $parameters);
    
            $loop = LoopFactory::create();
            $browser = new Browser($loop);
    
            $promise = $browser->get($this->url)
                ->then(function (ResponseInterface $response) use ($browser, $method, $parameters) {
                    $client = new Client($browser, (string)$response->getBody());
                    return $client->soapCall($method, $parameters);
                });
    
            $loop->run();
    
            return $promise;
    

    method and parameters content is:

    string(3) "add"
    
    array(6) {
      'environment' =>
      string(19) "ger...c"
      'password' =>
      string(16) "..."
      'accessRoles' =>
      array(4) {
        [0] =>
        string(2) "1x"
    ...
      }
      'document' =>
      string(4404) "<?xml ver...eID>"...
      'documentID' =>
      string(2) "83"
      'documentDate' =>
      string(10) "2019-11-14"
    }
    

    But I got an error from SOAP:

    {"code":0,"message":"Not all arguments are provided: environment is required","trace":"#0 \/var\/www\/vendor\/clue\/soap-react\/src\/Protocol\/ClientDecoder.php(31): SoapClient->__soapCall('add', Array)\n#1 \/var\/www\/vendor\/clue\/soap-react\/src\/Client.php(213): Clue\\React\\Soap\\Protocol\\ClientDecoder->decode('add', '<soap:Envelope ...')
    

    That environement is required, but I have passed it. I have looked to ClientDecoder.php(31) and have realized, that there empty Array() instead of arguments is using. Why so?

    question 
    opened by akimkelar 1
  • use with multiple clients

    use with multiple clients

    Hi all, I´m new with React PHP, I want to use this library with multiple clients calling the same webservice. How can I put all the requests from different users to the same $factory ? Thanks for your recomendations.

    question 
    opened by jjdarias 1
  • Explicitly handle non-2xx HTTP status codes

    Explicitly handle non-2xx HTTP status codes

    Currently, we just reject the promise with the RuntimeException from the clue/buzz-react library and do not attempt to parse the body as a SOAP request. Because of this, we can not parse the actual SOAP response when calling a method that is not defined.

    help wanted new feature 
    opened by clue 1
  • Do not follow redirects

    Do not follow redirects

    Following redirects makes little sense because it transforms the POST request to a GET one and hence loses the SOAP request body.

    "If the 301(302/307) status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued. "

    http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

    help wanted new feature 
    opened by clue 1
  •  Simplify usage by updating to new default loop and making Browser optional

    Simplify usage by updating to new default loop and making Browser optional

    This changeset simplifies usage by supporting the new default loop.

    // old (still supported)
    $browser = new React\Http\Browser($loop);
    $client = new Clue\React\Soap\Client($browser, $wsdl, $options);
    
    // new (using default loop)
    $client = new Clue\React\Soap\Client(null, $wsdl, $options);
    

    Builds on top of reactphp/event-loop#226, reactphp/event-loop#229, reactphp/event-loop#232, reactphp/socket#264 and reactphp/http#418

    new feature 
    opened by SimonFrings 0
Releases(v2.0.0)
  • v2.0.0(Oct 28, 2020)

    • Feature / BC break: Update to reactphp/http v1.0.0. (#45 by @SimonFrings)

    • Feature / BC break: Add type declarations and require PHP 7.1+ as a consequence (#47 by @SimonFrings, #49 by @clue)

    • Use fully qualified class names in documentation. (#46 by @SimonFrings)

    • Improve test suite and add .gitattributes to exclude dev files from export. Prepare PHP 8 support, update to PHPUnit 9 and simplify test matrix. (#40 by @andreybolonin, #42 and #44 by @SimonFrings and #48 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Nov 7, 2018)

    • First stable release, now following SemVer!

      I'd like to thank Bergfreunde GmbH, a German-based online retailer for Outdoor Gear & Clothing, for sponsoring large parts of this development! 🎉 Thanks to sponsors like this, who understand the importance of open source development, I can justify spending time and focus on open source development instead of traditional paid work.

      Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details.

    • BC break / Feature: Replace Factory with simplified Client constructor, add support for optional SOAP options and non-WSDL mode and respect WSDL type definitions when decoding and support classmap option. (#31, #32 and #33 by @clue)

      // old
      $factory = new Factory($loop);
      $client = $factory->createClientFromWsdl($wsdl);
      
      // new
      $browser = new Browser($loop);
      $client = new Client($browser, $wsdl);
      

      The Client constructor now accepts an array of options. All given options will be passed through to the underlying SoapClient. However, not all options make sense in this async implementation and as such may not have the desired effect. See also SoapClient documentation for more details.

      If working in WSDL mode, the $options parameter is optional. If working in non-WSDL mode, the WSDL parameter must be set to null and the options parameter must contain the location and uri options, where location is the URL of the SOAP server to send the request to, and uri is the target namespace of the SOAP service:

      $client = new Client($browser, null, array(
          'location' => 'http://example.com',
          'uri' => 'http://ping.example.com',
      ));
      
    • BC break: Mark all classes as final and all internal APIs as @internal. (#26 and #37 by @clue)

    • Feature: Add new Client::withLocation() method. (#38 by @floriansimon1, @pascal-hofmann and @clue)

      The withLocation(string $location): self method can be used to return a new Client with the updated location (URI) for all functions.

      Note that this is not to be confused with the WSDL file location. A WSDL file can contain any number of function definitions. It's very common that all of these functions use the same location definition. However, technically each function can potentially use a different location.

      $client = $client->withLocation('http://example.com/soap');
      
      assert('http://example.com/soap' === $client->getLocation('echo'));
      

      As an alternative to this method, you can also set the location option in the Client constructor (such as when in non-WSDL mode).

    • Feature: Properly handle SOAP error responses, accept HTTP error responses and do not follow any HTTP redirects. (#35 by @clue)

    • Improve documentation and update project homepage, documentation for HTTP proxy servers, support timeouts for SOAP requests (HTTP timeout option) and add cancellation support. (#25, #29, #30 #34 and #36 by @clue)

    • Improve test suite by supporting PHPUnit 6, optionally skip functional integration tests requiring internet and test against PHP 7.2 and PHP 7.1 and latest ReactPHP components. (#24 by @carusogabriel and #27 and #28 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Oct 2, 2017)

    • Feature: Added the possibility to use local WSDL files (#11 by @floriansimon1)

      $factory = new Factory($loop);
      $wsdl = file_get_contents('service.wsdl');
      $client = $factory->createClientFromWsdl($wsdl);
      
    • Feature: Add Client::getLocation() helper (#13 by @clue)

    • Feature: Forward compatibility with clue/buzz-react v2.0 and upcoming EventLoop (#9 by @floriansimon1 and #19 and #21 by @clue)

    • Improve test suite by adding PHPUnit to require-dev and test PHP 5.3 through PHP 7.0 and HHVM and fix Travis build config (#1 by @WyriHaximus and #12, #17 and #22 by @clue)

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Jul 28, 2014)

Owner
Christian Lück
Maintainer of @ReactPHP. Creator of Framework X. Head of @clue-engineering. Professional software engineer using open source to empower web-based projects.
Christian Lück
Simple and universal connection pool for ReactPHP applications.

szado/reactphp-connection-pool Async and flexible pool for any type of connections built on top of ReactPHP. Connection pooling allows you to easily m

shado 2 Apr 30, 2022
Slim Framework view helper built on top of the Twig templating component

Slim Framework Twig View This is a Slim Framework view helper built on top of the Twig templating component. You can use this component to create and

Slim Framework 321 Dec 16, 2022
FrankenPHP is a modern application server for PHP built on top of the Caddy web server

FrankenPHP: Modern App Server for PHP FrankenPHP is a modern application server for PHP built on top of the Caddy web server. FrankenPHP gives superpo

Kévin Dunglas 2.8k Jan 2, 2023
PHPUnit assertions for testing ReactPHP promises

ReactPHP Promises Testing A library that provides a set of convenient assertions for testing ReactPHP promises. Under the hood uses clue/php-block-rea

Sergey Zhuk 30 Dec 8, 2022
Dazzle Async IPC Messaging

Dazzle Async IPC Abstraction Note: This repository is part of Dazzle Project - the next-gen library for PHP. The project's purpose is to provide PHP d

Dazzle PHP 5 Feb 12, 2022
Make observables foreachable using async & await

ReactPHP awaitable observable Installation To install via Composer, use the command below, it will automatically detect the latest version and bind it

Cees-Jan Kiewiet 2 Nov 3, 2022
PHP Kafka client is used in PHP-FPM and Swoole. PHP Kafka client supports 50 APIs, which might be one that supports the most message types ever.

longlang/phpkafka Introduction English | 简体中文 PHP Kafka client is used in PHP-FPM and Swoole. The communication protocol is based on the JSON file in

Swoole Project 235 Dec 31, 2022
Fast php framework written in c, built in php extension

Yaf - Yet Another Framework PHP framework written in c and built as a PHP extension. Requirement PHP 7.0+ (master branch)) PHP 5.2+ (php5 branch) Inst

Xinchen Hui 4.5k Dec 28, 2022
This JSON marshaller is based on the one built into FEAST framework

Standalone JSON marshaller based off the one built into FEAST framework at feast/framework on packagist or feastframework/framework on github

null 13 Dec 9, 2022
PIP is a tiny application framework built for people who use a LAMP stack.

PIP is a tiny application framework built for people who use a LAMP stack. PIP aims to be as simple as possible to set up and use.

Ron Marasigan 244 Dec 30, 2022
Symprowire is a PHP MVC Framework based and built on Symfony, using the ProcessWire CMS as DBAL and Service Provider.

Symprowire - PHP MVC Framework for ProcessWire 3.x Symprowire is a PHP MVC Framework based and built on Symfony using ProcessWire 3.x as DBAL and Serv

Luis Mendez 7 Jan 16, 2022
TCP Worker Client for RoadRunner 2.0 application server

RoadRunner TCP Plugin RoadRunner is an open-source (MIT licensed) high-performance PHP application server, load balancer, and process manager. It supp

Spiral Scout 8 Nov 26, 2022
A Slim PHP MVC framework built just for fun!

Aura Framework A Slim PHP MVC framework built just for fun! en: Note: This repository only contains the core code of the Aura framework. If you want t

Murilo Magalhães Barreto 2 Dec 16, 2021
Hprose asynchronous client & standalone server based on swoole

Hprose for Swoole Introduction Hprose is a High Performance Remote Object Service Engine. It is a modern, lightweight, cross-language, cross-platform,

Hprose 186 Sep 9, 2022
Javascript Minifier built in PHP

JShrink JShrink is a php class that minifies javascript so that it can be delivered to the client quicker. This code can be used by any product lookin

Robert Hafner 25 Oct 8, 2022
PHP Coroutine HTTP client - Swoole Humanization Library

PHP Coroutine HTTP client - Swoole Humanization Library

swlib 973 Dec 17, 2022
JShrink is a php class that minifies javascript so that it can be delivered to the client quicker

JShrink JShrink is a php class that minifies javascript so that it can be delivered to the client quicker. This code can be used by any product lookin

Tedious Developments 677 Nov 16, 2022
Yii2 console application used to write our processors of methods to responsible to client calling.

Microservice Application Skeleton Yii2 console application used to write our processors of methods to responsible to client calling. This application

Jafaripur 0 Mar 10, 2022
A collapsible side navigation menu built to seamlessly work with Bootstrap framework

yii2-widget-sidenav This widget is a collapsible side navigation menu built to seamlessly work with Bootstrap framework. It is built over Bootstrap st

Kartik Visweswaran 36 Apr 9, 2022