Skip to content

Commit

Permalink
Merge pull request #18 from langleyfoxall/feature/public-app-support
Browse files Browse the repository at this point in the history
Public Xero app support
  • Loading branch information
Jordan Hall authored Nov 8, 2019
2 parents bcf931e + e58c87e commit 1e1bfb0
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 125 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ XERO_CONSUMER_KEY=XXXXXXIXHKXXXXXXST0TU44ZXXXXXX
XERO_CONSUMER_SECRET=XXXXXXBNNUXXXXXXGWAJNFOUXXXXXX
```

*Note: This library currently only supports private Xero apps, designed for
internal use by your organisation.*
If you wish to use a public app, you will have to add a new app to the
configuration file or change the existing one. The `app_type` should be
`public` rather than `private`.

## Usage

Expand Down
118 changes: 3 additions & 115 deletions src/Apps/PrivateXeroApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@

namespace LangleyFoxall\XeroLaravel\Apps;

use BadMethodCallException;
use Exception;
use Illuminate\Support\Str;
use LangleyFoxall\XeroLaravel\Utils;
use LangleyFoxall\XeroLaravel\Wrappers\QueryWrapper;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use LangleyFoxall\XeroLaravel\Traits\HasXeroRelationships;
use XeroPHP\Application\PrivateApplication;

/**
Expand All @@ -18,12 +13,7 @@
*/
class PrivateXeroApp extends PrivateApplication
{
/**
* Map between relationship names and Xero PHP library models
*
* @var array
*/
private $relationshipToModelMap = [];
use HasXeroRelationships;

/**
* PrivateXeroApp constructor.
Expand All @@ -35,108 +25,6 @@ public function __construct($config)
{
parent::__construct($config);

$this->populateRelationshipToModelMap('Accounting', '');
$this->populateRelationshipToModelMap('Assets', 'assets');
$this->populateRelationshipToModelMap('Files', 'files');
$this->populateRelationshipToModelMap('PayrollAU', 'payrollAU');
$this->populateRelationshipToModelMap('PayrollUS', 'payrollUS');
}

/**
* Retrieve a collection of the available relationships.
*
* @return \Illuminate\Support\Collection
*/
public function getAvailableRelationships()
{
$relationships = array_keys($this->relationshipToModelMap);

sort($relationships);

return collect($relationships);
}

/**
* Populate the relationship to model map, for all models within
* a specified model subdirectory.
*
* @param $modelSubdirectory
* @param $prefix
* @throws Exception
*/
public function populateRelationshipToModelMap($modelSubdirectory, $prefix)
{
$vendor = Utils::getVendorDirectory();

$dependencyDirectory = Utils::normalizePath(
$vendor.'/calcinai/xero-php/src/'
);

$modelsDirectory = Utils::normalizePath(
$dependencyDirectory.'/XeroPHP/Models/'.$modelSubdirectory
);

$di = new RecursiveDirectoryIterator($modelsDirectory);
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if ($file->isDir() || !Str::endsWith($filename, '.php')) {
continue;
}

$relationship = Str::camel(
$prefix.Str::plural(
str_replace(
[$modelsDirectory, '.php', DIRECTORY_SEPARATOR], '',
$filename
)
)
);

$model = str_replace(
[$dependencyDirectory, DIRECTORY_SEPARATOR, '.php'], ['', '\\'],
$filename
);

$this->relationshipToModelMap[$relationship] = $model;
}
}

/**
* Call a relationship method, and return a QueryWrapper.
* Syntax: $xero->contacts()
*
* @param $name
* @param $arguments
* @return QueryWrapper
* @throws \XeroPHP\Remote\Exception
*/
public function __call($name, $arguments)
{
$relationships = array_keys($this->relationshipToModelMap);

if (!in_array($name, $relationships)) {
throw new BadMethodCallException();
}

$model = $this->relationshipToModelMap[$name];

return new QueryWrapper($this->load($model), $this);
}

/**
* Call a relationship method and get results.
* Syntax: $xero->contacts
*
* @param $name
* @return null
*/
public function __get($name)
{
$relationships = array_keys($this->relationshipToModelMap);

if (!in_array($name, $relationships)) {
return null;
}

return $this->$name()->get();
$this->populateRelationshipToModelMaps();
}
}
30 changes: 30 additions & 0 deletions src/Apps/PublicXeroApp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace LangleyFoxall\XeroLaravel\Apps;

use Exception;
use LangleyFoxall\XeroLaravel\Traits\HasXeroRelationships;
use XeroPHP\Application\PublicApplication;

/**
* Class PublicXeroApp
*
* @package LangleyFoxall\XeroLaravel
*/
class PublicXeroApp extends PublicApplication
{
use HasXeroRelationships;

/**
* PrivateXeroApp constructor.
*
* @param $config
* @throws Exception
*/
public function __construct($config)
{
parent::__construct($config);

$this->populateRelationshipToModelMaps();
}
}
133 changes: 133 additions & 0 deletions src/Traits/HasXeroRelationships.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace LangleyFoxall\XeroLaravel\Traits;

use BadMethodCallException;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use LangleyFoxall\XeroLaravel\Utils;
use LangleyFoxall\XeroLaravel\Wrappers\QueryWrapper;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

trait HasXeroRelationships
{
/**
* Map between relationship names and Xero PHP library models
*
* @var array
*/
private $relationshipToModelMap = [];

/**
* Retrieve a collection of the available relationships.
*
* @return Collection
*/
public function getAvailableRelationships()
{
$relationships = array_keys($this->relationshipToModelMap);

sort($relationships);

return collect($relationships);
}

/**
* Populates all relationship to model maps.
*
* @throws Exception
*/
public function populateRelationshipToModelMaps()
{
$this->populateRelationshipToModelMap('Accounting', '');
$this->populateRelationshipToModelMap('Assets', 'assets');
$this->populateRelationshipToModelMap('Files', 'files');
$this->populateRelationshipToModelMap('PayrollAU', 'payrollAU');
$this->populateRelationshipToModelMap('PayrollUS', 'payrollUS');
}

/**
* Populate the relationship to model map, for all models within
* a specified model subdirectory.
*
* @param $modelSubdirectory
* @param $prefix
* @throws Exception
*/
public function populateRelationshipToModelMap($modelSubdirectory, $prefix)
{
$vendor = Utils::getVendorDirectory();

$dependencyDirectory = Utils::normalizePath(
$vendor.'/calcinai/xero-php/src/'
);

$modelsDirectory = Utils::normalizePath(
$dependencyDirectory.'/XeroPHP/Models/'.$modelSubdirectory
);

$di = new RecursiveDirectoryIterator($modelsDirectory);
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if ($file->isDir() || !Str::endsWith($filename, '.php')) {
continue;
}

$relationship = Str::camel(
$prefix.Str::plural(
str_replace(
[$modelsDirectory, '.php', DIRECTORY_SEPARATOR], '',
$filename
)
)
);

$model = str_replace(
[$dependencyDirectory, DIRECTORY_SEPARATOR, '.php'], ['', '\\'],
$filename
);

$this->relationshipToModelMap[$relationship] = $model;
}
}

/**
* Call a relationship method, and return a QueryWrapper.
* Syntax: $xero->contacts()
*
* @param $name
* @param $arguments
* @return QueryWrapper
*/
public function __call($name, $arguments)
{
$relationships = array_keys($this->relationshipToModelMap);

if (!in_array($name, $relationships)) {
throw new BadMethodCallException();
}

$model = $this->relationshipToModelMap[$name];

return new QueryWrapper($this->load($model), $this);
}

/**
* Call a relationship method and get results.
* Syntax: $xero->contacts
*
* @param $name
* @return null
*/
public function __get($name)
{
$relationships = array_keys($this->relationshipToModelMap);

if (!in_array($name, $relationships)) {
return null;
}

return $this->$name()->get();
}
}
6 changes: 4 additions & 2 deletions src/Wrappers/QueryWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use Illuminate\Support\Collection;
use LangleyFoxall\XeroLaravel\Apps\PrivateXeroApp;
use LangleyFoxall\XeroLaravel\Traits\HasXeroRelationships;
use XeroPHP\Application;
use XeroPHP\Remote\Query;

/**
Expand All @@ -29,9 +31,9 @@ class QueryWrapper
* Builds a QueryWrapper around a Query object
*
* @param Query $query
* @param PrivateXeroApp $app
* @param Application $app
*/
public function __construct(Query $query, PrivateXeroApp $app)
public function __construct(Query $query, Application $app)
{
$this->query = $query;
$this->app = $app;
Expand Down
18 changes: 12 additions & 6 deletions src/Xero.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?php
namespace LangleyFoxall\XeroLaravel;

use Exception;
use LangleyFoxall\XeroLaravel\Apps\PrivateXeroApp;
use LangleyFoxall\XeroLaravel\Apps\PublicXeroApp;
use XeroPHP\Application;

class Xero
{
Expand All @@ -12,7 +15,7 @@ class Xero
*
* @param string $key
* @return mixed
* @throws \Exception
* @throws Exception
*/
public function app($key = 'default')
{
Expand All @@ -27,15 +30,15 @@ public function app($key = 'default')
* Creates the XeroApp object
*
* @param string $key
* @return PrivateXeroApp
* @throws \Exception
* @return Application
* @throws Exception
*/
private function createApp($key)
{
$config = config(Constants::CONFIG_KEY);

if (!isset($config['apps']) || !isset($config['apps'][$key])) {
throw new \Exception('The specified key could not be found in the Xero \'apps\' array, ' .
throw new Exception('The specified key could not be found in the Xero \'apps\' array, ' .
'or the \'apps\' array does not exist.');
}

Expand All @@ -47,11 +50,14 @@ private function createApp($key)
break;

case 'public':
return new PublicXeroApp($appConfig);
break;

case 'partner':
throw new \Exception('Public and partner Xero app types are not yet supported.');
throw new Exception('Partner Xero app types are not yet supported.');
break;
}

throw new \Exception('Xero app type is invalid. Should be \'private\', \'public\', or \'partner\'.');
throw new Exception('Xero app type is invalid. Should be \'private\', \'public\', or \'partner\'.');
}
}

0 comments on commit 1e1bfb0

Please sign in to comment.