Skip to content

Commit

Permalink
Merge pull request #7 from adrian-enspired/56-alpha
Browse files Browse the repository at this point in the history
Version 56
  • Loading branch information
adrian-enspired authored Jan 5, 2023
2 parents adfa637 + 863afe6 commit efa080b
Show file tree
Hide file tree
Showing 32 changed files with 1,681 additions and 526 deletions.
25 changes: 13 additions & 12 deletions .phan/config.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<?php

return [
'allow_method_param_type_widening' => true,
'prefer_narrowed_phpdoc_param_type' => false,
'prefer_narrowed_phpdoc_return_type' => false,
'dead_code_detection' => true,
'directory_list' => ['src', 'vendor'],
'exclude_analysis_directory_list' => ['vendor'],
'suppress_issue_types' => [
"allow_method_param_type_widening" => true,
"prefer_narrowed_phpdoc_param_type" => false,
"prefer_narrowed_phpdoc_return_type" => false,
"dead_code_detection" => true,
"directory_list" => ["src", "tests", "vendor"],
"exclude_analysis_directory_list" => ["vendor"],
"suppress_issue_types" => [
// false positives
'PhanReadOnlyPublicProperty',
'PhanUnreferencedClass',
'PhanUnreferencedPublicMethod',
// this is a stupid warning (be careful! this might do exactly what it's supposed to do!)
'PhanSuspiciousBinaryAddLists'
"PhanReadOnlyPublicProperty",
"PhanUnreferencedClass",
"PhanUnreferencedPublicClassConstant",
"PhanUnreferencedPublicMethod",
// this is a stupid warning (be careful! this might do exactly what it's supposed to do)
"PhanSuspiciousBinaryAddLists"
]
];
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ _Check [Salesforce's Help Docs](https://help.salesforce.com/s/articleView?id=sf.
Creating a new Api client and connecting:
```php
use Nexcess\Salesforce\ {
Authentication\Password,
Authenticator\Password,
Client
};

Expand Down Expand Up @@ -112,13 +112,14 @@ var_dump($ded->Id);

## Advanced Usage

### Salesforce Object Classes
### Extending the SalesforceObject Class

The included `Nexcess\Salesforce\SaleforceObject` class can be used without modification as a generic "salesforce record" implementation - it will automatically set properties based on what's fetched from the Api. However, the intent is that applications will extend from it and define the properties needed for each of their Salesforce objects. This allows for a consistent schema that your code can rely on, and even lets you implement some level of validation directly in your application.

To build your own Salesforce Object, you must:
- extend from `Nexcess\Salesforce\SalesforceObject`
- define the object fields as public properties
- list any properties that must not be included in update() calls (e.g., renamed fields, nested objects or object lists) in UNEDITABLE_FIELDS.
- add any necessary logic in `setField()` (e.g., building a new object if your record has a relation)
- add any desired logic in `validateField()`

Expand All @@ -128,10 +129,53 @@ use Nexcess\Salesforce\SalesforceObject;

class Example extends SalesforceObject {

public const TYPE = "Example";

public ? string $Name = null;
}
```

### Inline Records and Record Lists

SOQL allows queries for nested objects and queries, which appear in results as inline records and query results respectively. This library does understand results from such queries, but your SalesforceObject subclasses must define properties in a particular way to support them.

For example, a query similar to `SELECT Manager.Id, Manager.Name, (SELECT Id, Name FROM Members) FROM Teams` would require a SalesforceObject class like so:
```php
use Nexcess\Salesforce\ {
Result,
SalesforceObject
};
use Example;

class Team extends SalesforceObject {

public const TYPE = "Team";

protected const UNEDITABLE_FIELDS = [
"Manager",
"Members",
...parent::UNEDITABLE_FIELDS
];

public ? Example $Manager = null;
public ? Result $Members = null;
}
```

Where there is an inline object, the property should be typed as the corresponding SalesforceObject subclass. For any record type where you're not making a SalesforceObject subclass, type the property as `SalesforceObject` — though this is obviously less useful.

Where there is a subquery, the property should be typed as a `Result` instance. Among other things, this allows the Result to support paginated subqueries.

### Object Mapping

Finally, to allow the Api Client take advantage of your subclasses, you must provide an `$objectMap` so it knows which PHP classes correspond to which Salesforce record types. Without this, you'll end up with generic SalesfoceObject instances for everything. Nested Results will be provided the same `$objectMap` as their parent Result instance.
```php
$salesforce = new Client(
$password->authenticate([...$credentials]),
[Example::TYPE => Example::class, Team::TYPE => Team::class]
);
```

### Field Validation

Some basic validation functions are included in `Nexcess\Salesforce\Validator`. These methods all take the value to validate as the first argument, and can have other arguments depending on needs. Follow this same pattern to implement additional validation functions for your own objects as needed.
Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nexcess/php-salesforce-rest-api",
"description": "Salesforce API Client based on bjsmasth/php-salesforce-rest-api",
"version": "51.0",
"version": "56.0",
"license": "MIT",
"keywords": [
"bjsmasth",
Expand All @@ -20,9 +20,9 @@
}
],
"require": {
"php": "^7.4|^8",
"guzzlehttp/guzzle": "^6.2|^7",
"php-enspired/exceptable": "^3.2"
"php": "^7.4 || ^8",
"guzzlehttp/guzzle": "^6.2 || ^7",
"php-enspired/exceptable": "^4"
},
"require-dev": {
"phan/phan": "^5",
Expand Down
14 changes: 7 additions & 7 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="vendor/autoload.php">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="vendor/autoload.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="unit">
<directory>./tests/unit</directory>
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>
35 changes: 0 additions & 35 deletions src/Authentication/Authentication.php

This file was deleted.

94 changes: 0 additions & 94 deletions src/Authentication/Password.php

This file was deleted.

39 changes: 39 additions & 0 deletions src/Authenticator/Authenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* @package Nexcess/Salesforce
* @author Nexcess.net <[email protected]>
* @copyright 2021 LiquidWeb Inc.
* @license MIT
*/

namespace Nexcess\Salesforce\Authenticator;

use GuzzleHttp\Client as HttpClient;

use Nexcess\Salesforce\Error\Authentication as AuthenticationException;

/**
* Handles Authenticating an HTTP Client with Salesforce.
*/
interface Authenticator {

/**
* Factory: builds a new Authenticator instance.
*
* Note, because Guzzle Clients are immutable (i.e., we cannot change the base_uri, etc.),
* we take default options here instead of injecting an actual Client instance.
*
* @param array $options Default options for the HTTP Client to authenticate with
* @return Authenticator The new instance
*/
public static function create(array $options = []) : Authenticator;

/**
* Authenticates with the Salesforce Api.
*
* @param array $parameters Authenticator parameters
* @throws AuthenticationException FAILED on failure
* @return HttpClient An authenticated HTTP Client
*/
public function authenticate(array $parameters) : HttpClient;
}
Loading

0 comments on commit efa080b

Please sign in to comment.