Cos’è TextBuilder
TextBuilder è una classe che permette di comporre tramite metodi concatenati i facets (annotazioni rich text) definiti da AT Protocol di Bluesky.
Il corpo dei post Bluesky è testo semplice, ma per visualizzare menzioni, link e hashtag è necessario inviare, insieme al testo, un array facets che indichi posizione (offset in byte) e tipo. TextBuilder calcola automaticamente questi offset e costruisce l’array.
Creazione di testo base
TextBuilder::make()
Con TextBuilder::make() generi un’istanza specificando il testo iniziale. Il testo iniziale è opzionale.
use Revolution\Bluesky\RichText\TextBuilder;
$builder = TextBuilder::make(text: 'Hello Bluesky');
text()
Con text() aggiungi testo in coda.
$builder = TextBuilder::make()
->text('Hello ')
->text('Bluesky');
// $builder->text === 'Hello Bluesky'
newLine()
Aggiunge un a capo. Con count puoi indicare il numero di righe (default: 1).
$builder = TextBuilder::make('Prima riga')
->newLine()
->text('Seconda riga')
->newLine(count: 2)
->text('Quarta riga');
toPost()
Converte l’istanza di TextBuilder in un record Post. Puoi passarlo direttamente a Bluesky::post().
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\RichText\TextBuilder;
$post = TextBuilder::make('Un post semplice')->toPost();
$response = Bluesky::withToken()->post($post);
Post::build()
Puoi anche passare una closure a Post::build(). Il valore di ritorno è un Post.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\RichText\TextBuilder;
$post = Post::build(function (TextBuilder $builder) {
$builder->text('Hello Bluesky');
});
$response = Bluesky::withToken()->post($post);
Aggiungere una menzione (@mention)
Con mention() aggiungi un facet di menzione.
$builder->mention(text: '@alice.bsky.social');
Risoluzione automatica del DID
Se ometti did, viene risolto automaticamente dall’handle (viene chiamato Bluesky::resolveHandle()).
// Risoluzione automatica del DID (viene fatta una chiamata API)
$builder->mention('@alice.bsky.social');
Specifica esplicita del DID
Se conosci già il DID, puoi passarlo esplicitamente per evitare la chiamata API.
// Specifica diretta del DID (consigliato: nessuna chiamata API)
$builder->mention(text: '@alice.bsky.social', did: 'did:plc:xxxxxxxxxxxxxxxxxxxx');
Se in produzione usi molte menzioni, mettere in cache i DID riduce il numero di chiamate API.
Inserire un link (URL)
Con link() aggiungi un facet di link.
// Usa l'URL stesso come testo visualizzato
$builder->link('https://laravel.com');
// Specifica testo visualizzato e URL separatamente
$builder->link(text: 'Sito ufficiale di Laravel', uri: 'https://laravel.com');
Se ometti uri, viene usato text come URI.
Aggiungere un hashtag
Con tag() aggiungi un facet di hashtag.
// Passando testo che inizia con # il tag viene estratto automaticamente
$builder->tag('#Laravel');
// Specifica esplicita della stringa del tag (senza #)
$builder->tag(text: '#Laravel', tag: 'Laravel');
Composizione di testo complesso
Puoi combinare più facet per creare testi post ricchi.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\RichText\TextBuilder;
$post = TextBuilder::make('Ho pubblicato un nuovo articolo!')
->newLine(count: 2)
->mention('@alice.bsky.social', did: 'did:plc:xxxx')
->text(' spero lo leggerai anche tu.')
->newLine()
->link(text: 'Leggi l\'articolo', uri: 'https://example.com/article/1')
->newLine()
->tag('#Laravel')
->text(' ')
->tag('#PHP')
->toPost();
$response = Bluesky::withToken()->post($post);
Scrittura con Post::build()
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\RichText\TextBuilder;
$post = Post::build(function (TextBuilder $builder) {
$builder->text('Ho pubblicato un nuovo articolo!')
->newLine(count: 2)
->mention('@alice.bsky.social', did: 'did:plc:xxxx')
->text(' spero lo leggerai anche tu.')
->newLine()
->link(text: 'Leggi l\'articolo', uri: 'https://example.com/article/1')
->newLine()
->tag('#Laravel')
->text(' ')
->tag('#PHP');
});
$response = Bluesky::withToken()->post($post);
Integrazione con i post
Combinazione con Bluesky::post()
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\RichText\TextBuilder;
$post = TextBuilder::make('test')
->newLine()
->link('https://bsky.app/')
->toPost();
$response = Bluesky::withToken()->post($post);
Combinazione con il canale Notification
Nel metodo toBluesky() di BlueskyChannel puoi usare Post::build().
use Illuminate\Notifications\Notification;
use Revolution\Bluesky\Notifications\BlueskyChannel;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\RichText\TextBuilder;
class DeployedNotification extends Notification
{
public function __construct(
private string $url,
) {}
public function via(object $notifiable): array
{
return [BlueskyChannel::class];
}
public function toBluesky(object $notifiable): Post
{
return Post::build(function (TextBuilder $builder) {
$builder->text('Deploy completato')
->newLine()
->link(text: 'Verifica', uri: $this->url)
->newLine()
->tag('#Laravel');
});
}
}
Rilevamento automatico dei facets
Puoi anche far rilevare automaticamente @mention, URL e #hashtag nel testo e impostare i facets.
use Revolution\Bluesky\RichText\TextBuilder;
$builder = TextBuilder::make('@alice.bsky.social test https://example.com #alice')
->detectFacets();
// Puoi aggiungere altri facets anche dopo detectFacets()
$builder->newLine()->tag('#bob');
$post = $builder->toPost();
detectFacets() è un rilevamento basato su espressioni regolari. Se vuoi certezza del link, usa esplicitamente link(), mention() o tag().
Aggiungere un facet personalizzato
Con il metodo facet() puoi aggiungere direttamente un array di facet arbitrario.
use Revolution\Bluesky\RichText\TextBuilder;
$builder = TextBuilder::make();
$builder->facet([
'index' => [
'byteStart' => 0,
'byteEnd' => 5,
],
'features' => [
[
'$type' => 'app.bsky.richtext.facet#link',
'uri' => 'https://example.com',
],
],
]);
Limiti di lunghezza e attenzioni
Offset in byte e grapheme
Gli indici dei facet in AT Protocol si specificano in offset UTF-8 in byte. TextBuilder calcola internamente il numero di byte usando strlen().
Caratteri multibyte come giapponese ed emoji occupano più byte anche se rappresentano un solo carattere, quindi gli offset sono determinati dai byte, non dal numero di caratteri.
// 'Hello' occupa 5 byte in UTF-8 (1 carattere = 1 byte)
// '日本語' occupa 9 byte in UTF-8 (1 carattere = 3 byte)
$builder = TextBuilder::make('日本語');
// strlen($builder->text) === 9
Limite di caratteri del post
I post di Bluesky hanno un limite di 300 caratteri in grapheme (caratteri visualizzati). Il limite è espresso in grapheme e non in byte, quindi puoi scrivere fino a 300 caratteri anche in giapponese.
use Illuminate\Support\Str;
$text = 'Questo è il testo del post.';
// Verifica del numero di caratteri in grapheme
$length = Str::length($text); // equivalente a mb_strlen()
TextBuilder di per sé non verifica il numero di caratteri. Se invii un post che supera i 300 grapheme, l’API di AT Protocol restituisce un errore.
Elenco dei metodi
| Metodo | Descrizione |
|---|
TextBuilder::make(string $text = '') | Crea un’istanza |
text(string $text) | Aggiunge testo in coda |
newLine(int $count = 1) | Aggiunge a capo |
mention(string $text, ?string $did = null) | Aggiunge un facet di menzione |
link(string $text, ?string $uri = null) | Aggiunge un facet di link |
tag(string $text, ?string $tag = null) | Aggiunge un facet di hashtag |
detectFacets() | Rileva automaticamente i facets dal testo |
facet(array $facet) | Aggiunge un facet personalizzato |
resetFacets() | Resetta tutti i facets |
toPost() | Converte in record Post |
toArray() | Converte in array ['text' => ..., 'facets' => ...] |