Skip to content

Properties & Model Features

Property Definitions

HubSpot properties have type definitions that control serialization and deserialization of values (e.g. dates become Carbon instances, enumerations become arrays).

Loading Definitions

php
use Rollogi\LaravelHubspot\Crm\Contact;

// Get all property definitions for a model
$definitions = Contact::query()->definitions()->get();

// Get a single property definition
$emailDefinition = Contact::query()->definitions()->get('email');

// Access via model instance
$contact = Contact::findOrFail('123');
$definitions = $contact->definitions;

Caching

Property definitions are cached for the duration configured in hubspot.definitions.cache (default: 30 days). You can force a refresh:

php
use Rollogi\LaravelHubspot\Crm\Contact;

Contact::query()->definitions()->refresh();

Set definitions.cache to false in the config to disable caching entirely.

Creating Custom Properties

php
use Rollogi\LaravelHubspot\Crm\Contact;

$property = Contact::query()->definitions()->create([
    'name' => 'custom_score',
    'label' => 'Custom Score',
    'type' => 'number',
    'fieldType' => 'number',
    'groupName' => 'contactinformation',
]);

Value Serialization

Property values are automatically serialized/deserialized based on their definition type:

Property TypePHP TypeBehavior
dateCarbon\CarbonParsed to/from ISO 8601
datetimeCarbon\CarbonParsed to/from Y-m-d
numberint|floatCast to numeric
enumerationarraySplit/joined by ;

Model Features

Magic Property Access

Models support dynamic property access through __get and __set:

php
use Rollogi\LaravelHubspot\Crm\Contact;

$contact = Contact::findOrFail('123');

// Read properties
echo $contact->firstname;
echo $contact->email;
echo $contact->id;            // From payload
echo $contact->createdAt;     // Cast to Carbon

// Write properties
$contact->firstname = 'Jane';
$contact->save();

Dirty Tracking

Only changed properties are sent when calling save():

php
use Rollogi\LaravelHubspot\Crm\Contact;

$contact = Contact::findOrFail('123');
$contact->firstname = 'Updated';

$contact->getDirty(); // ['firstname' => 'Updated']
$contact->save();     // Only sends firstname

Payload Casting

The model $schema defines automatic type casting for payload-level fields:

FieldCast Type
idint
createdAtdatetime (Carbon)
updatedAtdatetime (Carbon)
archivedbool
archivedAtdatetime (Carbon)
propertiesarray
associationsarray

Scopes

Define reusable query constraints as scope methods on your models:

php
use Rollogi\LaravelHubspot\Api\Builder;
use Rollogi\LaravelHubspot\Crm\Contact;

// In a custom model extending Contact
public function scopeActive(Builder $builder): Builder
{
    return $builder->where('lifecyclestage', 'customer');
}

// Usage
$customers = Contact::query()->active()->get();

Macros

Models use the Macroable trait, allowing you to add methods at runtime:

php
use Rollogi\LaravelHubspot\Crm\Contact;

Contact::macro('findByEmail', function (string $email): ?Contact {
    return Contact::query()->where('email', $email)->first();
});

$contact = Contact::findByEmail('john@example.com');

Expand

Re-fetch a model with all properties:

php
use Rollogi\LaravelHubspot\Crm\Contact;

$contact = Contact::find('123');
$contact->expand(); // Re-fetches with full() properties