> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# TextBuilder

> Uso dettagliato della classe TextBuilder per costruire in PHP il rich text (facets) di Bluesky.

## 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.

```mermaid theme={null}
sequenceDiagram
    participant App as App Laravel
    participant TB as TextBuilder
    participant Post as Record Post
    participant AT as AT Protocol

    App->>TB: TextBuilder::make('Hello')
    App->>TB: ->mention('@alice.bsky.social')
    App->>TB: ->link('https://example.com')
    App->>TB: ->tag('#Laravel')
    TB->>TB: Calcola gli offset in byte e<br>costruisce l'array facets
    TB->>Post: toPost()
    Post->>AT: Bluesky::post($post)
    AT-->>App: Risposta
```

## Creazione di testo base

### TextBuilder::make()

Con `TextBuilder::make()` generi un'istanza specificando il testo iniziale. Il testo iniziale è opzionale.

```php theme={null}
use Revolution\Bluesky\RichText\TextBuilder;

$builder = TextBuilder::make(text: 'Hello Bluesky');
```

### text()

Con `text()` aggiungi testo in coda.

```php theme={null}
$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).

```php theme={null}
$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()`.

```php theme={null}
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`.

```php theme={null}
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.

```php theme={null}
$builder->mention(text: '@alice.bsky.social');
```

### Risoluzione automatica del DID

Se ometti `did`, viene risolto automaticamente dall'handle (viene chiamato `Bluesky::resolveHandle()`).

```php theme={null}
// 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.

```php theme={null}
// Specifica diretta del DID (consigliato: nessuna chiamata API)
$builder->mention(text: '@alice.bsky.social', did: 'did:plc:xxxxxxxxxxxxxxxxxxxx');
```

<Tip>
  Se in produzione usi molte menzioni, mettere in cache i DID riduce il numero di chiamate API.
</Tip>

## Inserire un link (URL)

Con `link()` aggiungi un facet di link.

```php theme={null}
// 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.

```php theme={null}
// 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.

```php theme={null}
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()

```php theme={null}
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()

```php theme={null}
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()`.

```php theme={null}
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.

```php theme={null}
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();
```

<Warning>
  `detectFacets()` è un rilevamento basato su espressioni regolari. Se vuoi certezza del link, usa esplicitamente `link()`, `mention()` o `tag()`.
</Warning>

## Aggiungere un facet personalizzato

Con il metodo `facet()` puoi aggiungere direttamente un array di facet arbitrario.

```php theme={null}
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**.

```php theme={null}
// '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.

```php theme={null}
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()
```

<Info>
  `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.
</Info>

## 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' => ...]` |

<Info>
  Source: [src/RichText/TextBuilder.php](https://github.com/invokable/laravel-bluesky/blob/main/src/RichText/TextBuilder.php)
</Info>


## Related topics

- [Basic client - Laravel Bluesky](/it/packages/laravel-bluesky/basic-client.md)
- [Laravel Bluesky](/it/packages/laravel-bluesky/index.md)
- [Canale di notifica - Laravel Bluesky](/it/packages/laravel-bluesky/notification.md)
- [Query Builder](/it/query-builder.md)
- [Ricerca](/it/search.md)
