connectors

object

%Connector

/phlo/resources/connectors/Connector.phlo
version 1.0
creator q-ai.nl
summary Base class for API connectors: credentials, JSON requests, retries, pagination and a normalized result contract
package connectors
frontend false
backend true
requires creds HTTP
tags api connector http rest base
const

Connector :: section

line 10
在 Connector 中定义一个部分,允许组织相关的组件和功能。
void
const

Connector :: api

line 11
定义一个用于API交互的连接器,允许不同服务之间无缝通信。
void
method

%Connector -> __construct (?array $config = null)

line 13
使用可选的配置设置初始化Connector实例。如果未提供配置,它将尝试从预定义的部分加载凭据。
if ($config === null){
	$section = static::section
	$creds = $section ? %creds->{$section} : null
	$config = $creds ? (array)$creds->toArray : []
}
$this->config = $config
$this->timeout = 15
$this->retries = 0
static

Connector :: make (?array $config = null):static

line 24
使用提供的配置创建 Connector 类的新实例。
new static($config)
method

%Connector -> base

line 26
访问Connector的基础API,允许与其核心功能进行交互。
static::api
method

%Connector -> headers

line 27
此属性检索与 Connector 相关的头部信息。
[]
static

Connector :: fields

line 29
Connector::$fields 是一个静态属性,包含 Connector 类的字段定义数组。
[]
method

%Connector -> configured (...$keys):bool

line 31
检查连接器的配置中是否配置了所有指定的键。如果所有键都存在,则返回true,否则返回false。
foreach ($keys AS $key){
	if (($this->config[$key] ?? void) === void) return false
}
return true
method

%Connector -> missing (...$keys):?obj

line 38
检查指定的凭据是否已配置,如果已配置则返回null;否则,触发一个失败,指明缺少哪些凭据。
return $this->configured(...$keys) ? null : static::fail(static::section.' credentials not configured ('.implode(', ', $keys).')')
static

Connector :: bearer ($token):string

line 42
Connector::$bearer 属性保存格式化的包含 Bearer 令牌的授权头值,用于 API 请求。
'Authorization: Bearer '.$token
static

Connector :: basic ($user, $pass):string

line 43
通过将提供的用户名和密码编码为base64格式来生成Basic Authorization头。
'Authorization: Basic '.base64_encode($user.colon.$pass)
static

Connector :: build (string $method, string $url, ?array $query = null, array $headers = [], mixed $json = null, mixed $form = null):array

line 45
根据提供的参数构建HTTP请求配置,包括方法、URL、头部和主体。
if ($query) $url .= (str_contains($url, qm) ? '&' : qm).http_build_query($query)
$body = null
if ($json !== null){
	$body = is_string($json) ? $json : json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
	$headers[] = 'Content-Type: application/json'
}
elseif ($form !== null){
	$body = is_string($form) ? $form : http_build_query($form)
	$headers[] = 'Content-Type: application/x-www-form-urlencoded'
}
$headers[] = 'Accept: application/json'
return ['method' => strtoupper($method), 'url' => $url, 'headers' => $headers, 'body' => $body]
static

Connector :: ok ($data, int $status = 200):obj

line 60
Connector::$ok 属性包含一个对象,该对象具有布尔 'ok' 值、'status' 和 'data' 属性。
obj(ok: true, status: $status, data: $data)
static

Connector :: fail ($error, int $status = 0):obj

line 61
Connector::$fail 属性表示失败状态,包含一个对象,其中 'ok' 设置为 false,并包含 'status' 和 'error' 详细信息。
obj(ok: false, status: $status, error: $error)
static

Connector :: errorMessage ($data, string $raw, int $status):string

line 63
Connector::$errorMessage 从给定的数据对象中检索错误消息,检查各种属性以获取错误的字符串表示,如果未找到错误,则默认为格式化的 HTTP 状态消息。
if (is_object($data)){
	if (isset($data->error->message)) return (string)$data->error->message
	if (isset($data->error) && is_string($data->error)) return $data->error
	if (isset($data->message)) return (string)$data->message
	if (isset($data->errors)){
		$errors = $data->errors
		if (is_string($errors)) return $errors
		if (is_array($errors)) return is_string($errors[0] ?? null) ? $errors[0] : json_encode($errors)
		if (is_object($errors)) return json_encode($errors)
	}
}
return $raw !== void ? $raw : 'HTTP '.$status
static

Connector :: parse ($raw, int $status = 200):obj

line 78
将原始输入字符串解析为JSON对象,根据HTTP状态码返回成功响应或错误消息。
$raw = (string)$raw
$data = $raw === void ? null : json_decode($raw)
if ($status < 200 || $status >= 300) return static::fail(static::errorMessage($data, $raw, $status), $status)
return obj(ok: true, status: $status, data: $data ?? $raw)
static

Connector :: retryable ($method, int $status):bool

line 85
in_array($method, ['GET', 'HEAD', 'QUERY']) && ($status === 429 || $status >= 500)
static

Connector :: backoff (int $attempt, $response):int

line 87
Connector::$backoff 属性根据响应中的 'retry-after' 头计算以微秒为单位的退避时间,最大限制为 30 秒或默认值乘以尝试次数。
$after = (int)($response->headers['retry-after'] ?? 0)
return $after > 0 ? min($after, 30) * 1000000 : 200000 * $attempt
method

%Connector -> dispatch (array $req):obj

line 92
$method = $req['method']
$body = $req['body']
$attempt = 0
$response = null
while (true){
	try {
		if ($method === 'GET') $raw = HTTP($req['url'], $req['headers'], cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'DELETE') $raw = HTTP($req['url'], $req['headers'], DELETE: true, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'PUT') $raw = HTTP($req['url'], $req['headers'], PUT: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'PATCH') $raw = HTTP($req['url'], $req['headers'], PATCH: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		elseif ($method === 'QUERY') $raw = HTTP($req['url'], $req['headers'], QUERY: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
		else $raw = HTTP($req['url'], $req['headers'], POST: $body ?? void, cookies: false, timeout: $this->timeout, response: $response)
	}
	catch (\Throwable $e){
		return static::fail($e->getMessage(), 0)
	}
	$status = $response->status ?? 0
	if (($status >= 200 && $status < 300) || !static::retryable($method, $status) || $attempt >= $this->retries) break
	usleep(static::backoff(++$attempt, $response))
}
$result = static::parse($raw, $status)
$result->headers = $response->headers ?? []
return $result
method

%Connector -> request (string $method, string $url, ?array $query = null, array $headers = [], mixed $json = null, mixed $form = null):obj

line 118
使用指定的方法、URL、查询参数、头部以及可选的JSON或表单数据发送HTTP请求。
if (!str_starts_with($url, 'http')) $url = rtrim((string)$this->base, slash).slash.ltrim($url, slash)
$headers = array_merge((array)$this->headers, $headers)
return $this->dispatch(static::build($method, $url, $query, $headers, $json, $form))
method

%Connector -> get (string $url, ?array $query = null, array $headers = []):obj

line 124
向指定的URL发送GET请求,带有可选的查询参数和头部信息。
$this->request('GET', $url, query: $query, headers: $headers)
method

%Connector -> post (string $url, mixed $json = null, array $headers = []):obj

line 125
向指定的URL发送带有可选JSON数据和头部的POST请求。
$this->request('POST', $url, headers: $headers, json: $json)
method

%Connector -> put (string $url, mixed $json = null, array $headers = []):obj

line 126
向指定的URL发送PUT请求,附带可选的JSON数据和头部信息。
$this->request('PUT', $url, headers: $headers, json: $json)
method

%Connector -> patch (string $url, mixed $json = null, array $headers = []):obj

line 127
向指定的URL发送PATCH请求,带有可选的JSON数据和头部信息。
$this->request('PATCH', $url, headers: $headers, json: $json)
method

%Connector -> query (string $url, mixed $json = null, array $headers = []):obj

line 128
$this->request('QUERY', $url, headers: $headers, json: $json)
method

%Connector -> del (string $url, array $headers = []):obj

line 129
向指定的URL发送DELETE请求,并可选地附加头部信息。
$this->request('DELETE', $url, headers: $headers)
method

%Connector -> form (string $url, array $fields, array $headers = []):obj

line 130
向指定的URL发送带有给定表单字段和头部的POST请求。
$this->request('POST', $url, headers: $headers, form: $fields)
method

%Connector -> paginate (string $url, callable $extract, ?array $query = null, string $param = 'page', int $start = 1, int $max = 0):array

line 132
从指定的URL获取分页数据,使用提供的可调用函数提取项目,并在达到最大数量或没有更多数据可用时进行累积。
$items = []
$page = $start
while (true){
	$res = $this->get($url, ($query ?? []) + [$param => $page])
	if (!$res->ok) break
	$batch = $extract($res->data)
	if (!$batch) break
	foreach ($batch AS $item) $items[] = $item
	if ($max && count($items) >= $max) break
	$page++
}
return $items
object

%EBoekhouden

/phlo/resources/connectors/finance/EBoekhouden.phlo
version 1.0
creator q-ai.nl
summary e-Boekhouden.nl connector: session auth from an API token, relations and sales invoices
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:EBoekhouden
tags eboekhouden accounting invoices relations connector
const

EBoekhouden :: section

line 11
'EBoekhouden'
const

EBoekhouden :: api

line 12
'https://api.e-boekhouden.nl/v1'
prop

%EBoekhouden -> sessionToken

line 14
void
method

%EBoekhouden -> headers

line 16
$this->sessionToken !== void ? ['Authorization: '.$this->sessionToken] : []
static

EBoekhouden :: fields

line 18
arr(
	section: 'EBoekhouden',
	config: arr(source: 'Source label shown in the e-Boekhouden audit trail (optional)'),
	secret: arr(api_token: 'API token (Beheer > Instellingen > API)'),
)
method

%EBoekhouden -> session:obj

line 25
if ($m = $this->missing('api_token')) return $m
if ($this->sessionToken !== void) return static::ok($this->sessionToken)
$res = $this->post('session', ['accessToken' => trim((string)$this->config['api_token']), 'source' => (string)($this->config['source'] ?? 'Phlo')])
if (!$res->ok) return $res
$token = (string)($res->data->token ?? void)
if ($token === void) return static::fail('e-Boekhouden session token missing in response', $res->status)
$this->sessionToken = $token
return static::ok($token)
method

%EBoekhouden -> guard:?obj

line 36
$res = $this->session
return $res->ok ? null : $res
method

%EBoekhouden -> relations (array $query = []):obj

line 41
if ($m = $this->guard) return $m
return $this->get('relation', $query)
method

%EBoekhouden -> createRelation (array $relation):obj

line 46
if ($m = $this->guard) return $m
return $this->post('relation', $relation)
method

%EBoekhouden -> invoices (array $query = []):obj

line 51
if ($m = $this->guard) return $m
return $this->get('invoice', $query)
method

%EBoekhouden -> createInvoice (array $invoice):obj

line 56
if ($m = $this->guard) return $m
return $this->post('invoice', $invoice)
object

%ExactOnline

/phlo/resources/connectors/finance/ExactOnline.phlo
version 1.0
creator q-ai.nl
summary Exact Online connector (OAuth2): read sales invoices and accounts, create sales invoices
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:ExactOnline
tags exact exactonline accounting invoices oauth connector
const

ExactOnline :: section

line 11
在ExactOnline资源中定义一个部分,以便进行结构化数据管理。
'ExactOnline'
const

ExactOnline :: tokenUrl

line 12
返回用于从ExactOnline获取OAuth2令牌的URL。
'https://start.exactonline.nl/api/oauth2/token'
method

%ExactOnline -> base

line 14
使用配置中的指定部门构建ExactOnline API的基本URL。
'https://start.exactonline.nl/api/v1/'.($this->config['division'] ?? void)
static

ExactOnline :: fields

line 16
定义与ExactOnline集成所需的字段,包括OAuth凭据和范围的配置。
arr(
	section: 'ExactOnline',
	config: arr(division: 'Division (administration) number'),
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (managed and rotated after first authorization)',
	),
	scopes: 'OAuth2 authorization code flow; token endpoint refreshes automatically',
)
method

%ExactOnline -> guard

line 27
检查必需参数 'division'、'client_id'、'client_secret' 和 'refresh_token' 的存在。
$this->missing('division', 'client_id', 'client_secret', 'refresh_token')
method

%ExactOnline -> invoices (array $query = []):obj

line 29
根据提供的查询参数从ExactOnline获取销售发票列表。
if ($m = $this->guard) return $m
return $this->get('salesinvoice/SalesInvoices', $query)
method

%ExactOnline -> accounts (array $query = []):obj

line 34
使用指定的查询参数从ExactOnline检索账户信息。
if ($m = $this->guard) return $m
return $this->get('crm/Accounts', $query)
method

%ExactOnline -> createInvoice (array $invoice):obj

line 39
使用提供的发票数据在ExactOnline中创建新发票。
if ($m = $this->guard) return $m
return $this->post('salesinvoice/SalesInvoices', $invoice)
object

%GoogleCalendar

/phlo/resources/connectors/cloud/GoogleCalendar.phlo
version 1.0
creator q-ai.nl
summary Google Calendar connector (OAuth2): read events and create events
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:Google
tags google calendar events oauth connector
const

GoogleCalendar :: section

line 11
在Google日历资源中定义一个部分,以便组织事件和细节。
'Google'
const

GoogleCalendar :: tokenUrl

line 12
这是用于从Google Calendar的OAuth 2.0授权服务器获取访问令牌的URL端点。
'https://oauth2.googleapis.com/token'
method

%GoogleCalendar -> base

line 14
这定义了访问 Google Calendar API 版本 3 的基础 URL。
'https://www.googleapis.com/calendar/v3'
static

GoogleCalendar :: fields

line 16
GoogleCalendar::$fields 提供访问 Google Calendar 的配置详细信息,包括 OAuth 凭据和所需的范围。
arr(
	section: 'Google',
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (scopes: calendar, spreadsheets)',
	),
	scopes: 'https://www.googleapis.com/auth/calendar, https://www.googleapis.com/auth/spreadsheets',
)
method

%GoogleCalendar -> guard

line 26
检查必需凭据的存在:client_id、client_secret 和 refresh_token。
$this->missing('client_id', 'client_secret', 'refresh_token')
method

%GoogleCalendar -> events (string $calendarId = 'primary', array $query = []):obj

line 28
使用提供的日历ID和可选查询参数从指定的Google日历中检索事件。
if ($m = $this->guard) return $m
return $this->get('calendars/'.rawurlencode($calendarId).'/events', $query)
method

%GoogleCalendar -> createEvent (array $event, string $calendarId = 'primary'):obj

line 33
使用提供的事件详细信息在指定的 Google 日历中创建新事件。
if ($m = $this->guard) return $m
return $this->post('calendars/'.rawurlencode($calendarId).'/events', $event)
object

%GoogleSheets

/phlo/resources/connectors/cloud/GoogleSheets.phlo
version 1.0
creator q-ai.nl
summary Google Sheets connector (OAuth2): read ranges and append rows
extends OAuthConnector
package connectors
frontend false
backend true
requires @OAuthConnector creds:Google
tags google sheets spreadsheet oauth connector
const

GoogleSheets :: section

line 11
定义一个用于在 Google Sheets 资源中组织数据的部分。
'Google'
const

GoogleSheets :: tokenUrl

line 12
这是从 Google Sheets 获取 OAuth 2.0 令牌的 URL 端点。
'https://oauth2.googleapis.com/token'
method

%GoogleSheets -> base

line 14
此项表示访问 Google Sheets API 的基本 URL,特别是与电子表格交互的端点。
'https://sheets.googleapis.com/v4/spreadsheets'
static

GoogleSheets :: fields

line 16
定义Google Sheets集成的配置字段,包括OAuth凭据和所需的范围。
arr(
	section: 'Google',
	secret: arr(
		client_id: 'OAuth client ID',
		client_secret: 'OAuth client secret',
		refresh_token: 'OAuth refresh token (scopes: calendar, spreadsheets)',
	),
	scopes: 'https://www.googleapis.com/auth/spreadsheets',
)
method

%GoogleSheets -> guard

line 26
检查必需凭据的存在:client_id、client_secret 和 refresh_token。
$this->missing('client_id', 'client_secret', 'refresh_token')
method

%GoogleSheets -> values ($spreadsheetId, string $range):obj

line 28
从指定的 Google Sheets 电子表格中检索给定电子表格 ID 的范围内的值。
if ($m = $this->guard) return $m
return $this->get($spreadsheetId.'/values/'.rawurlencode($range))
method

%GoogleSheets -> append ($spreadsheetId, string $range, array $rows, string $valueInputOption = 'USER_ENTERED'):obj

line 33
将数据行附加到指定的 Google Sheets 电子表格范围,使用提供的值输入选项。
if ($m = $this->guard) return $m
return $this->post($spreadsheetId.'/values/'.rawurlencode($range).':append?valueInputOption='.$valueInputOption, ['values' => $rows])
object

%Lightspeed

/phlo/resources/connectors/shops/Lightspeed.phlo
version 1.0
creator q-ai.nl
summary Lightspeed Retail (V3) connector: read customers and sales, create customers
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Lightspeed
tags lightspeed webshop retail pos customers connector
const

Lightspeed :: section

line 11
在Lightspeed应用程序中定义一个部分,允许在该部分内组织和管理内容。
'Lightspeed'
method

%Lightspeed -> base

line 13
Lightspeed->base 构建访问 Lightspeed API 的基础 URL,如果可用,则包含配置中的集群 ID。
'https://api.lightspeedapp.com/API/V3/Account/'.($this->config['cluster_id'] ?? void)
method

%Lightspeed -> headers

line 15
此方法使用配置中提供的API密钥和密钥检索Lightspeed API身份验证所需的头部。
[static::basic($this->config['api_key'] ?? void, $this->config['api_secret'] ?? void)]
static

Lightspeed :: fields

line 17
Lightspeed::$fields 定义了连接到 Lightspeed API 所需的配置字段,包括集群 ID、语言、API 密钥、API 秘密和访问范围。
arr(
	section: 'Lightspeed',
	config: arr(
		cluster_id: 'Account / cluster ID',
		language: 'Language (optional, default nl)',
	),
	secret: arr(
		api_key: 'API key',
		api_secret: 'API secret',
	),
	scopes: 'Customer read/write, Sale read',
)
method

%Lightspeed -> customers (array $query = []):obj

line 30
使用提供的查询参数从Lightspeed API检索客户数据。
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Customer.json', $query)
method

%Lightspeed -> findCustomer ($participant):obj

line 35
根据提供的参与者标识符的格式,通过电子邮件或电话号码查找客户。
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
$field = str_contains((string)$participant, '@') ? 'Email' : 'Phone'
return $this->get('Customer.json', [$field => $participant, 'limit' => 1])
method

%Lightspeed -> customer ($id):obj

line 41
使用指定的客户ID从Lightspeed API检索客户信息。
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Customer/'.$id.'.json')
method

%Lightspeed -> sales (array $query = []):obj

line 46
使用提供的查询参数从API获取销售数据,确保所需的凭据存在。
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->get('Sale.json', $query)
method

%Lightspeed -> createCustomer (array $customer):obj

line 51
通过将提供的客户数据发送到Lightspeed API来创建新客户,确保所需参数存在。
if ($m = $this->missing('cluster_id', 'api_key', 'api_secret')) return $m
return $this->post('Customer.json', $customer)
object

%MessageBird

/phlo/resources/connectors/chat/MessageBird.phlo
version 1.0
creator q-ai.nl
summary MessageBird connector: send SMS
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:MessageBird
tags messagebird sms messaging connector
const

MessageBird :: section

line 11
在Phlo应用程序中定义MessageBird的一个部分。
'MessageBird'
method

%MessageBird -> base

line 13
这定义了MessageBird API的基础URL,用于发送和接收消息。
'https://rest.messagebird.com'
method

%MessageBird -> headers

line 15
这获取了使用提供的访问密钥对MessageBird API请求进行身份验证所需的头部信息。
['Authorization: AccessKey '.($this->config['access_key'] ?? void)]
static

MessageBird :: fields

line 17
定义了MessageBird配置的字段,包括发件人和访问密钥。
arr(
	section: 'MessageBird',
	config: arr(originator: 'Originator (sender number or name)'),
	secret: arr(access_key: 'Access key'),
)
static

MessageBird :: errorMessage ($data, string $raw, int $status):string

line 23
从MessageBird API响应中检索错误消息(如果可用);否则,回退到父类的错误消息方法。
if (is_object($data) && isset($data->errors[0]->description)) return (string)$data->errors[0]->description
return parent::errorMessage($data, $raw, $status)
method

%MessageBird -> sms ($to, $body, array $extra = []):obj

line 28
使用MessageBird API向指定的接收者发送SMS消息,需提供访问密钥和发件人配置。
if ($m = $this->missing('access_key', 'originator')) return $m
$recipients = is_array($to) ? $to : [$to]
return $this->post('messages', ['originator' => $this->config['originator'], 'recipients' => $recipients, 'body' => $body] + $extra)
object

%MicrosoftGraph

/phlo/resources/connectors/cloud/MicrosoftGraph.phlo
version 1.0
creator q-ai.nl
summary Microsoft Graph connector (app-only client credentials): read users and calendars, send mail, create events
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Microsoft
tags microsoft graph office365 calendar mail connector
const

MicrosoftGraph :: section

line 11
此功能与 Microsoft Graph API 交互,以管理资源中的部分。
'Microsoft'
method

%MicrosoftGraph -> base

line 13
这定义了访问 Microsoft Graph API 的基本 URL,允许与 Microsoft 服务和资源进行交互。
'https://graph.microsoft.com/v1.0'
method

%MicrosoftGraph -> headers

line 15
此项使用承载令牌检索与 Microsoft Graph 进行身份验证所需的头部信息。
[static::bearer((string)$this->token)]
static

MicrosoftGraph :: fields

line 17
定义连接到 Microsoft Graph 所需的配置字段,包括租户 ID、客户端 ID、邮箱、客户端密钥和应用程序权限。
arr(
	section: 'Microsoft',
	config: arr(
		tenant_id: 'Azure AD tenant ID',
		client_id: 'App registration client ID',
		mailbox: 'Default mailbox / user UPN for calendar and mail (optional)',
	),
	secret: arr(client_secret: 'App registration client secret'),
	scopes: 'Application permissions: User.Read.All, Calendars.ReadWrite, Mail.Send',
)
prop

%MicrosoftGraph -> token

line 28
使用fetchToken方法从Microsoft Graph获取访问令牌。
$this->fetchToken()
method

%MicrosoftGraph -> fetchToken

line 30
使用客户端凭据从 Microsoft Graph 获取 OAuth2 令牌,如果 APCu 可用,则缓存该令牌以供将来使用。
$tenant = $this->config['tenant_id'] ?? void
$id = $this->config['client_id'] ?? void
$secret = $this->config['client_secret'] ?? void
if ($tenant === void || $id === void || $secret === void) return void
$key = 'phlo:graph:'.$tenant.colon.$id
if (function_exists('apcu_fetch')){
	$cached = apcu_fetch($key)
	if ($cached) return $cached
}
$res = $this->dispatch(static::build('POST', 'https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/token', null, [], null, ['grant_type' => 'client_credentials', 'client_id' => $id, 'client_secret' => $secret, 'scope' => 'https://graph.microsoft.com/.default']))
if (!$res->ok) return void
$token = $res->data->access_token ?? void
$expires = (int)($res->data->expires_in ?? 3600)
if ($token !== void && function_exists('apcu_store')) apcu_store($key, $token, max(60, $expires - 60))
return $token
method

%MicrosoftGraph -> mailbox ($user = null)

line 48
检索与指定用户关联的邮箱,如果未提供用户,则默认为配置的邮箱。
$user ?? ($this->config['mailbox'] ?? void)
method

%MicrosoftGraph -> users (array $query = []):obj

line 50
根据提供的查询参数从 Microsoft Graph 检索用户列表。
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
return $this->get('users', $query)
method

%MicrosoftGraph -> user ($id):obj

line 55
使用指定的用户ID从Microsoft Graph获取用户信息。
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
return $this->get('users/'.rawurlencode((string)$id))
method

%MicrosoftGraph -> events ($user = null, array $query = []):obj

line 60
使用 Microsoft Graph API 从指定用户的 Microsoft 邮箱中获取事件。
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->get('users/'.rawurlencode((string)$mailbox).'/events', $query)
method

%MicrosoftGraph -> sendMail ($message, $user = null, bool $save = true):obj

line 67
使用 Microsoft Graph API 发送电子邮件消息,可以选择指定用户以及是否将消息保存到已发送邮件文件夹。
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->post('users/'.rawurlencode((string)$mailbox).'/sendMail', ['message' => $message, 'saveToSentItems' => $save])
method

%MicrosoftGraph -> createEvent (array $event, $user = null):obj

line 74
使用提供的事件详细信息在指定用户的 Microsoft 日历中创建新事件。
if ($m = $this->missing('tenant_id', 'client_id', 'client_secret')) return $m
$mailbox = $this->mailbox($user)
if ($mailbox === void) return static::fail('Microsoft mailbox required')
return $this->post('users/'.rawurlencode((string)$mailbox).'/events', $event)
object

%Moneybird

/phlo/resources/connectors/finance/Moneybird.phlo
version 1.0
creator q-ai.nl
summary Moneybird connector: read contacts and invoices, create sales invoices
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Moneybird
tags moneybird accounting invoices contacts connector
const

Moneybird :: section

line 11
在Moneybird集成中定义一个部分,用于组织相关功能。
'Moneybird'
method

%Moneybird -> base

line 13
这会检索Moneybird API的基础URL,如果可用,则包含配置中的管理ID。
'https://moneybird.com/api/v2/'.($this->config['administration_id'] ?? void)
method

%Moneybird -> headers

line 15
返回与Moneybird API身份验证所需的headers,使用从配置中的访问令牌派生的bearer token。
[static::bearer($this->config['access_token'] ?? void)]
static

Moneybird :: fields

line 17
定义了Moneybird集成的字段,包括管理ID和用于访问联系人和发票的个人访问令牌。
arr(
	section: 'Moneybird',
	config: arr(administration_id: 'Administration ID'),
	secret: arr(access_token: 'Personal access token with read/write for contacts and invoices'),
)
method

%Moneybird -> contacts (array $query = []):obj

line 23
根据提供的查询参数从Moneybird获取联系人列表。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts.json', $query)
method

%Moneybird -> findContact ($query):obj

line 28
根据提供的查询在Moneybird中查找联系人,返回找到的第一个结果。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts.json', ['query' => $query, 'per_page' => 1])
method

%Moneybird -> contact ($id):obj

line 33
从Moneybird检索与指定ID关联的联系人信息,需提供管理ID和访问令牌。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('contacts/'.$id.'.json')
method

%Moneybird -> invoices (array $query = []):obj

line 38
根据提供的查询参数从Moneybird获取发票,要求提供'administration_id'和'access_token'。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->get('sales_invoices.json', $query)
method

%Moneybird -> createContact (array $contact):obj

line 43
使用提供的联系信息在Moneybird中创建新联系人。它需要一个管理ID和访问令牌才能正常工作。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->post('contacts.json', ['contact' => $contact])
method

%Moneybird -> createInvoice (array $invoice):obj

line 48
使用提供的发票数据在Moneybird中创建新发票。
if ($m = $this->missing('administration_id', 'access_token')) return $m
return $this->post('sales_invoices.json', ['sales_invoice' => $invoice])
object

%OAuthConnector

/phlo/resources/connectors/OAuthConnector.phlo
version 1.0
creator q-ai.nl
summary Base class for OAuth2 connectors: stored, auto-refreshed bearer access tokens via TokenStore, on the OAuth2 primitive
extends Connector
package connectors
frontend false
backend true
requires @Connector TokenStore
tags oauth oauth2 connector base token refresh
const

OAuthConnector :: tokenUrl

line 11
指定获取OAuth令牌的URL。
void
method

%OAuthConnector -> oauthKey

line 13
获取OAuthConnector中当前部分的OAuth密钥。
static::section
prop

%OAuthConnector -> token

line 15
使用提供的凭据和刷新令牌从 TokenStore 中检索 OAuth 令牌。
TokenStore::access($this->oauthKey, static::tokenUrl, $this->config['client_id'] ?? void, $this->config['client_secret'] ?? void, ['refresh_token' => $this->config['refresh_token'] ?? null])
method

%OAuthConnector -> headers

line 17
返回OAuth认证所需的头部,包括从实例的token派生的bearer token。
[static::bearer((string)$this->token)]
method

%OAuthConnector -> authed

line 19
通过验证OAuth令牌是否非空来检查其是否已认证。
(string)$this->token !== void
object

%Resend

/phlo/resources/connectors/chat/Resend.phlo
version 1.0
creator q-ai.nl
summary Resend connector: send transactional email via the HTTP API
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Resend
tags resend email transactional messaging connector
const

Resend :: section

line 11
Resend::section 允许您在 Resend 资源中定义一个部分,以组织相关内容。
'Resend'
method

%Resend -> base

line 13
设置 Resend API 的基础 URL。
'https://api.resend.com'
method

%Resend -> headers

line 15
使用配置中提供的API密钥设置Resend请求的头部。
[static::bearer($this->config['api_key'] ?? void)]
static

Resend :: fields

line 17
定义Resend配置的字段,包括默认发件人电子邮件和API密钥。
arr(
	section: 'Resend',
	config: arr(from_email: 'Default sender, e.g. "App <noreply@yourdomain.com>"'),
	secret: arr(api_key: 'API key (re_...)'),
)
method

%Resend -> send ($to, $subject, $html = void, array $extra = []):obj

line 23
使用配置的发件人电子邮件地址向指定的收件人发送电子邮件,主题和可选的 HTML 内容。
if ($m = $this->missing('api_key', 'from_email')) return $m
$email = ['from' => $this->config['from_email'], 'to' => is_array($to) ? $to : [$to], 'subject' => $subject]
if ($html !== void) $email['html'] = $html
return $this->post('emails', $email + $extra)
object

%Shopify

/phlo/resources/connectors/shops/Shopify.phlo
version 1.0
creator q-ai.nl
summary Shopify Admin API connector: read customers, orders and products; create draft orders and products; update inventory
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Shopify
tags shopify webshop ecommerce orders products connector
const

Shopify :: section

line 11
在Shopify主题中定义一个部分,允许在商店内自定义内容和布局。
'Shopify'
method

%Shopify -> base

line 13
使用配置中的商店域名和API版本构建Shopify API的基础URL。
'https://'.($this->config['shop_domain'] ?? void).'/admin/api/'.($this->config['api_version'] ?? '2024-01')
method

%Shopify -> headers

line 15
这获取了Shopify API身份验证所需的头信息,包括来自配置的访问令牌。
['X-Shopify-Access-Token: '.($this->config['access_token'] ?? void)]
static

Shopify :: fields

line 17
定义与Shopify集成的配置字段,包括商店域名、API版本、访问令牌和所需的权限范围。
arr(
	section: 'Shopify',
	config: arr(
		shop_domain: 'Shop domain, e.g. your-store.myshopify.com',
		api_version: 'Admin API version (optional, default 2024-01)',
	),
	secret: arr(access_token: 'Admin API access token (shpat_...)'),
	scopes: 'read_customers, read_orders, read_products, write_draft_orders, write_inventory',
)
method

%Shopify -> customers (array $query = []):obj

line 27
使用提供的查询参数从 Shopify 获取客户列表。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers.json', $query)
method

%Shopify -> searchCustomers ($query, int $limit = 10):obj

line 32
根据查询字符串和可选的结果数量限制在Shopify中搜索客户。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers/search.json', ['query' => $query, 'limit' => $limit])
method

%Shopify -> customer ($id):obj

line 37
使用指定的客户ID从Shopify获取客户信息。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('customers/'.$id.'.json')
method

%Shopify -> orders (array $query = []):obj

line 42
根据提供的查询参数从Shopify获取订单列表。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('orders.json', $query)
method

%Shopify -> products (array $query = []):obj

line 47
使用提供的查询参数从Shopify获取产品列表。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->get('products.json', $query)
method

%Shopify -> createDraftOrder (array $order):obj

line 52
使用提供的订单详细信息在Shopify中创建草稿订单。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('draft_orders.json', ['draft_order' => $order])
method

%Shopify -> createProduct (array $product):obj

line 57
使用提供的产品详细信息在 Shopify 中创建新产品。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('products.json', ['product' => $product])
method

%Shopify -> setInventory ($inventoryItemId, $locationId, int $available):obj

line 62
为Shopify中特定库存项目在给定位置设置可用库存水平。
if ($m = $this->missing('shop_domain', 'access_token')) return $m
return $this->post('inventory_levels/set.json', ['inventory_item_id' => $inventoryItemId, 'location_id' => $locationId, 'available' => $available])
object

%Slack

/phlo/resources/connectors/chat/Slack.phlo
version 1.0
creator q-ai.nl
summary Slack connector: post messages, read channel history and list channels
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Slack
tags slack messaging chat connector
const

Slack :: section

line 11
在Slack消息中创建一个部分块,允许包含文本和其他元素。
'Slack'
const

Slack :: api

line 12
此项提供对Slack API的访问,允许与Slack服务和功能集成。
'https://slack.com/api'
method

%Slack -> headers

line 14
返回使用 bearer token 向 Slack API 发出请求时所需的身份验证头。
[static::bearer($this->config['bot_token'] ?? void)]
static

Slack :: fields

line 16
定义与Slack集成的配置字段,包括机器人令牌、签名密钥和所需的作用域。
arr(
	section: 'Slack',
	secret: arr(
		bot_token: 'Bot user OAuth token (xoxb-...)',
		signing_secret: 'Signing secret for inbound webhook verification (optional)',
	),
	scopes: 'chat:write, channels:history, channels:read',
)
method

%Slack -> result (obj $res):obj

line 25
处理来自Slack API调用的结果,如果成功则返回响应,如果发生错误则返回错误消息。
if (!$res->ok) return $res
$data = $res->data
if (is_object($data) && ($data->ok ?? null) === false) return static::fail($data->error ?? 'Slack API error', $res->status)
return $res
method

%Slack -> send ($channel, $text, array $extra = []):obj

line 32
使用Slack API向指定的Slack频道发送消息。它需要配置的bot令牌,并通过数组接受额外参数。
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->post('chat.postMessage', ['channel' => $channel, 'text' => $text] + $extra))
method

%Slack -> history ($channel, int $limit = 20):obj

line 37
从指定的Slack频道获取消息历史记录,并可选择限制返回的消息数量。
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->get('conversations.history', ['channel' => $channel, 'limit' => $limit]))
method

%Slack -> channels (int $limit = 100, string $types = 'public_channel'):obj

line 42
从Slack获取频道列表,可以选择限制频道数量并指定要返回的频道类型。
if (!$this->configured('bot_token')) return static::fail('Slack bot_token not configured')
return $this->result($this->get('conversations.list', ['limit' => $limit, 'types' => $types]))
object

%Telegram

/phlo/resources/connectors/chat/Telegram.phlo
version 1.0
creator q-ai.nl
summary Telegram Bot API connector: send messages, photos and documents; poll updates
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Telegram
tags telegram bot messaging chat connector
const

Telegram :: section

line 11
在Telegram资源中定义一个部分,允许对相关内容进行有组织的分组。
'Telegram'
method

%Telegram -> base

line 13
使用配置中提供的机器人令牌构建Telegram Bot API的基本URL。
'https://api.telegram.org/bot'.($this->config['bot_token'] ?? void)
static

Telegram :: fields

line 15
定义与Telegram配置相关的字段,包括机器人令牌和用于验证的可选Webhook密钥。
arr(
	section: 'Telegram',
	secret: arr(
		bot_token: 'Bot token from BotFather',
		webhook_secret: 'Webhook secret token for inbound verification (optional)',
	),
	help: 'Create a bot via BotFather and store its token. The chat_id is the recipient or chat to message.',
)
method

%Telegram -> result (obj $res):obj

line 24
处理来自Telegram API响应的结果,如果成功则返回响应,若检测到错误则返回失败消息。
if (!$res->ok) return $res
$data = $res->data
if (is_object($data) && ($data->ok ?? null) === false) return static::fail($data->description ?? 'Telegram API error', $res->status)
return $res
method

%Telegram -> send ($chatId, $text, array $extra = []):obj

line 31
使用提供的聊天ID和文本向指定的Telegram聊天发送消息,并可以选择额外参数。
if ($m = $this->missing('bot_token')) return $m
return $this->result($this->post('sendMessage', ['chat_id' => $chatId, 'text' => $text] + $extra))
method

%Telegram -> photo ($chatId, $photo, $caption = void, array $extra = []):obj

line 36
向指定的Telegram聊天发送照片,附带可选的标题和额外参数。
if ($m = $this->missing('bot_token')) return $m
$payload = ['chat_id' => $chatId, 'photo' => $photo]
if ($caption !== void) $payload['caption'] = $caption
return $this->result($this->post('sendPhoto', $payload + $extra))
method

%Telegram -> document ($chatId, $document, $caption = void, array $extra = []):obj

line 43
向指定的Telegram聊天发送文档,可选地包括标题和其他参数。
if ($m = $this->missing('bot_token')) return $m
$payload = ['chat_id' => $chatId, 'document' => $document]
if ($caption !== void) $payload['caption'] = $caption
return $this->result($this->post('sendDocument', $payload + $extra))
method

%Telegram -> updates (int $offset = 0, int $limit = 100):obj

line 50
从Telegram bot API获取更新,允许通过'offset'和'limit'参数进行分页。
if ($m = $this->missing('bot_token')) return $m
return $this->result($this->get('getUpdates', ['offset' => $offset, 'limit' => $limit]))
object

%TokenStore

/phlo/resources/connectors/TokenStore.phlo
version 1.0
creator q-ai.nl
summary Persisted OAuth2 token store with automatic refresh via the OAuth2 resource
package connectors
frontend false
backend true
requires OAuth2
tags oauth oauth2 token refresh store credentials
static

TokenStore :: path ($key):string

line 10
TokenStore::$path 属性定义了存储令牌数据的文件路径,该路径基于提供的键的经过清理的版本格式化为 JSON 文件。
data.'tokens/'.preg_replace('/[^a-z0-9_.-]+/i', us, (string)$key).'.json'
static

TokenStore :: read ($key):array

line 12
通过键从TokenStore读取令牌,如果文件存在且可访问,则返回令牌数组。
$file = static::path($key)
if (!is_file($file)) return []
@chmod(data.'tokens', 0700)
@chmod($file, 0600)
return (array)json_read($file, true)
static

TokenStore :: write ($key, array $token):void

line 20
该方法将令牌写入指定文件中的安全目录,确保目录和文件具有适当的权限。
$dir = data.'tokens'
is_dir($dir) || mkdir($dir, 0700, true)
@chmod($dir, 0700)
$file = static::path($key)
json_write($file, $token)
@chmod($file, 0600)
static

TokenStore :: valid (array $token):bool

line 29
通过确保访问令牌存在且未过期(允许在过期前有30秒的缓冲)来检查访问令牌是否有效。
($token['access_token'] ?? void) !== void && (int)($token['expires_at'] ?? 0) > time() + 30
static

TokenStore :: store ($res, $refresh):array

line 31
存储访问令牌、刷新令牌和过期时间以用于身份验证。
$token = [
	'access_token' => $res['access_token'],
	'refresh_token' => $res['refresh_token'] ?? $refresh,
	'expires_at' => time() + (int)($res['expires_in'] ?? 3600),
]
return $token
static

TokenStore :: lock ($key)

line 42
TokenStore::$lock 管理基于文件的锁定机制,用于令牌存储,确保在操作期间对令牌文件的独占访问。
$dir = data.'tokens'
is_dir($dir) || mkdir($dir, 0700, true)
$lock = @fopen(static::path($key).'.lock', 'c')
if (!$lock || !flock($lock, LOCK_EX)){
	$lock && fclose($lock)
	return null
}
return $lock
static

TokenStore :: access ($key, $tokenUrl, $clientId, $clientSecret, array $seed = []):?string

line 53
从 TokenStore 中检索访问令牌,如有必要,使用刷新令牌进行刷新。
$token = static::read($key)
if (static::valid($token)) return $token['access_token']
$lock = static::lock($key)
if (!$lock) return null
try {
	$token = static::read($key)
	if (!($token['refresh_token'] ?? null) && ($seed['refresh_token'] ?? null)){
		$token = ['refresh_token' => $seed['refresh_token']]
		static::write($key, $token)
	}
	if (static::valid($token)) return $token['access_token']
	$refresh = $token['refresh_token'] ?? null
	if (!$refresh || !$tokenUrl || !$clientId) return null
	$res = OAuth2::refresh($tokenUrl, $clientId, $clientSecret, $refresh)
	if (!($res['access_token'] ?? null)) return null
	$token = static::store($res, $refresh)
	static::write($key, $token)
	return $token['access_token']
} finally {
	flock($lock, LOCK_UN)
	fclose($lock)
}
object

%Twilio

/phlo/resources/connectors/chat/Twilio.phlo
version 1.0
creator q-ai.nl
summary Twilio connector: send SMS and read message status
extends Connector
package connectors
frontend false
backend true
requires @Connector creds:Twilio
tags twilio sms messaging connector
const

Twilio :: section

line 11
在Phlo应用程序中定义Twilio集成的部分。
'Twilio'
method

%Twilio -> base

line 13
构建用于访问 Twilio API 的基础 URL,使用配置中的账户 SID。
'https://api.twilio.com/2010-04-01/Accounts/'.($this->config['account_sid'] ?? void)
method

%Twilio -> headers

line 15
使用配置中提供的账户 SID 和身份验证令牌检索 Twilio API 请求所需的头部信息。
[static::basic($this->config['account_sid'] ?? void, $this->config['auth_token'] ?? void)]
static

Twilio :: fields

line 17
定义用于配置 Twilio 集成的字段,包括账户 SID、发送者号码和可选的消息服务 SID,以及身份验证令牌。
arr(
	section: 'Twilio',
	config: arr(
		account_sid: 'Account SID (ACxxxx)',
		from_number: 'Sender number in E.164, e.g. +31600000000 (use this or messaging_service_sid)',
		messaging_service_sid: 'Messaging Service SID (optional alternative to from_number)',
	),
	secret: arr(auth_token: 'Auth token'),
)
method

%Twilio -> sms ($to, $body, array $extra = []):obj

line 27
使用Twilio的API发送SMS消息,配置中需要提供from_number或messaging_service_sid。
if ($m = $this->missing('account_sid', 'auth_token')) return $m
$from = $this->config['from_number'] ?? void
$service = $this->config['messaging_service_sid'] ?? void
if ($from === void && $service === void) return static::fail('Twilio from_number or messaging_service_sid required')
$fields = ['To' => $to, 'Body' => $body] + $extra
if ($service !== void) $fields['MessagingServiceSid'] = $service
else $fields['From'] = $from
return $this->form('Messages.json', $fields)
method

%Twilio -> message ($sid):obj

line 38
使用指定的消息 SID 从 Twilio 检索消息。
if ($m = $this->missing('account_sid', 'auth_token')) return $m
return $this->get('Messages/'.$sid.'.json')

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。