usemuffin / webservice Goto Github PK
View Code? Open in Web Editor NEWBringing the power of the CakePHP ORM to your favourite webservices
License: MIT License
Bringing the power of the CakePHP ORM to your favourite webservices
License: MIT License
Is there a version that can used with CakePHP 4.x
<?php
// ExampleWebservice
public funcion __construct(array $config = [])
{
parent::__construct($config);
$this->driver(new ExampleDriver());
}
// ExampleDriver
public function initialize()
{
$this->webservice(new ExampleWebservice());
}
// Setup the Endpoint
$endpoint = new ExampleEndpoint([
'connection' => new ExampleDriver(),
'endpoint' => 'Example'
]);
Fatal error: Maximum function nesting level of '256' reached, aborting! in /Users/david/Sites/gaia-supply/vendor/muffin/webservice/src/Webservice/Webservice.php on line 52
I'd just expect the relevant settings to be setup in each class
#In the latest version of debugkit, they use setLogger() instead of logger().
https://github.com/cakephp/debug_kit/blame/0d70858a4f01d24f17514ee2f9dc0f0c92f4f3e8/src/Panel/SqlLogPanel.php#L67
So it creates an exception because the returned logger is not an instance of the Psr\Log\LoggerInterface
This could be the solution
2882e91
ref : cakephp/debug_kit#624
I have been successfully able to get a read query working, but unable to get create and update working. I've looked through community examples but I'm unable to find any examples of doing create, update and delete calls from the controller. Does anyone have an example of how they would look? My confusion is arising from normally using patchEntity then save, however, an entity is not applicable.
I'm trying to connect to a Magento 2 REST API
POST /V1/products
PUT /V1/products/:sku
DELETE /V1/products/:sku
GET /V1/products
GET /V1/products/:sku
My api response contains a meta element with the pagination data for the response.
{
"meta": {
"pagination": {
"page": 1,
"next_page": 2,
"previous_page": null,
"total_results": 102,
"total_pages": 6,
"per_page": 20
}
},
"body": {
"results": [
{
"id": 530,
"name": "Unlimited Broadband",
// etc
However when the response is parsed into a Resource
this data is lost. I can't see it in Muffin\Webservice\Query
which makes sense as it's not been executed yet. However when it is executed it will be converted into a Resource, so it's lost then also.
I would rather know from the preceding request if there is a next page or not rather than intentionally making a 404 request to find the last page.
I am creating a ticket for myself to polish off the final few bits that might be needed to get the plugin to a stage where we can issue a release.
I have created an example application for testing. https://github.com/davidyell/Example-MuffinWebservice
@ADmad If you can think of anything else, or would like to do some testing yourself, please let me know if there are outstanding items and I will get them done.
I'm keen to get 2.0 released, so I can start working on the Pagination and Form Context
I was writing my Webservice class, and wanted to get the endpoint to add to my url, in the _executeReadQuery
method.
$apiUrl = 'https://example.com/api/v1/';
/* @var $endpoint \Muffin\Webservice\Model\Endpoint */
$endpoint = $query->repository()->endpoint();
$endpointUrl = $apiUrl . $endpoint->endpoint();
I found calling endpoint()
on the repository returning an Endpoint class instance, yet, calling endpoint()
on the Endpoint, returned a string.
I would probably change the names to be more descriptive of what they're actually doing. I'm easy on the use of getter/setters, but I'd prefer they were used.
$apiUrl = 'https://example.com/api/v1/';
/* @var $endpoint \Muffin\Webservice\Model\Endpoint */
$endpoint = $query->repository()->getEndpoint();
$endpointUrl = $apiUrl . $endpoint->getName();
I can obviously submit a pull request for this, but as it would break BC, I would like some input from other people. As it would probably mean a new major release as well.
@Marlinc Please correct me if I'm wrong but I think this condition will throw a warning almost everytime, when an empty string will be marshalled: https://github.com/UseMuffin/Webservice/blob/master/src/Marshaller.php#L71
It's probably a copy/paste issue from Cake's ORM but this will return usually a string: https://github.com/UseMuffin/Webservice/blob/master/src/Marshaller.php#L53
On Cake's ORM it will always return an array, why it works there: https://github.com/cakephp/cakephp/blob/master/src/Database/Schema/Table.php#L505
Please can you push a release for this, as the codebase hasn't changed at all in a few months, a nice 0.0.1
would be ace so I don't see dev-master
lurking in my composer file.
Thanks!
Are there any plans for CakePHP 5.x compatibility?
Cakephp 3.10
Webservice 2.10
I use webservice package to get remote data like this:
{
"id": 37744,
"name": "A19-R35",
"latitude": 40.427244444444,
"timestamp": 1633612408,
"longitude": 17.477786666667
},
{
"id": 37776,
"name": "A99-S440T",
"latitude": 40.427088888889,
"timestamp": 1633611825,
"longitude": 17.47781
},
{
"id": 37821,
"name": "A134-S180",
"latitude": 41.626684444444,
"timestamp": 1627731959,
"longitude": 13.319757777778
},
{
"id": 38066,
"name": "A139-S440T",
"latitude": 38.055973333333,
"timestamp": 1633562464,
"longitude": 13.113187777778
},
{
"id": 38353,
"name": "A29-V380",
"latitude": 40.4250433,
"timestamp": 1633611852,
"longitude": 17.4824466
},
{
"id": 38696,
"name": "A62-S190",
"latitude": 40.94256,
"timestamp": 1633601755,
"longitude": 9.5173666
},
{
"id": 38750,
"name": "A40-VM90",
"latitude": 40.7200366,
"timestamp": 1633411097,
"longitude": 8.6301933
},
{
"id": 38751,
"name": "A46-S190",
"latitude": 40.6871316,
"timestamp": 1633593958,
"longitude": 8.62475
},
{
"id": 38760,
"name": "A96-l75",
"latitude": 39.8879566,
"timestamp": 1633593014,
"longitude": 8.5964433
},
{
"id": 38786,
"name": "A137-ACM90",
"latitude": 39.3558099,
"timestamp": 1633604014,
"longitude": 9.05761
},
{
"id": 38787,
"name": "A38-VM90",
"latitude": 39.9739633,
"timestamp": 1633429440,
"longitude": 9.6387783
},
{
"id": 38790,
"name": "A134-S180",
"latitude": 39.35592,
"timestamp": 1633606331,
"longitude": 9.0577099
},
{
"id": 38791,
"name": "A49-I90",
"latitude": 39.3560433,
"timestamp": 1633602699,
"longitude": 9.057675
},
{
"id": 38829,
"name": "A25-R293",
"latitude": 42.566625,
"timestamp": 1633611572,
"longitude": 12.9755516
}
]
If I do a get:
$this->Vehicles->get(38751);
or a find with conditions:
$this->Vehicles->find()->where(['id' => 38751])->toArray()
return same the first element of list:
{
"id": 37744,
"name": "A19-R35",
"latitude": 40.427244444444,
"timestamp": 1633612675,
"longitude": 17.477786666667
}
Webservice twitter does not implement isQueryLoggingEnabled
Muffin\Webservice\Exception\UnimplementedWebserviceMethodException
vendor/cakephp/debug_kit/src/Panel/SqlLogPanel.php triggers this in the if ($connection->isQueryLoggingEnabled()) {
call.
With CakePHP 3.7+
I've error to match the edit object. Cake 3.6 try to find
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'xxx.resources' doesn't exist
This is the code under UsersWebservice
$resource = $this->_transformResource(new UsersEndpoint(), $resultArray);
return new ResultSet([$resource], 1);
and returning this object format
Muffin\Webservice\Model\Resource Object
(
[id] => 3
[username] => abc
[fullname] => ABC
[email] => [email protected]
[group_id] => 1
[tenant_id] => 1
[team_id] => 0
[tenant] => stdClass Object
(
[id] => 1
[code] => xxx
[name] => xxx
[active] => 1
[created] => 2018-11-08T13:00:00
[modified] => 2018-11-08T13:00:00
)
[group] => stdClass Object
(
[id] => 1
[code] => SA
[description] => Super Admin
[tenant_id] => 0
)
[[new]] =>
Any suggestion
Hi,
I'm trying to understand if it is possible to get add related resources to response.
I do a request to the API to get messages, the response contains an array of the user that it posted id. simple example:
{
"id": "36f23f2bc90d35f0",
"created": "2020-06-24T09:27:40.217+00:00",
"body": "This is a message",
"user": {
"id": 1,
"name": "jan",
"email": "[email protected]"
}
}
is it possible some way that the user array transforms to a User resource inside the Message Resource? At the moment when I do $this->_transformResults($query->endpoint(), $messages);
it will returns a MessageResource with an array instead of user resource.
I'm trying use this lib, but always return Missing Datasource Configuration
It should be possible to use CrudView with the Webservice plugin. For this quite a few things have to happen.
Some of the things that need to change:
\Cake\Datasource\RepositoryInterface
FriendsOfCake/search#79\Search\Model\Behavior\SearchBehavior
needs to be somehow compatible with \Muffin\Webservice\Model\Endpoint
classes. Possibly by using traits. Interesting PR: cakephp/elastic-search#83.\Search\Model\Filter\Value
). Currently the only way to use Search is to use the \Search\Model\Filter\Callback
filter.\Cake\Datasource\EntityInterface
(for example in the CrudViewHelper
)\Muffin\Webservice\Query
needs to have the contain
method\Muffin\Webservice\Endpoint
requires some notion of defining associations.It might be necessary to change the CakePHP core to add more methods to specific interfaces. Some of the things that need to be made:
\Cake\Datasource\AssociationInterface
to describe a general association between two RepositoryInterface
implementations. cakephp/cakephp#9002.Created the Model/Endpoint/IplookupEndpoint.php
and Model/Resource/Iplookup.php
files. Then loaded my model and hit the endpoint.
public function iplookup()
{
$this->loadModel('Gaia/Supply.Iplookup', 'Endpoint');
$ipData = $this->Iplookup->find()
->where(['ip' => $this->request->query('ip')])
->execute();
$this->set('ipData', $ipData);
}
I would expect a single Iplookup
resource back.
I got a TypeError
exception.
Argument 2 passed to Muffin\Webservice\Webservice\Webservice::_transformResource() must be of the type array, string given, called in /Users/david/Sites/Gaia/vendor/muffin/webservice/src/Webservice/Webservice.php on line 321
{
"success": true,
"data": {
"city": {
"city": {
"geoname_id": 5375480,
"names": {
"de": "Mountain View",
"en": "Mountain View",
"fr": "Mountain View",
"ja": "マウンテンビュー",
"ru": "Маунтин-Вью",
"zh-CN": "芒廷维尤"
}
},
"continent": {
"code": "NA",
"geoname_id": 6255149,
"names": {
"de": "Nordamerika",
"en": "North America",
"es": "Norteamérica",
"fr": "Amérique du Nord",
"ja": "北アメリカ",
"pt-BR": "América do Norte",
"ru": "Северная Америка",
"zh-CN": "北美洲"
}
},
"country": {
"geoname_id": 6252001,
"iso_code": "US",
"names": {
"de": "USA",
"en": "United States",
"es": "Estados Unidos",
"fr": "États-Unis",
"ja": "アメリカ合衆国",
"pt-BR": "Estados Unidos",
"ru": "Сша",
"zh-CN": "美国"
}
},
"location": {
"latitude": 37.386,
"longitude": -122.0838,
"metro_code": 807,
"time_zone": "America/Los_Angeles"
},
"postal": {
"code": "94040"
},
"registered_country": {
"geoname_id": 6252001,
"iso_code": "US",
"names": {
"de": "USA",
"en": "United States",
"es": "Estados Unidos",
"fr": "États-Unis",
"ja": "アメリカ合衆国",
"pt-BR": "Estados Unidos",
"ru": "Сша",
"zh-CN": "美国"
}
},
"subdivisions": [
{
"geoname_id": 5332921,
"iso_code": "CA",
"names": {
"de": "Kalifornien",
"en": "California",
"es": "California",
"fr": "Californie",
"ja": "カリフォルニア州",
"pt-BR": "Califórnia",
"ru": "Калифорния",
"zh-CN": "加利福尼亚州"
}
}
],
"traits": {
"ip_address": "8.8.8.8"
}
},
"isp": "Level 3 Communications",
"provider": false
}
}
I think that the Webservice::_transformResults
is assuming that the return is an array of items, and not a single item. As such it's using a foreach
loop and making an assumption that each value in the array should also be an array.
What i did:
/PayPalApi/src/Webservice/PayPalProductsWebservice.php
/PayPalApi/src/Model/Endpoint/Schema/PayPalProductSchema.php
/PayPalApi/src/Model/Resource/PayPalProduct.php
$expectedClass = \get_class(FactoryLocator::get('Endpoint')->get('PayPalApi.PayPalProducts')->newEmptyEntity())
debug($expectedClass);
What i got:
Muffin\Webservice\Model\Resource
What i expected:
PayPalApi\Model\Resource\PayPalProduct
Work around:
Creating /PayPalApi/src/Model/Endpoint/PayPalProductsEndpoint.php
with empty class that extends \Muffin\Webservice\Model\Endpoint
changes code result to expected one
PayPalProduct class should be used without requirement of creating empty custom PayPalProductsEndpoint class
The Query->count()
contains the following line:
return $this->__resultSet->total();
But the Query->_execute()
method assigns directly the result of the webservice request to $this->__resultSet
without checking the returned type:
return $this->__resultSet = $this->_webservice->execute($this);
and according to the doc, the WebserviceInterface->execute()
function may return a ResultSet, but also an integer or a boolean:
@return \Muffin\Webservice\ResultSet|int|bool
Therefore for example if the webservice request fails and returns false
, $this->__resultSet
does not have any total()
method and an error is raised.
A solution could be :
if(method_exists($this->__resultSet, 'total')) {
return $this->__resultSet->total();
} else {
return false;
}
or
if(is_a($this->__resultSet, '\Cake\Datasource\ResultSetInterface')) {
return $this->__resultSet->total();
} else {
return false;
}
What I did
Installed the plugin using composer. Created a new driver App\Lib\SamKnows\Driver\SamKnows.php
. Extended it from the AbstractDriver
and implemented the method stubs.
Then I added the ConnectionManager::config(Configure::consume('Webservices'));
as per the docs over here.
What happened
I got an exception for a missing datasource.
Error: Datasource class Webservices could not be found. Datasource class Webservices could not be found.
⟩ Cake\Datasource\ConnectionRegistry->_throwMissingClassError CORE/src/Core/ObjectRegistry.php, line 87
I believe the problem lays here.
⟩ DebugKit\Panel\SqlLogPanel->initialize ROOT/vendor/cakephp/debug_kit/src/Routing/Filter/DebugBarFilter.php, line 159
What I expected
I expected my application would just be able to render my homepage as normal.
/cc @markstory
A driver with a class of 'App\Webservice\Driver\FreshService' ends up trying to load a datasource named 'app' instead of something like Webservice\FreshService pr Driver\FreshService. I've tracked down the issue to Webservice/src/Model/Endpoint.php function defaultConnectionName(): string
I'm new to this framework however the default behavior of looking for Datasource > app didn't seem quite right.
Hello,
I am new to using your package, and I want to share the following issue on one of your dev branches.
The class Muffin\Webservice\Datasource\Query is causing the following Fatal Error, as the method signature is not compliant with the one in CakePHP's QueryTrait :
Declaration of Muffin\Webservice\Datasource\Query::_execute() must be compatible with Cake\Datasource\QueryTrait::_execute(): Cake\Datasource\ResultSetInterface in /var/www/html/vendor/muffin/webservice/src/Datasource/Query.php on line 549
This error occured on branch cake-4.x
, as I am using CakePHP 4.2.
Best regards and thanks for your work on this package !
Has anyone has any luck with an endpoint that returns an image?
I get the error:
Argument 2 passed to Muffin\Webservice\Webservice\Webservice::_transformResource() must be of the type array, null given, called in .../vendor/muffin/webservice/src/Webservice/Webservice.php
In CakePHP 3.5 classes using ValidatorAwareTrait
must have BUILD_VALIDATOR_EVENT
constant defined. In this case Muffin\Webservice\Model\Endpoint
class. Currently causing "Undefined class constant 'BUILD_VALIDATOR_EVENT'" exception.
So, I'm trying out Webservice plugin for Cake 4.
I've created a Driver and using as a Driver works just fine.
But, when I try to use as a WebService, I got this php error.
explode() expects parameter 2 to be string, null given
Webservice/src/Model/EndpointLocator.php
Line 78 in 3e01f3b
Since $alias = 'Posts
(my controller), pluginSplit($alias)[0]
is null.
And the explode
method cannot accept null as the second parameter.
I'm trying to figure out what $connectionName
is expecting in this scenario because it could be null if $pluginParts is null.
$connectionName = Inflector::underscore(end($pluginParts));
Can you help me clarify that?
Is that a bug?
Thanks in advanced
If you try to create custom Resource subclass as shown here: Endpoint->getResourceClass() method will always return null instead of class name. This will then cause Fatal Error here:
https://github.com/UseMuffin/Webservice/blob/2.0.0-RC1/src/Webservice/Webservice.php#L384
Tested on CakePHP 3.6.12 & Webservice 2.0.0-RC1
I have configured the driver and the webservice class, with my resources and endpoints. Recently we changed our api, so that we have types in the url.
An example of this would be
I have, in my Webservice class, configured the nested resources as follows.
public function initialize()
{
parent::initialize();
$this->addNestedResource(Configure::read('dsapi.url') . 'packages/:type', ['type']);
$this->addNestedResource(Configure::read('dsapi.url') . 'providers/:type', ['type']);
}
I cannot access my providers endpoint, because the requests are being redirected to the packages endpoint.
I'd expect that the nested resources would co-habit and I'd be able to access both endpoints, with their various types.
I can access one or the other by commenting out one of the lines, but not both at the same time.
It seems that this class is missing from the repo.
Muffin\Webservice\Exception\UnimplementedWebserviceMethodException
I have created my ExamplesTable
, but no endpoint class.
$this->modelFactory('Endpoint', [EndpointRegistry::class, 'get']);
$endpoint = $this->loadModel('Examples', 'Endpoint');
Exception: The datasource configuration "supply" was not found. in [/Users/david/Sites/Gaia/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php, line 196]
I would expect that a MissingEndpoint
exception, or similar, telling me that the Endpoint class is missing or can't be loaded. Rather than the method getting all the way to the ConnectionManager.
I have clear install of CakePHP (latest).
After I've followed all of the steps provided in the "Usage" section of this plugin I'm stuck on the Unknown repository type "Endpoint". Make sure you register a type before trying to use it. error.
Not sure how to register this type. I've tried
public function beforeFilter(Event $event)
{
$this->modelFactory(
'Endpoint',
['Endpoint', 'factory']
);
$this->loadModel('Articles', 'Endpoint');
}
but got Argument 2 passed to Cake\Controller\Controller::modelFactory() must be callable, array given error.
For example App::shortName()
There seems to be no way to clear the Endpoint registry. This means if you're testing with lots of test cases, there is no way to reset the registry.
I crated the following driver:
namespace Gutscheinpony\Webservice\Driver;
use Cake\Network\Http\Client;
use Muffin\Webservice\AbstractDriver;
class Gutscheinpony extends AbstractDriver
{
/**
* {@inheritDoc}
*/
public function initialize()
{
$this->client(new Client([
'headers' => [
'X-Api-Token' => $this->config('token')
]
]));
$this->webservice('Offers');
}
}
As error message I get:
Exception: Webservice class Gutscheinpony/Webservice.Offers (and fallback Gutscheinpony/Webservice.Gutscheinpony) could not be found. in [/var/www/schnaeppchenfuchs/vendor/muffin/webservice/src/AbstractDriver.php, line 218]
If I do it with: (probably it's more correct to specifiy the plugin here)
$this->webservice('Gutscheinpony.Offers');
I get:
Exception: Webservice class Gutscheinpony/Webservice.Gutscheinpony.Offers (and fallback Gutscheinpony/Webservice.Gutscheinpony) could not be found. in [/var/www/schnaeppchenfuchs/vendor/muffin/webservice/src/AbstractDriver.php, line 218]
It seems that the namespace building doesn't work properly here.
I think this https://github.com/UseMuffin/Webservice/blob/master/src/AbstractDriver.php#L95 needs to be -1
, then it would work (but only for $this->webservice('Offers');
) . I'm not sure here if this should be the error I will create a PR.
I'm having this error once I tried to do the edit function. Should I define schema in some class ?
Missing schema User or webservice Users describe implementation
Muffin\Webservice\Exception\MissingEndpointSchemaException
I wanted to quickly make some notes about things which I think could be worked on for the next major release of the plugin. This is a quick list and by no means exhaustive. Any suggestions are welcome
3.4-test
branch?Endpoint::endpoint()
and Endpoint::alias()
to getters and settersEndpoint::endpoint
and Endpoint::endpoint()
setConfig()
and getConfig()
setAlias()
and getAlias()
methods which are now part of the core RepositoryInterface
into the Endpoints{@inheritDoc}
doc blocks with actual doc blocksAbstractDriver
class into the Driver
folder and update it's namespaceEndpoint::webservice()
phpunit.xml
file as PHPUnit 7.x doesn't have the BaseListener
classSchema::options()
Schema::columnType()
ControllerEndpointFilter
since dispatch filters are deprecated in Cake 3.6 and add corresponding middleware instead. #64Using Query::repository() as getter is deprecated. Use getRepository() instead.
Seems mostly to be in the testsTypeMap()
callsThe \Muffin\Webservice\Datasource\Marshaller
currently ignores the existence of /src/Model/Endpoint/Schema/****Schema
classes, does not build a property map, and never calls TypeInterface::marshal()
Additionally \Muffin\Webservice\Webservice\Webservice::_transformResource()
never calls TypeInterface::toPHP()
Tested on version 3.0.0
Hi,
I'm trying to use your very promising plugin to implement some CRUD on a custom webservice but I'm facing a problem when creating a form in the view. The FormHelper fails to create a context based on the Resource given to the Form->create($resource)
method.
I noticed the form-context
branch of the project, and I guess this has something to do with that, but what's the state of these branches ? Is it already possible to use the FormHelper ? If not what's the best alternative ? Modelless forms ?
Thanks a lot.
I'm working through the usage example in the readme and have stumbled across an issue that's probably simple, but I'm stuck on.
I'm struggling with the example Webservice.
<?php
namespace App\Webservice;
use Cake\Network\Http\Client;
use Muffin\Webservice\Query;
use Muffin\Webservice\Webservice\Webservice;
class ArticlesWebservice extends Webservice
{
/**
* {@inheritDoc}
*/
protected function _executeReadQuery(Query $query, array $options = [])
{
$response = $this->driver()->client()->get('/articles.json');
if (!$response->isOk()) {
return false;
}
$resources = $this->_transformResults($query->endpoint(), $response->json['articles']);
return new ResultSet($resources, count($resources));
}
}
Running this code I'm seeing an "Class 'App\Webservice\ResultSet' not found" error.
What class/file/source does new ResultSet($resources, count($resources));
come from?
I've looked through the included classes and can't seem to find it. So, I assumed maybe the example just forgot use Cake\ORM\ResultSet
. Looking at the spec for Cake\ORM\ResultSet
the input variables are a Cake\ORM\Query
and Cake\Database\StatementInterface
. The variables passed to ResultSet
in the example are not those types.
What am I missing here?
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.