diff --git a/samples/resthookManager.php b/samples/resthookManager.php new file mode 100644 index 0000000..c5c4410 --- /dev/null +++ b/samples/resthookManager.php @@ -0,0 +1,64 @@ + '', + 'clientSecret' => '', + 'redirectUri' => '', +)); + +// By default, the SDK uses the Guzzle HTTP library for requests. To use CURL, +// you can change the HTTP client by using following line: +// $infusionsoft->setHttpClient(new \Infusionsoft\Http\CurlClient()); + +// If the serialized token is available in the session storage, we tell the SDK +// to use that token for subsequent requests. +if (isset($_SESSION['token'])) { + $infusionsoft->setToken(unserialize($_SESSION['token'])); +} + +// If we are returning from Infusionsoft we need to exchange the code for an +// access token. +if (isset($_GET['code']) and !$infusionsoft->getToken()) { + $infusionsoft->requestAccessToken($_GET['code']); + $_SESSION['token'] = serialize($infusionsoft->getToken()); +} + +function resthookManager($infusionsoft) { + $resthooks = $infusionsoft->resthooks(); + + // first, create a new task + $resthook = $resthooks->create([ + 'eventKey' => 'contact.add', + 'hookUrl' => 'http://infusionsoft.app/verifyRestHook.php' + ]); + var_dump($resthook); + $resthook = $resthooks->find($resthook->id)->verify(); + + return $resthook; +} + +if ($infusionsoft->getToken()) { + try { + $resthook = resthookManager($infusionsoft); + } + catch (\Infusionsoft\TokenExpiredException $e) { + // If the request fails due to an expired access token, we can refresh + // the token and then do the request again. + $infusionsoft->refreshAccessToken(); + + // Save the serialized token to the current session for subsequent requests + $_SESSION['token'] = serialize($infusionsoft->getToken()); + + $resthook = resthookManager($infusionsoft); + } + + var_dump($resthook); +} +else { + echo 'Click here to authorize'; +} diff --git a/samples/verifyRestHook.php b/samples/verifyRestHook.php new file mode 100644 index 0000000..93db154 --- /dev/null +++ b/samples/verifyRestHook.php @@ -0,0 +1,21 @@ + '', + 'clientSecret' => '', + 'redirectUri' => '', +)); + +// In order to verify the endpoint, we need to return the X-Hook-Secret header. +// By default, the autoverify() function will set the proper header, but if you +// pass false as the first argument to autoverify(false) the function will simply +// return the header value for you to set as you please (handy if you are using +// a PHP class or framework that manages requests for you + +$infusionsoft->resthooks()->autoverify(); + +return; \ No newline at end of file diff --git a/src/Infusionsoft/Api/Rest/RestModel.php b/src/Infusionsoft/Api/Rest/RestModel.php index 7b2f097..6843e94 100644 --- a/src/Infusionsoft/Api/Rest/RestModel.php +++ b/src/Infusionsoft/Api/Rest/RestModel.php @@ -11,952 +11,990 @@ * Give Jens some love: https://github.com/jenssegers/laravel-model */ -abstract class RestModel implements ArrayAccess, JsonSerializable { - - protected $client = null; - - protected $where = []; - - protected $return_key = ''; - - /** - * The model's attributes. - * - * @var array - */ - protected $attributes = array(); - - /** - * The attributes that should be hidden for arrays. - * - * @var array - */ - protected $hidden = array(); - - /** - * The attributes that should be visible in arrays. - * - * @var array - */ - protected $visible = array(); - - /** - * The accessors to append to the model's array form. - * - * @var array - */ - protected $appends = array(); - - /** - * The attributes that should be casted to native types. - * - * @var array - */ - protected $casts = array(); - - /** - * Indicates whether attributes are snake cased on arrays. - * - * @var bool - */ - public static $snakeAttributes = true; - - /** - * The array of booted models. - * - * @var array - */ - protected static $booted = array(); - - /** - * The cache of the mutated attributes for each class. - * - * @var array - */ - protected static $mutatorCache = array(); - - /** - * Create a new model instance. - * - * @param array $attributes - * @return self - */ - public function __construct(Infusionsoft $client) - { - $this->client = $client; - - $this->bootIfNotBooted(); - } - - /** - * Returns the full URL for the query, optionally concatinated with additional URI elements - * - * @return string - */ - public function getFullUrl($additional = null) - { - $url = $this->full_url; - if(substr($url, -1) != '/') { - $url .= '/'; - } - - if($additional) { - $additional = ltrim($additional, '/'); - } - - return $url.$additional; - } - - /** - * Returns the full URL for the index request, allowing for specific index endpoints - * - * @return string - */ - public function getIndexUrl() - { - $url = $this->full_url; - - return $url; - } - - /** - * Mock this model from itself. - * - * @param array $attributes - * @return self - */ - public function mock(array $attributes = []) - { - $this->fill($attributes); - return $this; - } - - /** - * Creates a new object and saves it in storage/API. - * - * @param array $attributes - * @return self - */ - public function create(array $attributes = []) - { - $this->mock($attributes); - $this->save(); - return $this; - } - - /** - * Save this model to storage/api. - * - * @return self - */ - public function save() - { - // well, is it a post or a put? we need to figure out if this thing exists or not - // long story short, if the "id" is set, it's an update. - if(isset($this->id)) - { - $data = $this->client->restfulRequest('put', $this->getFullUrl($this->id), (array) $this->toArray()); - } - else - { - $data = $this->client->restfulRequest('post', $this->getFullUrl(), (array) $this->toArray()); - } - - $this->fill($data); - - return $this; - } - - public function find($id) - { - $data = $this->client->restfulRequest('get', $this->getFullUrl($id)); - $this->fill($data); - - return $this; - } - - public function sync($syncToken) { - $this->where['sync_token'] = $syncToken; - $data = $this->client->restfulRequest('get', $this->getFullUrl()); - $this->fill($data); - - return $this; - } - - public function where($key, $value = null) - { - if(is_array($key)) - { - foreach($key as $k => $v) - { - $this->where[$k] = $v; - } - - return $this; - } - - $this->where[$key] = $value; - - return $this; - } - - public function delete() - { - $response = $this->client->restfulRequest('delete', $this->getFullUrl($this->id)); - - return true; - } - - public function get() - { - if(!empty($this->where)) - { - $data = $this->client->restfulRequest('get', $this->getIndexUrl(), $this->where); - } - else - { - $data = $this->client->restfulRequest('get', $this->getIndexUrl()); - } - - $cursor = []; - - if(isset($data['sync_token'])) - { - $cursor = $data['sync_token']; - } - - $collection = $this->collect($data, $cursor); - - return $collection; - } - - public function all() - { - $data = $this->client->restfulRequest('get', $this->getIndexUrl()); - - $cursor = []; - - if(isset($data['sync_token'])) - { - $cursor = $data['sync_token']; - } - - $collection = $this->collect($data, $cursor); - - return $collection; - } - - public function collect(array $array, $cursor = []) - { - $items = []; - - foreach($array[$this->return_key] as $item) - { - $thing = clone $this; - array_push($items, $thing->mock($item)); - } - - return new InfusionsoftCollection($items); - } - - /** - * Check if the model needs to be booted and if so, do it. - * - * @return void - */ - protected function bootIfNotBooted() - { - $class = get_class($this); - - if ( ! isset(static::$booted[$class])) - { - static::$booted[$class] = true; - - static::boot(); - } - } - - /** - * The "booting" method of the model. - * - * @return void - */ - protected static function boot() - { - if (function_exists('class_uses_recursive')) - { - static::bootTraits(); - } - } - - /** - * Boot all of the bootable traits on the model. - * - * @return void - */ - protected static function bootTraits() - { - foreach (class_uses_recursive(get_called_class()) as $trait) - { - if (method_exists(get_called_class(), $method = 'boot'.class_basename($trait))) - { - forward_static_call([get_called_class(), $method]); - } - } - } - - /** - * Fill the model with an array of attributes. - * - * @param array $attributes - * @return self - */ - public function fill(array $attributes) - { - foreach ($attributes as $key => $value) - { - $this->setAttribute($key, $value); - } - - return $this; - } - - /** - * Create a new instance of the given model. - * - * @param array $attributes - * @param bool $exists - * @return self - */ - public function newInstance($attributes = array()) - { - $model = new static((array) $attributes); - - return $model; - } - - /** - * Create a collection of models from plain arrays. - * - * @param array $items - * @return array - */ - public static function hydrate(array $items) - { - $instance = new static; - - $items = array_map(function ($item) use ($instance) - { - return $instance->newInstance($item); - }, $items); - - return $items; - } - - /** - * Get the hidden attributes for the model. - * - * @return array - */ - public function getHidden() - { - return $this->hidden; - } - - /** - * Set the hidden attributes for the model. - * - * @param array $hidden - * @return void - */ - public function setHidden(array $hidden) - { - $this->hidden = $hidden; - } - - /** - * Add hidden attributes for the model. - * - * @param array|string|null $attributes - * @return void - */ - public function addHidden($attributes = null) - { - $attributes = is_array($attributes) ? $attributes : func_get_args(); - - $this->hidden = array_merge($this->hidden, $attributes); - } - - /** - * Get the visible attributes for the model. - * - * @return array - */ - public function getVisible() - { - return $this->visible; - } - - /** - * Set the visible attributes for the model. - * - * @param array $visible - * @return void - */ - public function setVisible(array $visible) - { - $this->visible = $visible; - } - - /** - * Add visible attributes for the model. - * - * @param array|string|null $attributes - * @return void - */ - public function addVisible($attributes = null) - { - $attributes = is_array($attributes) ? $attributes : func_get_args(); - - $this->visible = array_merge($this->visible, $attributes); - } - - /** - * Set the accessors to append to model arrays. - * - * @param array $appends - * @return void - */ - public function setAppends(array $appends) - { - $this->appends = $appends; - } - - /** - * Convert the model instance to JSON. - * - * @param int $options - * @return string - */ - public function toJson($options = 0) - { - return json_encode($this->toArray(), $options); - } - - /** - * Convert the object into something JSON serializable. - * - * @return array - */ - public function jsonSerialize() - { - return $this->toArray(); - } - - /** - * Convert the model instance to an array. - * - * @return array - */ - public function toArray() - { - return $this->attributesToArray(); - } - - /** - * Convert the model's attributes to an array. - * - * @return array - */ - public function attributesToArray() - { - $attributes = $this->getArrayableAttributes(); - - $mutatedAttributes = $this->getMutatedAttributes(); - - // We want to spin through all the mutated attributes for this model and call - // the mutator for the attribute. We cache off every mutated attributes so - // we don't have to constantly check on attributes that actually change. - foreach ($mutatedAttributes as $key) - { - if ( ! array_key_exists($key, $attributes)) continue; - - $attributes[$key] = $this->mutateAttributeForArray( - $key, $attributes[$key] - ); - } - - // Next we will handle any casts that have been setup for this model and cast - // the values to their appropriate type. If the attribute has a mutator we - // will not perform the cast on those attributes to avoid any confusion. - foreach ($this->casts as $key => $value) - { - if ( ! array_key_exists($key, $attributes) || - in_array($key, $mutatedAttributes)) continue; - - $attributes[$key] = $this->castAttribute( - $key, $attributes[$key] - ); - } - - // Here we will grab all of the appended, calculated attributes to this model - // as these attributes are not really in the attributes array, but are run - // when we need to array or JSON the model for convenience to the coder. - foreach ($this->getArrayableAppends() as $key) - { - $attributes[$key] = $this->mutateAttributeForArray($key, null); - } - - return $attributes; - } - - /** - * Get an attribute array of all arrayable attributes. - * - * @return array - */ - protected function getArrayableAttributes() - { - return $this->getArrayableItems($this->attributes); - } - - /** - * Get all of the appendable values that are arrayable. - * - * @return array - */ - protected function getArrayableAppends() - { - if ( ! count($this->appends)) return []; - - return $this->getArrayableItems( - array_combine($this->appends, $this->appends) - ); - } - - /** - * Get an attribute array of all arrayable values. - * - * @param array $values - * @return array - */ - protected function getArrayableItems(array $values) - { - if (count($this->visible) > 0) - { - return array_intersect_key($values, array_flip($this->visible)); - } - - return array_diff_key($values, array_flip($this->hidden)); - } - - /** - * Get an attribute from the model. - * - * @param string $key - * @return mixed - */ - public function getAttribute($key) - { - $inAttributes = array_key_exists($key, $this->attributes); - - // If the key references an attribute, we can just go ahead and return the - // plain attribute value from the model. This allows every attribute to - // be dynamically accessed through the _get method without accessors. - if ($inAttributes or $this->hasGetMutator($key)) - { - return $this->getAttributeValue($key); - } - } - - /** - * Get a plain attribute (not a relationship). - * - * @param string $key - * @return mixed - */ - protected function getAttributeValue($key) - { - $value = $this->getAttributeFromArray($key); - - // If the attribute has a get mutator, we will call that then return what - // it returns as the value, which is useful for transforming values on - // retrieval from the model to a form that is more useful for usage. - if ($this->hasGetMutator($key)) - { - return $this->mutateAttribute($key, $value); - } - - // If the attribute exists within the cast array, we will convert it to - // an appropriate native PHP type dependant upon the associated value - // given with the key in the pair. Dayle made this comment line up. - if ($this->hasCast($key)) - { - $value = $this->castAttribute($key, $value); - } - - return $value; - } - - /** - * Get an attribute from the $attributes array. - * - * @param string $key - * @return mixed - */ - protected function getAttributeFromArray($key) - { - if (array_key_exists($key, $this->attributes)) - { - return $this->attributes[$key]; - } - } - - /** - * Determine if a get mutator exists for an attribute. - * - * @param string $key - * @return bool - */ - public function hasGetMutator($key) - { - return method_exists($this, 'get'.$this->studly($key).'Attribute'); - } - - /** - * Get the value of an attribute using its mutator. - * - * @param string $key - * @param mixed $value - * @return mixed - */ - protected function mutateAttribute($key, $value) - { - return $this->{'get'.$this->studly($key).'Attribute'}($value); - } - - /** - * Get the value of an attribute using its mutator for array conversion. - * - * @param string $key - * @param mixed $value - * @return mixed - */ - protected function mutateAttributeForArray($key, $value) - { - $value = $this->mutateAttribute($key, $value); - - return $value instanceof ArrayableInterface ? $value->toArray() : $value; - } - - /** - * Determine whether an attribute should be casted to a native type. - * - * @param string $key - * @return bool - */ - protected function hasCast($key) - { - return array_key_exists($key, $this->casts); - } - - /** - * Determine whether a value is JSON castable for inbound manipulation. - * - * @param string $key - * @return bool - */ - protected function isJsonCastable($key) - { - if ($this->hasCast($key)) - { - return in_array( - $this->getCastType($key), ['array', 'json', 'object'], true - ); - } - - return false; - } - - /** - * Get the type of cast for a model attribute. - * - * @param string $key - * @return string - */ - protected function getCastType($key) - { - return trim(strtolower($this->casts[$key])); - } - - /** - * Cast an attribute to a native PHP type. - * - * @param string $key - * @param mixed $value - * @return mixed - */ - protected function castAttribute($key, $value) - { - if (is_null($value)) return $value; - - switch ($this->getCastType($key)) - { - case 'int': - case 'integer': - return (int) $value; - case 'real': - case 'float': - case 'double': - return (float) $value; - case 'string': - return (string) $value; - case 'bool': - case 'boolean': - return (bool) $value; - case 'object': - return json_decode($value); - case 'array': - case 'json': - return json_decode($value, true); - default: - return $value; - } - } - - /** - * Set a given attribute on the model. - * - * @param string $key - * @param mixed $value - * @return void - */ - public function setAttribute($key, $value) - { - // First we will check for the presence of a mutator for the set operation - // which simply lets the developers tweak the attribute as it is set on - // the model, such as "json_encoding" an listing of data for storage. - if ($this->hasSetMutator($key)) - { - $method = 'set'.$this->studly($key).'Attribute'; - - return $this->{$method}($value); - } - - if ($this->isJsonCastable($key)) - { - $value = json_encode($value); - } - - $this->attributes[$key] = $value; - } - - /** - * Determine if a set mutator exists for an attribute. - * - * @param string $key - * @return bool - */ - public function hasSetMutator($key) - { - return method_exists($this, 'set'.$this->studly($key).'Attribute'); - } - - /** - * Clone the model into a new, non-existing instance. - * - * @return self - */ - public function replicate() - { - with($instance = new static)->fill($this->attributes); - - return $instance; - } - - /** - * Get all of the current attributes on the model. - * - * @return array - */ - public function getAttributes() - { - return $this->attributes; - } - - /** - * Get the mutated attributes for a given instance. - * - * @return array - */ - public function getMutatedAttributes() - { - $class = get_class($this); - - if ( ! isset(static::$mutatorCache[$class])) - { - static::cacheMutatedAttributes($class); - } - - return static::$mutatorCache[$class]; - } - - /** - * Extract and cache all the mutated attributes of a class. - * - * @param string $class - * @return void - */ - public static function cacheMutatedAttributes($class) - { - $mutatedAttributes = array(); - - // Here we will extract all of the mutated attributes so that we can quickly - // spin through them after we export models to their array form, which we - // need to be fast. This'll let us know the attributes that can mutate. - foreach (get_class_methods($class) as $method) - { - if (strpos($method, 'Attribute') !== false && - preg_match('/^get(.+)Attribute$/', $method, $matches)) - { - if (static::$snakeAttributes) $matches[1] = snake_case($matches[1]); - - $mutatedAttributes[] = lcfirst($matches[1]); - } - } - - static::$mutatorCache[$class] = $mutatedAttributes; - } - - /** - * Dynamically retrieve attributes on the model. - * - * @param string $key - * @return mixed - */ - public function __get($key) - { - return $this->getAttribute($key); - } - - /** - * Dynamically set attributes on the model. - * - * @param string $key - * @param mixed $value - * @return void - */ - public function __set($key, $value) - { - $this->setAttribute($key, $value); - } - - /** - * Determine if the given attribute exists. - * - * @param mixed $offset - * @return bool - */ - public function offsetExists($offset) - { - return isset($this->$offset); - } - - /** - * Get the value for a given offset. - * - * @param mixed $offset - * @return mixed - */ - public function offsetGet($offset) - { - return $this->$offset; - } - - /** - * Set the value for a given offset. - * - * @param mixed $offset - * @param mixed $value - * @return void - */ - public function offsetSet($offset, $value) - { - $this->$offset = $value; - } - - /** - * Unset the value for a given offset. - * - * @param mixed $offset - * @return void - */ - public function offsetUnset($offset) - { - unset($this->$offset); - } - - /** - * Determine if an attribute exists on the model. - * - * @param string $key - * @return void - */ - public function __isset($key) - { - return ((isset($this->attributes[$key]) || isset($this->relations[$key])) || - ($this->hasGetMutator($key) && ! is_null($this->getAttributeValue($key)))); - } - - /** - * Unset an attribute on the model. - * - * @param string $key - * @return void - */ - public function __unset($key) - { - unset($this->attributes[$key]); - } - - /** - * Handle dynamic static method calls into the method. - * - * @param string $method - * @param array $parameters - * @return mixed - */ - public static function __callStatic($method, $parameters) - { - $instance = new static; - - return call_user_func_array(array($instance, $method), $parameters); - } - - /** - * Convert the model to its string representation. - * - * @return string - */ - public function __toString() - { - return $this->toJson(); - } - - /** - * When a model is being unserialized, check if it needs to be booted. - * - * @return void - */ - public function __wakeup() - { - $this->bootIfNotBooted(); - } - - public function studly($value) - { - $value = ucwords(str_replace(['-', '_'], ' ', $value)); - return str_replace(' ', '', $value); - } +abstract class RestModel implements ArrayAccess, JsonSerializable +{ + + protected $client = null; + + protected $where = []; + + protected $updateVerb = 'put'; + + protected $return_key = null; + + /** + * The model's attributes. + * + * @var array + */ + protected $attributes = array(); + + /** + * The attributes that should be hidden for arrays. + * + * @var array + */ + protected $hidden = array(); + + /** + * The attributes that should be visible in arrays. + * + * @var array + */ + protected $visible = array(); + + /** + * The accessors to append to the model's array form. + * + * @var array + */ + protected $appends = array(); + + /** + * The attributes that should be casted to native types. + * + * @var array + */ + protected $casts = array(); + + /** + * Indicates whether attributes are snake cased on arrays. + * + * @var bool + */ + public static $snakeAttributes = true; + + /** + * The array of booted models. + * + * @var array + */ + protected static $booted = array(); + + /** + * The cache of the mutated attributes for each class. + * + * @var array + */ + protected static $mutatorCache = array(); + + /** + * Create a new model instance. + * + * @param array $attributes + * + * @return self + */ + public function __construct(Infusionsoft $client) + { + $this->client = $client; + + $this->bootIfNotBooted(); + } + + /** + * Returns the full URL for the query, optionally concatinated with additional URI elements + * + * @return string + */ + public function getFullUrl($additional = null) + { + $url = $this->full_url; + if (substr($url, -1) != '/') { + $url .= '/'; + } + + if ($additional) { + $additional = ltrim($additional, '/'); + } + + return $url . $additional; + } + + /** + * Returns the full URL for the index request, allowing for specific index endpoints + * + * @return string + */ + public function getIndexUrl() + { + $url = $this->full_url; + + return $url; + } + + /** + * Mock this model from itself. + * + * @param array $attributes + * + * @return self + */ + public function mock(array $attributes = []) + { + $this->fill($attributes); + + return $this; + } + + /** + * Creates a new object and saves it in storage/API. + * + * @param array $attributes + * + * @return self + */ + public function create(array $attributes = []) + { + $this->mock($attributes); + $this->save(); + + return $this; + } + + /** + * Save this model to storage/api. + * + * @return self + */ + public function save() + { + // well, is it a post or a put? we need to figure out if this thing exists or not + // long story short, if the "id" is set, it's an update. + if (isset($this->id)) { + $data = $this->client->restfulRequest(strtolower($this->updateVerb), $this->getFullUrl($this->id), + (array)$this->toArray()); + } else { + $data = $this->client->restfulRequest('post', $this->getFullUrl(), (array)$this->toArray()); + } + + $this->fill($data); + + return $this; + } + + public function find($id) + { + $data = $this->client->restfulRequest('get', $this->getFullUrl($id)); + $this->fill($data); + + return $this; + } + + public function sync($syncToken) + { + $this->where['sync_token'] = $syncToken; + $data = $this->client->restfulRequest('get', $this->getFullUrl()); + $this->fill($data); + + return $this; + } + + public function where($key, $value = null) + { + if (is_array($key)) { + foreach ($key as $k => $v) { + $this->where[$k] = $v; + } + + return $this; + } + + $this->where[$key] = $value; + + return $this; + } + + public function delete() + { + $response = $this->client->restfulRequest('delete', $this->getFullUrl($this->id ? $this->id : $this->key)); + + return true; + } + + public function get() + { + if ( ! empty($this->where)) { + $data = $this->client->restfulRequest('get', $this->getIndexUrl(), $this->where); + } else { + $data = $this->client->restfulRequest('get', $this->getIndexUrl()); + } + + $cursor = []; + + if (isset($data['sync_token'])) { + $cursor = $data['sync_token']; + } + + $collection = $this->collect($data, $cursor); + + return $collection; + } + + public function all() + { + $data = $this->client->restfulRequest('get', $this->getIndexUrl()); + + $cursor = []; + + if (isset($data['sync_token'])) { + $cursor = $data['sync_token']; + } + + $collection = $this->collect($data, $cursor); + + return $collection; + } + + public function collect(array $array, $cursor = []) + { + $items = []; + + $base_object = $array; + + if ( ! empty($this->return_key)) { + $base_object = $array[$this->return_key]; + } + + foreach ($base_object as $item) { + $thing = clone $this; + array_push($items, $thing->mock($item)); + } + + return new InfusionsoftCollection($items); + } + + /** + * Check if the model needs to be booted and if so, do it. + * + * @return void + */ + protected function bootIfNotBooted() + { + $class = get_class($this); + + if ( ! isset(static::$booted[$class])) { + static::$booted[$class] = true; + + static::boot(); + } + } + + /** + * The "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + if (function_exists('class_uses_recursive')) { + static::bootTraits(); + } + } + + /** + * Boot all of the bootable traits on the model. + * + * @return void + */ + protected static function bootTraits() + { + foreach (class_uses_recursive(get_called_class()) as $trait) { + if (method_exists(get_called_class(), $method = 'boot' . class_basename($trait))) { + forward_static_call([get_called_class(), $method]); + } + } + } + + /** + * Fill the model with an array of attributes. + * + * @param array $attributes + * + * @return self + */ + public function fill(array $attributes) + { + foreach ($attributes as $key => $value) { + $this->setAttribute($key, $value); + } + + return $this; + } + + /** + * Create a new instance of the given model. + * + * @param array $attributes + * @param bool $exists + * + * @return self + */ + public function newInstance($attributes = array()) + { + $model = new static((array)$attributes); + + return $model; + } + + /** + * Create a collection of models from plain arrays. + * + * @param array $items + * + * @return array + */ + public static function hydrate(array $items) + { + $instance = new static; + + $items = array_map(function ($item) use ($instance) { + return $instance->newInstance($item); + }, $items); + + return $items; + } + + /** + * Sets the HTTP verb used to update the service + * + * @return string + */ + public function setUpdateVerb($verb = 'put') + { + $this->updateVerb = $verb; + + return $this->updateVerb; + } + + /** + * Retrieves the HTTP verb used to updated the service + * + * @return string + */ + public function getUpdateVerb() + { + return $this->updateVerb; + } + + /** + * Get the hidden attributes for the model. + * + * @return array + */ + public function getHidden() + { + return $this->hidden; + } + + /** + * Set the hidden attributes for the model. + * + * @param array $hidden + * + * @return void + */ + public function setHidden(array $hidden) + { + $this->hidden = $hidden; + } + + /** + * Add hidden attributes for the model. + * + * @param array|string|null $attributes + * + * @return void + */ + public function addHidden($attributes = null) + { + $attributes = is_array($attributes) ? $attributes : func_get_args(); + + $this->hidden = array_merge($this->hidden, $attributes); + } + + /** + * Get the visible attributes for the model. + * + * @return array + */ + public function getVisible() + { + return $this->visible; + } + + /** + * Set the visible attributes for the model. + * + * @param array $visible + * + * @return void + */ + public function setVisible(array $visible) + { + $this->visible = $visible; + } + + /** + * Add visible attributes for the model. + * + * @param array|string|null $attributes + * + * @return void + */ + public function addVisible($attributes = null) + { + $attributes = is_array($attributes) ? $attributes : func_get_args(); + + $this->visible = array_merge($this->visible, $attributes); + } + + /** + * Set the accessors to append to model arrays. + * + * @param array $appends + * + * @return void + */ + public function setAppends(array $appends) + { + $this->appends = $appends; + } + + /** + * Convert the model instance to JSON. + * + * @param int $options + * + * @return string + */ + public function toJson($options = 0) + { + return json_encode($this->toArray(), $options); + } + + /** + * Convert the object into something JSON serializable. + * + * @return array + */ + public function jsonSerialize() + { + return $this->toArray(); + } + + /** + * Convert the model instance to an array. + * + * @return array + */ + public function toArray() + { + return $this->attributesToArray(); + } + + /** + * Convert the model's attributes to an array. + * + * @return array + */ + public function attributesToArray() + { + $attributes = $this->getArrayableAttributes(); + + $mutatedAttributes = $this->getMutatedAttributes(); + + // We want to spin through all the mutated attributes for this model and call + // the mutator for the attribute. We cache off every mutated attributes so + // we don't have to constantly check on attributes that actually change. + foreach ($mutatedAttributes as $key) { + if ( ! array_key_exists($key, $attributes)) { + continue; + } + + $attributes[$key] = $this->mutateAttributeForArray($key, $attributes[$key]); + } + + // Next we will handle any casts that have been setup for this model and cast + // the values to their appropriate type. If the attribute has a mutator we + // will not perform the cast on those attributes to avoid any confusion. + foreach ($this->casts as $key => $value) { + if ( ! array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) { + continue; + } + + $attributes[$key] = $this->castAttribute($key, $attributes[$key]); + } + + // Here we will grab all of the appended, calculated attributes to this model + // as these attributes are not really in the attributes array, but are run + // when we need to array or JSON the model for convenience to the coder. + foreach ($this->getArrayableAppends() as $key) { + $attributes[$key] = $this->mutateAttributeForArray($key, null); + } + + return $attributes; + } + + /** + * Get an attribute array of all arrayable attributes. + * + * @return array + */ + protected function getArrayableAttributes() + { + return $this->getArrayableItems($this->attributes); + } + + /** + * Get all of the appendable values that are arrayable. + * + * @return array + */ + protected function getArrayableAppends() + { + if ( ! count($this->appends)) { + return []; + } + + return $this->getArrayableItems(array_combine($this->appends, $this->appends)); + } + + /** + * Get an attribute array of all arrayable values. + * + * @param array $values + * + * @return array + */ + protected function getArrayableItems(array $values) + { + if (count($this->visible) > 0) { + return array_intersect_key($values, array_flip($this->visible)); + } + + return array_diff_key($values, array_flip($this->hidden)); + } + + /** + * Get an attribute from the model. + * + * @param string $key + * + * @return mixed + */ + public function getAttribute($key) + { + $inAttributes = array_key_exists($key, $this->attributes); + + // If the key references an attribute, we can just go ahead and return the + // plain attribute value from the model. This allows every attribute to + // be dynamically accessed through the _get method without accessors. + if ($inAttributes or $this->hasGetMutator($key)) { + return $this->getAttributeValue($key); + } + } + + /** + * Get a plain attribute (not a relationship). + * + * @param string $key + * + * @return mixed + */ + protected function getAttributeValue($key) + { + $value = $this->getAttributeFromArray($key); + + // If the attribute has a get mutator, we will call that then return what + // it returns as the value, which is useful for transforming values on + // retrieval from the model to a form that is more useful for usage. + if ($this->hasGetMutator($key)) { + return $this->mutateAttribute($key, $value); + } + + // If the attribute exists within the cast array, we will convert it to + // an appropriate native PHP type dependant upon the associated value + // given with the key in the pair. Dayle made this comment line up. + if ($this->hasCast($key)) { + $value = $this->castAttribute($key, $value); + } + + return $value; + } + + /** + * Get an attribute from the $attributes array. + * + * @param string $key + * + * @return mixed + */ + protected function getAttributeFromArray($key) + { + if (array_key_exists($key, $this->attributes)) { + return $this->attributes[$key]; + } + } + + /** + * Determine if a get mutator exists for an attribute. + * + * @param string $key + * + * @return bool + */ + public function hasGetMutator($key) + { + return method_exists($this, 'get' . $this->studly($key) . 'Attribute'); + } + + /** + * Get the value of an attribute using its mutator. + * + * @param string $key + * @param mixed $value + * + * @return mixed + */ + protected function mutateAttribute($key, $value) + { + return $this->{'get' . $this->studly($key) . 'Attribute'}($value); + } + + /** + * Get the value of an attribute using its mutator for array conversion. + * + * @param string $key + * @param mixed $value + * + * @return mixed + */ + protected function mutateAttributeForArray($key, $value) + { + $value = $this->mutateAttribute($key, $value); + + return $value instanceof ArrayableInterface ? $value->toArray() : $value; + } + + /** + * Determine whether an attribute should be casted to a native type. + * + * @param string $key + * + * @return bool + */ + protected function hasCast($key) + { + return array_key_exists($key, $this->casts); + } + + /** + * Determine whether a value is JSON castable for inbound manipulation. + * + * @param string $key + * + * @return bool + */ + protected function isJsonCastable($key) + { + if ($this->hasCast($key)) { + return in_array($this->getCastType($key), ['array', 'json', 'object'], true); + } + + return false; + } + + /** + * Get the type of cast for a model attribute. + * + * @param string $key + * + * @return string + */ + protected function getCastType($key) + { + return trim(strtolower($this->casts[$key])); + } + + /** + * Cast an attribute to a native PHP type. + * + * @param string $key + * @param mixed $value + * + * @return mixed + */ + protected function castAttribute($key, $value) + { + if (is_null($value)) { + return $value; + } + + switch ($this->getCastType($key)) { + case 'int': + case 'integer': + return (int)$value; + case 'real': + case 'float': + case 'double': + return (float)$value; + case 'string': + return (string)$value; + case 'bool': + case 'boolean': + return (bool)$value; + case 'object': + return json_decode($value); + case 'array': + case 'json': + return json_decode($value, true); + default: + return $value; + } + } + + /** + * Set a given attribute on the model. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + public function setAttribute($key, $value) + { + // First we will check for the presence of a mutator for the set operation + // which simply lets the developers tweak the attribute as it is set on + // the model, such as "json_encoding" an listing of data for storage. + if ($this->hasSetMutator($key)) { + $method = 'set' . $this->studly($key) . 'Attribute'; + + return $this->{$method}($value); + } + + if ($this->isJsonCastable($key)) { + $value = json_encode($value); + } + + $this->attributes[$key] = $value; + } + + /** + * Determine if a set mutator exists for an attribute. + * + * @param string $key + * + * @return bool + */ + public function hasSetMutator($key) + { + return method_exists($this, 'set' . $this->studly($key) . 'Attribute'); + } + + /** + * Clone the model into a new, non-existing instance. + * + * @return self + */ + public function replicate() + { + with($instance = new static)->fill($this->attributes); + + return $instance; + } + + /** + * Get all of the current attributes on the model. + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Get the mutated attributes for a given instance. + * + * @return array + */ + public function getMutatedAttributes() + { + $class = get_class($this); + + if ( ! isset(static::$mutatorCache[$class])) { + static::cacheMutatedAttributes($class); + } + + return static::$mutatorCache[$class]; + } + + /** + * Extract and cache all the mutated attributes of a class. + * + * @param string $class + * + * @return void + */ + public static function cacheMutatedAttributes($class) + { + $mutatedAttributes = array(); + + // Here we will extract all of the mutated attributes so that we can quickly + // spin through them after we export models to their array form, which we + // need to be fast. This'll let us know the attributes that can mutate. + foreach (get_class_methods($class) as $method) { + if (strpos($method, 'Attribute') !== false && preg_match('/^get(.+)Attribute$/', $method, $matches)) { + if (static::$snakeAttributes) { + $matches[1] = snake_case($matches[1]); + } + + $mutatedAttributes[] = lcfirst($matches[1]); + } + } + + static::$mutatorCache[$class] = $mutatedAttributes; + } + + /** + * Dynamically retrieve attributes on the model. + * + * @param string $key + * + * @return mixed + */ + public function __get($key) + { + return $this->getAttribute($key); + } + + /** + * Dynamically set attributes on the model. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + public function __set($key, $value) + { + $this->setAttribute($key, $value); + } + + /** + * Determine if the given attribute exists. + * + * @param mixed $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->$offset); + } + + /** + * Get the value for a given offset. + * + * @param mixed $offset + * + * @return mixed + */ + public function offsetGet($offset) + { + return $this->$offset; + } + + /** + * Set the value for a given offset. + * + * @param mixed $offset + * @param mixed $value + * + * @return void + */ + public function offsetSet($offset, $value) + { + $this->$offset = $value; + } + + /** + * Unset the value for a given offset. + * + * @param mixed $offset + * + * @return void + */ + public function offsetUnset($offset) + { + unset($this->$offset); + } + + /** + * Determine if an attribute exists on the model. + * + * @param string $key + * + * @return void + */ + public function __isset($key) + { + return ((isset($this->attributes[$key]) || isset($this->relations[$key])) || ($this->hasGetMutator($key) && ! is_null($this->getAttributeValue($key)))); + } + + /** + * Unset an attribute on the model. + * + * @param string $key + * + * @return void + */ + public function __unset($key) + { + unset($this->attributes[$key]); + } + + /** + * Handle dynamic static method calls into the method. + * + * @param string $method + * @param array $parameters + * + * @return mixed + */ + public static function __callStatic($method, $parameters) + { + $instance = new static; + + return call_user_func_array(array($instance, $method), $parameters); + } + + /** + * Convert the model to its string representation. + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } + + /** + * When a model is being unserialized, check if it needs to be booted. + * + * @return void + */ + public function __wakeup() + { + $this->bootIfNotBooted(); + } + + public function studly($value) + { + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + + return str_replace(' ', '', $value); + } } \ No newline at end of file diff --git a/src/Infusionsoft/Api/Rest/ResthookService.php b/src/Infusionsoft/Api/Rest/ResthookService.php new file mode 100644 index 0000000..ca64045 --- /dev/null +++ b/src/Infusionsoft/Api/Rest/ResthookService.php @@ -0,0 +1,55 @@ +setUpdateVerb('put'); + parent::__construct($client); + } + + public function events(){ + $data = $this->client->restfulRequest('get', $this->getFullUrl('event_keys')); + $this->fill($data); + + return $this; + } + + public function verify() + { + $data = $this->client->restfulRequest('post', $this->getFullUrl($this->key.'/verify')); + $this->fill($data); + + return $this; + } + + public function autoverify($return_header = true) + { + $headers = array(); + foreach($_SERVER as $key => $value) { + if (substr($key, 0, 5) <> 'HTTP_') + { + continue; + } + $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5))))); + $headers[$header] = $value; + } + + if(isset($headers['X-Hook-Secret'])) { + if($return_header) + { + header('X-Hook-Secret: '.$headers['X-Hook-Secret']); + } + else + { + return $headers['X-Hook-Secret']; + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/Infusionsoft/Infusionsoft.php b/src/Infusionsoft/Infusionsoft.php index 1faf77f..8bb84f5 100644 --- a/src/Infusionsoft/Infusionsoft.php +++ b/src/Infusionsoft/Infusionsoft.php @@ -588,6 +588,14 @@ public function products($api = 'rest') return $this->getRestApi('ProductService'); } + /** + * @return \Infusionsoft\Api\Rest\ResthookService + */ + public function resthooks() + { + return $this->getRestApi('ResthookService'); + } + /** * @return \Infusionsoft\Api\SearchService */