├── .gitignore
├── .htaccess
├── LICENSE
├── README.md
├── SalesforceAPI.php
└── examples.sample.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | examples.php
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 | Deny from all
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Salesforce REST API PHP Wrapper
2 | ===============================
3 |
4 | This is a PHP Wrapper for the Salesforce Rest API.
5 |
6 | It currently uses the just the Username-Password (http://www.salesforce.com/us/developer/docs/api_rest/) authentication flow. Eventually, the OAuth will be added to the class.
7 |
--------------------------------------------------------------------------------
/SalesforceAPI.php:
--------------------------------------------------------------------------------
1 |
8 | * @license GPL, or GNU General Public License, version 2
9 | */
10 |
11 | class SalesforceAPI extends APIAbstract {
12 | public
13 | $last_response;
14 | protected
15 | $client_id,
16 | $client_secret,
17 | $instance_url,
18 | $base_url,
19 | $headers,
20 | $return_type,
21 | $api_version;
22 | private
23 | $access_token,
24 | $handle;
25 |
26 | // Supported request methods
27 | const
28 | METH_DELETE = 'DELETE',
29 | METH_GET = 'GET',
30 | METH_POST = 'POST',
31 | METH_PUT = 'PUT',
32 | METH_PATCH = 'PATCH';
33 |
34 | // Return types
35 | const
36 | RETURN_OBJECT = 'object',
37 | RETURN_ARRAY_K = 'array_k',
38 | RETURN_ARRAY_A = 'array_a';
39 |
40 | const
41 | LOGIN_PATH = '/services/oauth2/token',
42 | OBJECT_PATH = 'sobjects/',
43 | GRANT_TYPE = 'password';
44 |
45 | /**
46 | * Constructs the SalesforceConnection
47 | *
48 | * This sets up the connection to salesforce and instantiates all default variables
49 | *
50 | * @param string $instance_url The url to connect to
51 | * @param string|int $version The version of the API to connect to
52 | * @param string $client_id The Consumer Key from Salesforce
53 | * @param string $client_secret The Consumer Secret from Salesforce
54 | */
55 | public function __construct($instance_url,$version, $client_id, $client_secret, $return_type = self::RETURN_OBJECT)
56 | {
57 | // Instantiate base variables
58 | $this->instance_url = $instance_url;
59 | $this->api_version = $version;
60 | $this->client_id = $client_id;
61 | $this->client_secret = $client_secret;
62 | $this->return_type = $return_type;
63 |
64 | $this->base_url = $instance_url;
65 | $this->instance_url = $instance_url . '/services/data/v' . $version . '/';
66 |
67 | $this->headers = [
68 | 'Content-Type' => 'application/json'
69 | ];
70 |
71 | // If the cURL handle doesn't exist, create it
72 | if(is_null($this->handle)) {
73 | $this->handle = curl_init();
74 | $options = [
75 | // CURLOPT_SSL_VERIFYPEER => false,
76 | // CURLOPT_SSL_VERIFYHOST => false,
77 | CURLOPT_CONNECTTIMEOUT => 5,
78 | CURLOPT_TIMEOUT => 240,
79 | CURLOPT_RETURNTRANSFER => true,
80 | CURLOPT_BUFFERSIZE => 128000
81 |
82 | ];
83 | curl_setopt_array($this->handle, $options);
84 | }
85 | }
86 |
87 | /*========== Authorization =========*/
88 | /**
89 | * Logs in the user to Salesforce with a username, password, and security token
90 | *
91 | * @param string $username
92 | * @param string $password
93 | * @param string $security_token
94 | * @return mixed
95 | * @throws SalesforceAPIException
96 | */
97 | public function login($username, $password, $security_token)
98 | {
99 | // Set the login data
100 | $login_data = [
101 | 'grant_type' => self::GRANT_TYPE,
102 | 'client_id' => $this->client_id,
103 | 'client_secret' => $this->client_secret,
104 | 'username' => $username,
105 | 'password' => $password . $security_token
106 | ];
107 | // Change the content type to a form
108 | // $headers = [
109 | // 'Content-Type' => 'application/x-www-form-urlencoded'
110 | // ];
111 |
112 | // TODO: Fix this to use the httpRequest function. There is an issue with the curl opt Custom Request
113 |
114 | $ch = curl_init();
115 |
116 | $http_params = http_build_query($login_data);
117 |
118 | curl_setopt($ch, CURLOPT_URL, $this->base_url . '/services/oauth2/token');
119 | curl_setopt($ch, CURLOPT_POST, 5);
120 | curl_setopt($ch, CURLOPT_HEADER, 1);
121 | curl_setopt($ch, CURLOPT_POSTFIELDS, $http_params);
122 | curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type : application/x-www-form-urlencoded"));
123 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
124 | curl_setopt($ch, CURLOPT_SSLVERSION, 4);
125 |
126 | $login = curl_exec($ch);
127 | $login = explode("\n", $login);
128 | $login = json_decode($login[count($login)-1]);
129 | //echo 'Auth response: '; print_r($data); echo '
';
130 | curl_close($ch);
131 | // Send the request
132 | // $login = $this->httpRequest($this->base_url . self::LOGIN_PATH,$login_data, $headers, self::METH_POST);
133 |
134 | // Set the access token
135 | // if($this->return_type === self::RETURN_OBJECT) {
136 | $this->access_token = $login->access_token;
137 | // } elseif($this->return_type === self::RETURN_ARRAY_A) {
138 | // $this->access_token = $login['access_token'];
139 | // }
140 |
141 |
142 | // Return the login object
143 | // TODO: Should this be returned?
144 | return $login;
145 | }
146 |
147 | /*=========== Organization Information ===============*/
148 | /**
149 | * Get a list of all the API Versions for the instance
150 | *
151 | * @return mixed
152 | * @throws SalesforceAPIException
153 | */
154 | public function getAPIVersions()
155 | {
156 | return $this->httpRequest( $this->base_url . '/services/data' );
157 | }
158 |
159 | /**
160 | * Lists the limits for the organization. This is in beta and won't return for most people
161 | *
162 | * @return mixed
163 | * @throws SalesforceAPIException
164 | */
165 | public function getOrgLimits()
166 | {
167 | return $this->request('limits/');
168 | }
169 |
170 | /**
171 | * Gets a list of all the available REST resources
172 | *
173 | * @return mixed
174 | * @throws SalesforceAPIException
175 | */
176 | public function getAvailableResources()
177 | {
178 | return $this->request('');
179 | }
180 |
181 | /**
182 | * Get a list of all available objects for the organization
183 | *
184 | * @return mixed
185 | * @throws SalesforceAPIException
186 | */
187 | public function getAllObjects()
188 | {
189 | return $this->request( self::OBJECT_PATH );
190 | }
191 |
192 | /*========== Object Metadata ============*/
193 | /**
194 | * Get metadata about an Object
195 | *
196 | * @param string $object_name
197 | * @param bool $all Should this return all meta data including information about each field, URLs, and child relationships
198 | * @param DateTime $since Only return metadata if it has been modified since the date provided
199 | * @return mixed
200 | * @throws SalesforceAPIException
201 | */
202 | public function getObjectMetadata($object_name, $all = false, DateTime $since = null)
203 | {
204 | $headers = [];
205 | // Check if the If-Modified-Since header should be set
206 | if($since !== null && $since instanceof DateTime) {
207 | $headers['IF-Modified-Since'] = $since->format('D, j M Y H:i:s e');
208 | } elseif($since !== null && !$since instanceof DateTime) {
209 | // If the $since flag has been set and is not a DateTime instance, throw an error
210 | throw new SalesforceAPIException('To get object metadata for an object, you must provide a DateTime object');
211 | }
212 |
213 | // Should this return all meta data including information about each field, URLs, and child relationships
214 | if($all === true)
215 | return $this->request( self::OBJECT_PATH . $object_name . '/describe/',[],self::METH_GET, $headers);
216 | else
217 | return $this->request( self::OBJECT_PATH . $object_name,[],self::METH_GET,$headers);
218 | }
219 |
220 | /*========= Working with Records ==========*/
221 | /**
222 | * Create a new record
223 | *
224 | * @param string $object_name
225 | * @param array $data
226 | * @return mixed
227 | * @throws SalesforceAPIException
228 | */
229 | public function create( $object_name, $data )
230 | {
231 | return $this->request( self::OBJECT_PATH . (string)$object_name, $data, self::METH_POST );
232 | }
233 |
234 | /**
235 | * Update an existing object
236 | *
237 | * @param string $object_name
238 | * @param string $object_id
239 | * @param array $data
240 | * @return mixed
241 | * @throws SalesforceAPIException
242 | */
243 | public function update( $object_name, $object_id, $data )
244 | {
245 | return $this->request( self::OBJECT_PATH . (string) $object_name . '/' . $object_id, $data, self::METH_PATCH );
246 | }
247 |
248 | /**
249 | * Delete a record
250 | *
251 | * @param string $object_name
252 | * @param string $object_id
253 | * @return mixed
254 | * @throws SalesforceAPIException
255 | */
256 | public function delete( $object_name, $object_id )
257 | {
258 | return $this->request( self::OBJECT_PATH . (string) $object_name . '/' . $object_id, null, self::METH_DELETE );
259 | }
260 |
261 | /**
262 | * Get a record
263 | *
264 | * @param string $object_name
265 | * @param string $object_id
266 | * @param array|null $fields
267 | * @return mixed
268 | * @throws SalesforceAPIException
269 | */
270 | public function get( $object_name, $object_id, $fields = null )
271 | {
272 | $params = [];
273 | // If fields are included, append them to the parameters
274 | if($fields !== null && is_array($fields)) {
275 | $params['fields'] = implode(',', $fields);
276 | }
277 | return $this->request( self::OBJECT_PATH . (string) $object_name . '/' . $object_id, $params );
278 | }
279 |
280 | /**
281 | * Searches using a SOQL Query
282 | *
283 | * @param string $query The query to perform
284 | * @param bool $all Search through deleted and merged data as well
285 | * @param bool $explain If the explain flag is set, it will return feedback on the query performance
286 | * @return mixed
287 | * @throws SalesforceAPIException
288 | */
289 | public function searchSOQL($query, $all = false, $explain = false) {
290 | $search_data = [
291 | 'q' => $query
292 | ];
293 |
294 | // If the explain flag is set, it will return feedback on the query performance
295 | if($explain) {
296 | $search_data['explain'] = $search_data['q'];
297 | unset($search_data['q']);
298 | }
299 |
300 | // If is set, search through deleted and merged data as well
301 | if($all)
302 | $path = 'queryAll/';
303 | else
304 | $path = 'query/';
305 |
306 | return $this->request($path,$search_data,self::METH_GET);
307 | }
308 |
309 | public function getQueryFromUrl($query)
310 | {
311 | // Throw an error if no access token
312 | if(!isset($this->access_token))
313 | throw new SalesforceAPIException('You have not logged in yet.');
314 |
315 | // Set the Authorization header
316 | $request_headers = [
317 | 'Authorization' => 'Bearer ' . $this->access_token
318 | ];
319 |
320 | // Merge all the headers
321 | $request_headers = array_merge($request_headers, []);
322 |
323 | return $this->httpRequest( $this->base_url .$query,[],$request_headers);
324 | }
325 |
326 | /**
327 | * Makes a request to the API using the access key
328 | *
329 | * @param string $path The path to use for the API request
330 | * @param array $params
331 | * @param string $method
332 | * @param array $headers
333 | * @return mixed
334 | * @throws SalesforceAPIException
335 | */
336 | protected function request($path, $params = [], $method = self::METH_GET, $headers = [])
337 | {
338 | // Throw an error if no access token
339 | if(!isset($this->access_token))
340 | throw new SalesforceAPIException('You have not logged in yet.');
341 |
342 | // Set the Authorization header
343 | $request_headers = [
344 | 'Authorization' => 'Bearer ' . $this->access_token
345 | ];
346 |
347 | // Merge all the headers
348 | $request_headers = array_merge($request_headers, $headers);
349 |
350 | return $this->httpRequest($this->instance_url . $path, $params, $request_headers, $method);
351 | }
352 |
353 | /**
354 | * Performs the actual HTTP request to the Salesforce API
355 | *
356 | * @param string $url
357 | * @param array|null $params
358 | * @param array|null $headers
359 | * @param string $method
360 | * @return mixed
361 | * @throws SalesforceAPIException
362 | */
363 | protected function httpRequest($url, $params = null, $headers = null, $method = self::METH_GET)
364 | {
365 | // Set the headers
366 | if(isset($headers) && $headers !== null && !empty($headers))
367 | $request_headers = array_merge($this->headers,$headers);
368 | else
369 | $request_headers = $this->headers;
370 |
371 | // Add any custom fields to the request
372 | if(isset($params) && $params !== null && !empty($params)) {
373 | if($request_headers['Content-Type'] == 'application/json') {
374 | $json_params = json_encode($params);
375 | curl_setopt($this->handle, CURLOPT_POSTFIELDS, $json_params);
376 | } else {
377 | $http_params = http_build_query($params);
378 | curl_setopt($this->handle, CURLOPT_POSTFIELDS, $http_params);
379 | }
380 |
381 | }
382 |
383 | // Modify the request depending on the type of request
384 | switch($method)
385 | {
386 | case 'POST':
387 | // curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, null);
388 | curl_setopt($this->handle, CURLOPT_POST, true);
389 | break;
390 | case 'GET':
391 | // curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, null);
392 | curl_setopt($this->handle, CURLOPT_POSTFIELDS, []);
393 | curl_setopt($this->handle, CURLOPT_POST, false);
394 | if(isset($params) && $params !== null && !empty($params))
395 | $url .= '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
396 | break;
397 | default:
398 | curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $method);
399 | break;
400 | }
401 |
402 |
403 | curl_setopt($this->handle, CURLOPT_URL, $url);
404 | curl_setopt($this->handle, CURLOPT_HTTPHEADER, $this->createCurlHeaderArray($request_headers));
405 |
406 | $response = curl_exec($this->handle);
407 |
408 | $response = $this->checkForRequestErrors($response, $this->handle);
409 |
410 | $result = json_decode($response);
411 |
412 | if($this->return_type === self::RETURN_OBJECT) {
413 | return $result;
414 | } elseif($this->return_type === self::RETURN_ARRAY_A) {
415 | return $this->objectToArray($result);
416 | }
417 | }
418 |
419 | /**
420 | * Makes the header array have the right format for the Salesforce API
421 | *
422 | * @param $headers
423 | * @return array
424 | */
425 | private function createCurlHeaderArray($headers) {
426 | $curl_headers = [];
427 | // Create the header array for the request
428 | foreach($headers as $key => $header) {
429 | $curl_headers[] = $key . ': ' . $header;
430 | }
431 | return $curl_headers;
432 | }
433 |
434 | /**
435 | * Checks for errors in a request
436 | *
437 | * @param string $response The response from the server
438 | * @param Resource $handle The CURL handle
439 | * @return string The response from the API
440 | * @throws SalesforceAPIException
441 | * @see http://www.salesforce.com/us/developer/docs/api_rest/index_Left.htm#CSHID=errorcodes.htm|StartTopic=Content%2Ferrorcodes.htm|SkinName=webhelp
442 | */
443 | private function checkForRequestErrors($response, $handle) {
444 | $curl_error = curl_error($handle);
445 | if($curl_error !== '') {
446 | throw new SalesforceAPIException($curl_error);
447 | }
448 | $request_info = curl_getinfo($handle);
449 |
450 | switch($request_info['http_code']) {
451 | case 304:
452 | if($response === '')
453 | return json_encode(['message' => 'The requested object has not changed since the specified time']);
454 | break;
455 | case 300:
456 | case 200:
457 | case 201:
458 | case 204:
459 | if($response === '')
460 | return json_encode(['success' => true]);
461 | break;
462 | default:
463 | if(empty($response) || $response !== '')
464 | throw new SalesforceAPIException($response);
465 | else {
466 | $result = json_decode($response);
467 | if(isset($result->error))
468 | throw new SalesforceAPIException($result->error_description);
469 | }
470 | break;
471 | }
472 |
473 | $this->last_response = $response;
474 |
475 | return $response;
476 | }
477 |
478 |
479 | }
480 |
481 | abstract class APIAbstract {
482 | /**
483 | * Converts objects returned into arrays.
484 | * This is necessary when returning complex objects.
485 | * For example, an object returned from a search using a cross-object reference cannot be displayed using methods to display simple objects...
486 | * /api/task/search?fields=project:name
487 | * /api/task/search?fields=DE:Parameter Name
488 | * both contain colons, which will result in a stdClass error when using the methods to reference simple objects.
489 | * The function below provides a way to convert the 'project:name' object into a usuable array
490 | * i.e. $task['project:name'] can be used by placing the returned object into the function
491 | *
492 | */
493 | function objectToArray ( $object )
494 | {
495 | if( !is_object( $object ) && !is_array( $object ) )
496 | {
497 | return $object;
498 | }
499 | if( is_object( $object ) )
500 | {
501 | $object = get_object_vars( $object );
502 | }
503 | return array_map( array($this, 'objectToArray'), $object );
504 | }
505 | }
506 |
507 | class SalesforceAPIException extends Exception {}
--------------------------------------------------------------------------------
/examples.sample.php:
--------------------------------------------------------------------------------
1 | ', '');
6 |
7 | $salesforce->login('','','');
8 |
9 | $api_versions = $salesforce->getAPIVersions();
10 | $limits = $salesforce->getOrgLimits();
11 | $resource = $salesforce->getAvailableResources();
12 | $objects = $salesforce->getAllObjects();
13 |
14 | $date = new DateTime();
15 |
16 | $good_metadata = $salesforce->getObjectMetadata('Account');
17 | $good_metadata_all = $salesforce->getObjectMetadata('Account', true);
18 | $good_metadata_since = $salesforce->getObjectMetadata('Account', true, $date);
19 | $bad_metadata = $salesforce->getObjectMetadata('SomeOtherObject');
20 |
21 | $create_account = $salesforce->create( 'Account', ['name' => 'New Account'] );
22 | $update_project = $salesforce->update( 'Account', $create_account->id, ['name' => 'Changed'] );
23 | $project = $salesforce->get( 'Account', $create_account->id );
24 | $project_with_fields = $salesforce->get( 'Account', $create_account->id, ['Name', 'OwnerId'] );
25 | $delete_project = $salesforce->delete( 'Account', $create_account->id );
26 |
27 | $response = $salesforce->searchSOQL('SELECT name from Position__c',true);
--------------------------------------------------------------------------------