Giter Club home page Giter Club logo

phpactiveresource's Introduction

PHP ActiveResource

Click here to lend your support to: phpactiveresource and make a donation at www.pledgie.com !

This is a PHP class for accessing Ruby on Rails REST APIs in an ActiveResource style of coding. The benefit is easier use of RoR-based REST services without having to roll your own CURL-based client each time. Hopefully this class saves a few people some time coding in PHP against RoR-based REST services. It’s by no means an exhaustive port, and some methods are missing, but it does try to cover all the basics.

Note: You will need the php curl extension installed on your system. On Ubuntu, you can install it via:

sudo apt-get install php5-curl

Usage

With Composer

Create a composer.json file with the following:

{
	"require": {
		"phpactiveresource/phpactiveresource": "dev-master"
	}
}

Now load the script via Composer’s autoloader:

<?php

require_once 'vendor/autoload.php';

use ActiveResource\ActiveResource;

class Song extends ActiveResource {
	public $site = 'http://localhost:3000/';
	public $element_name = 'songs';
}

// etc.

?>

Without Composer

<?php

require_once ('lib/ActiveResource.php');

class Song extends ActiveResource {
    var $site = 'http://localhost:3000/';
    var $element_name = 'songs';
}

// create a new item
$song = new Song (array ('artist' => 'Joe Cocker', 'title' => 'A Little Help From My Friends'));
$song->save ();

// fetch and update an item, chaining statements
$song->find (44)->set ('title', 'The River')->save ();

// fetch and update, line by line
$song->find (44);
$song->title = 'The River';
$song->save ();

// get all songs
$songs = $song->find ('all');

// delete a song
$song->find (44);
$song->destroy ();

// custom method
$songs = $song->get ('by_year', array ('year' => 1999));

?>

Extra URL params

If you want to add extra params to the end of the url eg: an API key, you can set $extra_params

<?php

require_once ('lib/ActiveResource.php');

class Song extends ActiveResource {
    var $site = 'http://localhost:3000/';
    var $element_name = 'songs';
    var $extra_params = '?key=123456789';
}

Extra Http Headers

If you need to add extra http request headers you can set $request_headers

<?php

require_once ('lib/ActiveResource.php');

class Song extends ActiveResource {
    var $site = 'http://localhost:3000/';
    var $element_name = 'songs';
    var $request_headers = array("x-api-key: some-api-key-here");
}

See the Github Wiki pages for more examples and documentation.

phpactiveresource's People

Contributors

bmaynard avatar fugi avatar jbroadway avatar jhirbour avatar lux avatar rafaelp avatar sheldonrampton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

phpactiveresource's Issues

problem with Redmine - ZEND

Hi,

i am using your library for posting the redmine issue ( as per http://www.redmine.org/projects/redmine/wiki/Rest_api_with_php ).

It is working fine in a normal php (everything in one place) file. but It returns the below error when i try to use the same inside the ZEND

what i did with ZEND

  1. Got the file https://github.com/lux/phpactiveresource/blob/master/ActiveResource.php
  2. placed the file under the folder library
  3. Added new file under the util folder (file name Redmine.php)

class Redmine extends ActiveResource {
var $site = GeneralConstants::REDMINE_URL;
var $user = GeneralConstants::REDMINE_USER_USERNAME;
var $password = GeneralConstants::REDMINE_USER_PASSWORD;
var $request_format = GeneralConstants::REDMINE_API_REQUEST_FORMAT;

}

  1. inside the Controller i have placed the following code

        $redmineIssue = new Redmine(array(
                'subject' => $redmineTitle, 
                'description' => htmlentities($redmineDescription),
                'project_id' => GeneralConstants::REDMINE_ISSUE_PROJECT_ID, 
                'assigned_to_id' => GeneralConstants::REDMINE_ISSUE_ASSIGNED_TO_USER_ID, 
                'tracker_id' => GeneralConstants::REDMINE_ISSUE_TRACKER_ID));
        $redmineIssue->save();
    

i got the following error,

["request_method"]=> string(4) "POST" ["response_code"]=> string(3) "404" ["response_headers"]=> string(217) "HTTP/1.1 404 Not Found Connection: Keep-Alive Content-Type: text/html; charset=utf-8 Date: Mon, 20 Aug 2012 15:03:22 GMT Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12) Content-Length: 485 Cache-Control: no-cache" ["response_body"]=> string(485) "

Can you please give me some idea to fix this issue.

Hardcoded $site

Hi,

Great library. I'm using it as part of a project to integrate Redmine with Drupal. As far as I can tell there is no way to get around having to hardcode the $site variable in the class that you extend ActiveResource with.

For example I would like to have an Issue class like this:

class Issue extends ActiveResource {

  var $site;

  var $request_format = 'xml';

  public function __construct($site, $data = NULL) {
    $this->site = $site;

    parent::__construct($data);
  }
}

The issue with this is that on line 372 of ActiveResource, it creates a new Issue without adding any parameters, which will produce a PHP warning. I could just ignore the warning, but is there a better way?

Thanks,
Matt

Limitation in creating XML objects.

I am trying to write an application that works with the RedMine API. I need to be able to send custom fields and the way they are handled are in the format:

<issue>
  <subject>Test</subject>
  <project_id>data</project_id>
  <description>Text</description>
  <custom_fields>
    <custom_field id="1"><value>value</value></custom_field>
    <custom_field id="2"><value>value</value></custom_field>
    <custom_field id="3"><value>value</value></custom_field>
  </custom_fields>
</issue>

If I use the format of having an array of arrays within custom_fields it doesn't pull over the ID for each custom_field.

$issue = array(
  'subject' => 'Test',
  'project_id' => 'data',
  'description' => 'Text',
  'custom_fields => array(
    'custom_field => array(
       array('@id' =>"1", 'value' => 'value'),
       array('@id' =>"2", 'value' => 'value'),
       array('@id' =>"3", 'value' => 'value')
  )
);


Cannot convert object types?

$obj = new stdClass();
        $obj->id = 1;
        $obj->value = "test";

        $rm_issue = new Redmine_Issue(array(
            'tracker_id' => $iss->getTracker(),
            'project_id' => $iss->getProject(),
            'subject' => $iss->getSubject(), 
            'description' => $iss->getDesc(),
            'custom_fields' => array($obj)
        ));

        $rm_issue->save();
        print_r($rm_issue);

I get an error when using the "save" method.

Warning: strlen() expects parameter 1 to be string, object given in C:\xampp\htdocs\testing\eldoweb\library\ActiveResource.php on line 424

So apparently I can't pass in an array of objects. Does anyone know a work around?

add custom request header

I made a little patch to add some headers to the request.
I use it to authenticate with an api key in the header (redmine).

--- ActiveResource.php.orig 2012-10-11 09:40:33.000000000 +0200
+++ ActiveResource.php  2012-10-11 09:40:12.000000000 +0200
@@ -96,6 +96,11 @@
    var $request_body = '';

    /**
+    * The request headers that was sent to the server.
+    */
+   var $request_headers = array();
+
+   /**
     * The complete URL that the request was sent to.
         */
            var $request_uri = '';
@@ -615,7 +620,7 @@
        }

        if ($this->request_format == 'xml') {
-           curl_setopt ($ch, CURLOPT_HTTPHEADER, array ("Expect:", "Content-Type: text/xml", "Length: " .          strlen  $params)));
+           $this->request_headers = array_merge($this->request_headers, array ("Expect:", "Content-Type: text/xml",    Length: " . strlen ($params)));
        }
        switch ($method) {
            case 'POST':
@@ -635,6 +640,10 @@
            default:
                break;
        }
+       if (count($this->request_headers)) {
+           curl_setopt ($ch, CURLOPT_HTTPHEADER, $this->request_headers);
+       }
+
        $res = curl_exec ($ch);

        // Check HTTP status code for denied access

POST to "time_entry" uses invalid entity name

If you are trying to use the class to write time_entries, you will get a 404 response. The reasone is, that the class is unable to create the correct singular form from the pluralized version of the entitiy name. this can be patched by

adding the class var 1 protected $sOriginalElementName = '';
changing the constructor to set the class var using the original entity name before the pluralization is called:
1 function __construct ($data = array ()) { 2 $this->_data = $data; 3 4 // add this line here - to store the original name of the entity 5 $this->sOriginalElementName = ($this->element_name ? $this->element_name : strtolower (get_class ($this))); 6 // Allow class-defined element name or use class name if not defined 7 $this->element_name = ($this->element_name ? $this->pleuralize ($this->element_name) : $this->pleuralize (strtolower (get_class ($this)))); 8 ...
and then Changing the Method _send_and_receive to use sOriginalElementName instead of substr ($this->element_name, 0, -1);
1 function _send_and_receive ($url, $method, $data = array ()) { 2 $params = ''; 3 $el = $this->sOriginalElementName;//substr ($this->element_name, 0, -1); 4 if ($this->request_format == 'url') { 5 ...

see: http://www.redmine.org/projects/redmine/wiki/Rest_api_with_php

Lack of true inflection

First off, thanks for this library, it's exactly what I was looking for to get my rails app's data onto everyone's ubiquitous cheap php servers. One problem I ran into though is the lack of inflection beyond adding an 's' to the element_name. Putting 'people' or 'person' resulted in it hitting the api with /peoples/ or /persons/. I just removed the part where it adds the 's' if $element_name is declared and set it to 'people' so it's working fine, but just wanted to file the issue to see if more robust inflection is planned.

https://github.com/jbroadway/phpactiveresource/tree/master id issue still exists in line 244

Hi,

id issue not fixed thoroughly - it still exists in line 244

osv@blackbook001:~/Work/Redmine/tests$ phpactiveresource-master/examples/redmine.php
**PHP Notice:  Undefined index: id in /home/osv/Work/Redmine/tests/phpactiveresource-master/lib/ActiveResource/ActiveResource.php on line 244**
RmIssue Object
(
    [site] => http://redmine.work.bory/
    [element_name] => issue
    [request_headers] => Array
        (
            [0] => x-api-key: 5ccb0f6e300893352b70d378d9c4845b80f09b0e
        )

    [extra_params] => 
    [user] => 
    [password] => 
    [element_name_plural] => issues
    [_data:ActiveResource\ActiveResource:private] => Array
        (
        )

    [error] => HTTP Basic: Access denied.
    [errno] => 401
    [request_body] => 
    [request_uri] => http://redmine.work.bory/issues.xml?assigned_to=Redmine+Admin
    [request_method] => GET
    [response_code] => 
    [response_headers] => 
    [response_body] => 
    [request_format] => url
    [pleural_corrections] => Array
        (
            [persons] => people
            [peoples] => people
            [mans] => men
            [mens] => men
            [womans] => women
            [womens] => women
            [childs] => children
            [childrens] => children
            [sheeps] => sheep
            [octopuses] => octopi
            [quizs] => quizzes
            [axises] => axes
            [buffalos] => buffaloes
            [tomatos] => tomatoes
            [potatos] => potatoes
            [oxes] => oxen
            [mouses] => mice
            [matrixes] => matrices
            [vertexes] => vertices
            [indexes] => indices
        )

)
osv@blackbook001:~/Work/Redmine/tests$ 
osv@blackbook001:~/Work/Redmine/tests$ vi  /home/osv/Work/Redmine/tests/phpactiveresource-master/lib/ActiveResource/ActiveResource.php

235 
236         /**
237          * Finds a record or records via:
238          *
239          *     GET /collection/id.xml
240          *     GET /collection.xml
241          */
242         public function find ($id = false, $options = array ()) {
243                 if (! $id) {
**244                         $id = $this->_data['id'];**
245                 }
246                 $options_string = '';
247                 if (count ($options) > 0) {
248                         $options_string = '?' . http_build_query ($options);
249                 }
250                 if ($id == 'all' || $id == false) {
251                         // URL/plural.xml?someparam=1
252                         $url = $this->site . $this->element_name_plural . '.xml';
253                         return $this->_send_and_receive ($url . $options_string, 'GET');
254                 }
255 
256                 // URL/plural/id.xml?someparam=1
257                 return $this->_send_and_receive ($this->site . $this->element_name_plural . '/' . $id . '.xml' . $options_string, 'GET');
258         }
259 

An exception will be thrown in the case of "HTTP/1.1 100 Continue"

I ran into a bug in ActiveResource.php when using it with the Redmin REST API, as instructed here: http://www.redmine.org/wiki/redmine/Rest_api_with_php

When saving a new issue with a very large text in its description property, by calling $issue->save(), the following exception will occur:

"Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML' in /path/to/ActiveResource.php:319"

I found out the cause of the problem: if the request size is large enough, then apparently PHP's SimpleXMLElement function will send an HTTP 100 CONTINUE request to the web server, to make sure it doesn't waste bandwidth by sending so much information that may not be accepted.

In such cases, $res will end up containing not one, but two status lines in the response.

So instead of this (what the server usually returns if the request is small enough):

HTTP/1.1 201 Created
(headers here)
[EMPTY LINE]
(xml data here)

...We get this:

HTTP/1.1 100 Continue
[EMPTY LINE]
HTTP/1.1 201 Created
(headers here)
[EMPTY LINE]
(xml data here)

Since the code in its current form always expects but one status line and headers, followed by an empty line and then the actual XML code, it will split $res in two right at the first empty line it encounters, and then will simply assume that the second part (which it puts back in $res) will contain only XML code fit to be processed by the SimpleXMLElement function.

I've changed the code a bit to keep repeating the splitting procedure until no more status lines are encountered at the beginning of $res (at which point it will assume that the remainder really is pure parsable XML code). The patch is as follows:

--- ActiveResource_unpatched.php   2010-12-10 17:27:15.000000000 +0100
+++ ActiveResource_fixed.php        2010-12-10 17:15:24.000000000 +0100
@@ -299,20 +299,25 @@ class ActiveResource {
    $res = $this->_fetch ($url, $method, $params);
  •   list ($headers, $res) = explode ("\r\n\r\n", $res, 2);
    
  •   $this->response_headers = $headers;
    
  •   $this->response_body = $res;
    
  •   if (preg_match ('/HTTP\/[0-9]\.[0-9] ([0-9]+)/', $headers, $regs)) {
    
  •       $this->response_code = $regs[1];
    
  •   } else {
    
  •       $this->response_code = false;
    
  •   }
    
  •   // Keep splitting off any top headers until we get to the (XML) body:
    
  •   while (strpos($res, "HTTP/") === 0) {
    
  •       list ($headers, $res) = explode ("\r\n\r\n", $res, 2);
    
  •       $this->response_headers = $headers;
    
  •       $this->response_body = $res;
    
  •       if (preg_match ('/HTTP\/[0-9]\.[0-9] ([0-9]+)/', $headers, $regs)) {
    
  •           $this->response_code = $regs[1];
    
  •       } else {
    
  •           $this->response_code = false;
    
  •       }
    
  •       if (! $res) {
    
  •           return $this;
    
  •       } elseif ($res == ' ') {
    
  •           $this->error = 'Empty reply';
    
  •           return $this;
    
  •       }
    
  •   if (! $res) {
    
  •       return $this;
    
  •   } elseif ($res == ' ') {
    
  •       $this->error = 'Empty reply';
    
  •       return $this;
      }
    
      // parse XML response</pre></blockquote>
    

You may of course think of a better way to handle this, but this currently works for me. I hope this is useful to you! Thanks for this very handy library and keep up the good work!

Kind regards,

Volkert (volkertb)

UTF8 Support

When pushing data via save we have noticed, that special chars such as german umlaute (ä,ü,ö etc) are broken. checking your code we found that you handle non utf-8 chars only in _xml_entities.

this can be fixed by using mb_encode_numericentity:

function _xml_entities ($string) {
return mb_encode_numericentity($string, array(0x80, 0xff, 0, 0xff), "UTF-8");
}

Please note, that i took the second parameter of the function form the php.net documentation - i am not sure if that covers all relevant characters.... If you intend to use the code, you may want to have a closer look at that.

Namespaces support

If element_name was not defined, constructor takes a class name (this line). But get_class returns not only the class name, but the whole namespaces chain. To fix that, on lines 164-168, $element_name gets cleaned of namespaces, but element_name_plural doesn't. And as element_name_plural is used in URL's, they won't work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.