Skip to content

Commit

Permalink
Merge pull request #7 from stitch-digital/support-for-multiple-connec…
Browse files Browse the repository at this point in the history
…tions

added support for passing base url and api key through constructor
  • Loading branch information
johntrickett86 authored Oct 10, 2024
2 parents eb4d805 + 187f925 commit 1e8eeba
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 35 deletions.
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,18 @@ return [
];
```

You will need to add the following environment variables to your `.env` file:
This package is built using Saloon. Check out their [documentation here](https://docs.saloon.dev/).

## Usage

### Using a Single Simpro Connection
If you are using a single Simpro connection, you can add the following environment variables to your `.env` file:

```bash
SIMPRO_BASE_URL=https://your-build-url.simprosuite.com
SIMPRO_API_KEY=your-api-key
```

This package is built using Saloon. Check out their [documentation here](https://docs.saloon.dev/).

## Usage

To use the package, you can use the Simpro facade to make requests to the API:

```php
Expand All @@ -129,6 +130,25 @@ use StitchDigital\LaravelSimproApi\Requests\Info\GetInfo;
$response = Simpro::send(new GetInfo())->json();
```

### Using Multiple Simpro Connections
If you are using multiple Simpro connections, you can pass the base URL and API key to the constructor of the request - although this means you can no longer user the facade:

```php
use StitchDigital\LaravelSimproApi\LaravelSimproApi;
use StitchDigital\LaravelSimproApi\Requests\Info\GetInfo;

$connector = new LaravelSimproApi(
baseUrl: 'https://custom-api-url.simprosuite.com',
apiKey: 'custom-api-key'
);

$response = $connector->send(new GetInfo());

$response->json();
```

### Available Requests

For a full list of available requests, use the following command:

```bash
Expand Down
184 changes: 158 additions & 26 deletions src/Commands/LaravelSimproApiCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Console\Helper\Table;
use ReflectionClass;
use ReflectionParameter;

use function Laravel\Prompts\table;

class LaravelSimproApiCommand extends Command
{
Expand All @@ -16,49 +19,178 @@ public function handle(): int
{
$this->info('Listing all available requests in the Simpro package:');

// Define the path to the Requests folder
$requestPath = base_path('vendor/stitch-digital/laravel-simpro-api/src/Requests');
// Get the request path
$requestPath = $this->getRequestPath();

// Validate the request path
if (! $this->validateRequestPath($requestPath)) {
return self::FAILURE;
}

// Fetch the request classes and format the output
$rows = $this->getRequestRows($requestPath);

// Display the formatted requests in a table using Laravel Prompts
$this->displayRequestTable($rows);

$this->info('Request listing complete.');

return self::SUCCESS;
}

/**
* Get the base path for the Requests folder.
*/
protected function getRequestPath(): string
{
return base_path('vendor/stitch-digital/laravel-simpro-api/src/Requests');
}

// Check if the directory exists
/**
* Validate if the request path exists.
*/
protected function validateRequestPath(string $requestPath): bool
{
if (! is_dir($requestPath)) {
$this->error('Requests directory not found.');

return self::FAILURE;
return false;
}

// Create a Filesystem instance to work with files
$filesystem = new Filesystem;
return true;
}

// Get all PHP files in the Requests directory recursively
/**
* Fetch and format the request classes into table rows.
*
* @return array<int, array{string, string, string}>
*/
protected function getRequestRows(string $requestPath): array
{
$filesystem = new Filesystem;
$files = $filesystem->allFiles($requestPath);

// Create an array to store formatted paths
$rows = [];

// Loop through the files and format the output
foreach ($files as $file) {
// Get the relative path from the Requests folder and format it
$relativePath = str_replace([$requestPath.DIRECTORY_SEPARATOR, '.php'], '', $file->getPathname());
$relativePath = $this->getRelativePath($file, $requestPath);
$subDirectory = $this->getSubDirectory($relativePath);
$fileName = $this->getFileName($relativePath);
$className = $this->getClassName($relativePath);
$constructorParams = $this->getConstructorParams($className);

$rows[] = [$subDirectory, $fileName, implode(', ', $constructorParams)];
}

return $rows;
}

/**
* Display the request data in a table using Laravel Prompts.
*
* @param array<int, array{string, string, string}> $rows
*/
protected function displayRequestTable(array $rows): void
{
table(
headers: ['Directory', 'Request', 'Parameters'],
rows: $rows
);
}

/**
* Get the relative path of a file.
*/
protected function getRelativePath(\SplFileInfo $file, string $requestPath): string
{
return str_replace([$requestPath.DIRECTORY_SEPARATOR, '.php'], '', $file->getPathname());
}

/**
* Get the subdirectory from a relative path.
*/
protected function getSubDirectory(string $relativePath): string
{
$pathParts = explode(DIRECTORY_SEPARATOR, $relativePath);

return implode(' / ', array_slice($pathParts, 0, -1));
}

/**
* Get the file name from a relative path.
*/
protected function getFileName(string $relativePath): string
{
$pathParts = explode(DIRECTORY_SEPARATOR, $relativePath);

return end($pathParts);
}

/**
* Get the fully qualified class name from a relative path.
*/
protected function getClassName(string $relativePath): string
{
return 'StitchDigital\\LaravelSimproApi\\Requests\\'.str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath);
}

// Split the path into parts
$pathParts = explode(DIRECTORY_SEPARATOR, $relativePath);
/**
* Get the constructor parameters for a given class.
*
* @return array<int, string>
*/
protected function getConstructorParams(string $className): array
{
if (! class_exists($className)) {
return [];
}

// Combine subdirectory and filename into a formatted path
$subDirectory = implode(' / ', array_slice($pathParts, 0, -1));
$fileName = end($pathParts);
$reflection = new ReflectionClass($className);

// Add the subdirectory and filename to the rows array
$rows[] = [$subDirectory, $fileName];
$constructor = $reflection->getConstructor();
if (! $constructor) {
return [];
}

// Create a table to display the requests
$this->table(
['Directory', 'Request'], // Table headers
$rows // Table rows
return array_map(
fn (ReflectionParameter $param) => $this->formatParameter($param),
$constructor->getParameters()
);
}

$this->info('Request listing complete.');
/**
* Format a ReflectionParameter into a string for display.
*/
protected function formatParameter(ReflectionParameter $param): string
{
$type = $param->getType();
$typeString = '';

return self::SUCCESS;
// Handle named types (e.g., int, string)
if ($type instanceof \ReflectionNamedType) {
$typeString = $type->getName().' ';
}
// Handle union types (e.g., int|string)
elseif ($type instanceof \ReflectionUnionType) {
$typeString = implode('|', array_map(
fn ($t) => $t instanceof \ReflectionNamedType ? $t->getName() : '',
$type->getTypes()
)).' ';
}
// Handle intersection types (e.g., A&B)
elseif ($type instanceof \ReflectionIntersectionType) {
$typeString = implode('&', array_map(
fn ($t) => $t instanceof \ReflectionNamedType ? $t->getName() : '',
$type->getTypes()
)).' ';
}

$paramString = '$'.$param->getName();

// Handle optional parameters with default values
if ($param->isOptional()) {
$paramString .= ' = '.var_export($param->getDefaultValue(), true);
}

return $typeString.$paramString;
}
}
16 changes: 12 additions & 4 deletions src/LaravelSimproApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,29 @@
use Saloon\RateLimitPlugin\Contracts\RateLimitStore;
use Saloon\RateLimitPlugin\Limit;
use Saloon\RateLimitPlugin\Stores\LaravelCacheStore;
use Saloon\RateLimitPlugin\Traits\HasRateLimits;
use Saloon\RateLimitPlugin\Traits\HasRateLimits; // Correct import for the HasRateLimits trait
use Saloon\Traits\Plugins\AcceptsJson;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;

class LaravelSimproApi extends Connector implements Cacheable, HasPagination
{
use AcceptsJson, AlwaysThrowOnErrors, HasCaching, HasRateLimits;

private string $baseUrl;

private string $apiKey;

// Constants for time values
private const DEFAULT_MAX_WAIT_TIME_SECONDS = 60;

private const DEFAULT_DELAY_MILLISECONDS = 1000;

public function __construct()
public function __construct(?string $baseUrl = null, ?string $apiKey = null)
{
// Set the base URL and API key from the constructor or default config
$this->baseUrl = $baseUrl ?? config('simpro-api.base_url');
$this->apiKey = $apiKey ?? config('simpro-api.api_key');

// Set the rate limiting flag from the config
$this->rateLimitingEnabled = config('simpro-api.rate_limit.enabled', true);
}
Expand All @@ -43,7 +51,7 @@ public function __construct()
*/
public function resolveBaseUrl(): string
{
return config('simpro-api.base_url').'/api/v1.0';
return $this->baseUrl.'/api/v1.0';
}

/**
Expand All @@ -67,7 +75,7 @@ protected function defaultConfig(): array
*/
protected function defaultAuth(): TokenAuthenticator
{
return new TokenAuthenticator(config('simpro-api.api_key'));
return new TokenAuthenticator($this->apiKey);
}

/**
Expand Down

0 comments on commit 1e8eeba

Please sign in to comment.