PHPackages                             risetechapps/risetools - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. risetechapps/risetools

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

risetechapps/risetools
======================

Coleção de macros e helpers Laravel criados pela RiseTechApps.

3.0.2(2w ago)0449↓67.7%3MITBladePHP ^8.4

Since Nov 11Pushed 3mo agoCompare

[ Source](https://github.com/risetechapps/risetools)[ Packagist](https://packagist.org/packages/risetechapps/risetools)[ RSS](/packages/risetechapps-risetools/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (21)Versions (18)Used By (3)

🌅 Rise Tech Tools
=================

[](#-rise-tech-tools)

Pacote de **macros, helpers e utilitários avançados** da [Rise Tech](https://risetech.com.br) para aplicações Laravel.

Inclui agora:

✨ **AvatarGenerator** — criação automática de avatares circulares com gradiente, iniciais e cores consistentes.
Ideal para APIs, dashboards, perfis de usuários e sistemas que precisam de avatares dinâmicos.

> Compatível com **Laravel 12+** e **PHP 8.4+**

[![Packagist Version](https://camo.githubusercontent.com/ad3b0a0de06ca7efb80211acab180427daa0ab0dce617dd6b572f85a8bd8c609/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7269736574656368617070732f72697365746f6f6c732e7376673f636f6c6f723d303062666135)](https://packagist.org/packages/risetechapps/risetools)[![License](https://camo.githubusercontent.com/86e1c55c086975d07c11c0167b78b714f52212d8bfccd76dabba8f67f0488c6a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f7269736574656368617070732f72697365746f6f6c732e7376673f636f6c6f723d303062666135)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/8954266cf3bb41de3961bc203636a79d9ab4299cf0d15590042cf148ae556fc6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342d626c75652e737667)](https://www.php.net/)[![Laravel](https://camo.githubusercontent.com/b72e0aa3b09f6ee9f1cd47f19792a8204408312803c6b277768a5d2c99ffd60c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31322e782d7265642e737667)](https://laravel.com)

---

🚀 Instalação
------------

[](#-instalação)

```
composer require risetechapps/risetools
```

---

Macros de Resposta JSON
-----------------------

[](#macros-de-resposta-json)

Para padronizar as respostas da API e facilitar o consumo por clientes, foram registradas macros na `Illuminate\Contracts\Routing\ResponseFactory` que seguem um formato JSON consistente.

Todas as respostas JSON seguirão a seguinte estrutura base:

CampoTipoDescrição`success``boolean`Indica se a operação foi bem-sucedida (`true`) ou se ocorreu um erro (`false`).`code``integer`O código de status HTTP da resposta.`message``string`Uma mensagem descritiva sobre o resultado da operação (opcional).`data``object/array`Os dados de resposta da operação (opcional).### Macros Disponíveis

[](#macros-disponíveis)

As macros podem ser chamadas diretamente a partir da *facade* `response()`.

#### 1. `response()->jsonSuccess($data = null, $message = 'Operation completed successfully.')`

[](#1-response-jsonsuccessdata--null-message--operation-completed-successfully)

Utilizada para retornar uma resposta de sucesso.

- **Status HTTP:** `200 OK`
- **Parâmetros:**
    - `$data`: Dados a serem retornados (array ou `JsonResource`).
    - `$message`: Mensagem de sucesso personalizada.
- **Exemplo de Uso:**```
    return response()->jsonSuccess(['id' => 1, 'name' => 'Produto X']);
    ```
- **Exemplo de Resposta:**```
    {
        "success": true,
        "code": 200,
        "message": "Operation completed successfully.",
        "data": {
            "id": 1,
            "name": "Produto X"
        }
    }
    ```

#### 2. `response()->jsonError($message = 'Resource not available.', $data = null)`

[](#2-response-jsonerrormessage--resource-not-available-data--null)

Utilizada para retornar um erro de processamento ou de entidade não processável.

- **Status HTTP:** `422 Unprocessable Entity`
- **Parâmetros:**
    - `$message`: Mensagem de erro personalizada.
    - `$data`: Dados adicionais sobre o erro (ex: erros de validação).
- **Exemplo de Uso:**```
    return response()->jsonError('Os dados fornecidos são inválidos.', ['errors' => ['field' => 'required']]);
    ```

#### 3. `response()->jsonGone($message = 'Recurso não disponível.', $data = null)`

[](#3-response-jsongonemessage--recurso-não-disponível-data--null)

Utilizada para indicar que o recurso solicitado não está mais disponível e não será novamente.

- **Status HTTP:** `410 Gone`
- **Parâmetros:**
    - `$message`: Mensagem de erro personalizada.
    - `$data`: Dados adicionais sobre o erro.
- **Exemplo de Uso:**```
    return response()->jsonGone('A versão desta API foi descontinuada.');
    ```

#### 4. `response()->jsonNotFound($message = 'Resource not found.', $data = null)`

[](#4-response-jsonnotfoundmessage--resource-not-found-data--null)

Utilizada para indicar que o recurso solicitado não foi encontrado.

- **Status HTTP:** `404 Not Found`
- **Parâmetros:**
    - `$message`: Mensagem de erro personalizada.
    - `$data`: Dados adicionais sobre o erro.
- **Exemplo de Uso:**```
    return response()->jsonNotFound('O usuário com ID 5 não existe.');
    ```

#### 5. `response()->jsonInternal($message = 'Internal server error.', $data = null)`

[](#5-response-jsoninternalmessage--internal-server-error-data--null)

Utilizada para indicar um erro interno do servidor.

- **Status HTTP:** `500 Internal Server Error`
- **Parâmetros:**
    - `$message`: Mensagem de erro personalizada.
    - `$data`: Dados adicionais sobre o erro (ex: ID de rastreamento de log).
- **Exemplo de Uso:**```
    return response()->jsonInternal('Ocorreu um erro inesperado ao processar a requisição.');
    ```

---

### Macro Base (Interna)

[](#macro-base-interna)

A macro `jsonBase` é a implementação interna utilizada por todas as outras macros e não deve ser chamada diretamente em seu código de aplicação.

`response()->jsonBase(bool $success, string $message = null, array|JsonResource $data = null, int $code = Response::HTTP_OK)`

---

🎨 AvatarGenerator
=================

[](#-avatargenerator)

O **AvatarGenerator** permite gerar imagens de avatar totalmente automáticas com:

- ✔ Gradiente circular elegante
- ✔ Cores únicas e consistentes baseadas no nome
- ✔ Iniciais automáticas (ex.: “Mateus Soares” → MS)
- ✔ Fundo circular com transparência
- ✔ Retorno como PNG binário
- ✔ Retorno Base64 (ideal para API)
- ✔ Salvamento como arquivo
- ✔ Salvamento via Laravel Storage

---

🧪 Exemplo de Uso
----------------

[](#-exemplo-de-uso)

### ➤ Gerar avatar como PNG

[](#-gerar-avatar-como-png)

```
use RiseTechApps\RiseTools\Features\AvatarGenerator;

$avatar = new AvatarGenerator();
$png = $avatar->generate('Mateus Soares');

return response($png)->header('Content-Type', 'image/png');
```

---

### ➤ Gerar avatar em Base64

[](#-gerar-avatar-em-base64)

```
$avatar = new AvatarGenerator();

return [
    'avatar' => $avatar->generateBase64('Mateus Soares'),
];
```

---

### ➤ Salvar avatar em arquivo

[](#-salvar-avatar-em-arquivo)

```
$avatar = new AvatarGenerator();
$avatar->saveToFile('avatars/mateus.png', 'Mateus Soares');
```

---

### ➤ Salvar usando Storage do Laravel

[](#-salvar-usando-storage-do-laravel)

```
$avatar = new AvatarGenerator();

$avatar->saveToStorage(
    'public',
    'avatars/mateus.png',
    'Mateus Soares'
);
```

---

⚙️ Funcionamento
----------------

[](#️-funcionamento)

O gradiente é criado com base em um hash MD5 do nome, garantindo que cada usuário tenha sempre **as mesmas cores**.
As iniciais são extraídas automaticamente:

NomeResultadoMateus Soares**MS**Mateus**MA**João da Silva**JS**""**U**---

🛠️ Tecnologias Utilizadas
-------------------------

[](#️-tecnologias-utilizadas)

- PHP GD / FreeType
- Nenhuma dependência externa
- Totalmente stateless

---

MaskInput
=========

[](#maskinput)

O **MaskInput** permite **aplicar máscaras em strings**, ideal para CPF, CNPJ, telefone, CEP e outros formatos personalizados.

### Utilizando a classe `MaskInput`

[](#utilizando-a-classe-maskinput)

```
use RiseTechApps\RiseTools\Features\MaskInput\MaskInput;

$maskInput = new MaskInput();

$result = $maskInput->MaskInput('12345678901', '###.###.###-##');

echo $result;
// 123.456.789-01

echo MaskInput('12345678901', '###.###.###-##');
// 123.456.789-01
```

---

🧩 Como funciona
---------------

[](#-como-funciona)

- O caractere `#` representa um valor dinâmico
- Qualquer outro caractere na máscara é inserido automaticamente
- A máscara é aplicada da esquerda para a direita
- Valores excedentes são ignorados

### Parâmetros

[](#parâmetros)

ParâmetroTipoDescrição`$value`stringValor sem máscara`$mask`stringMáscara desejada---

Device
======

[](#device)

O utilitário para **detecção de informações do dispositivo, navegador, plataforma e geolocalização por IP** em aplicações Laravel.

Este recurso utiliza o pacote `hisorange/browser-detect` para identificar o ambiente do usuário e a API pública `ip-api.com` para dados de geolocalização.

---

🚀 Uso
-----

[](#-uso)

### Obtendo informações do dispositivo

[](#obtendo-informações-do-dispositivo)

```
use RiseTechApps\RiseTools\Features\Device\Device;

$info = Device::info();

dd($info);
```

---

📌 Retorno do método `info()`
----------------------------

[](#-retorno-do-método-info)

O método retorna um array com as seguintes informações:

```
[
    'device' => 'Desktop | Mobile | Tablet | Bot | Unknown',
    'browser' => 'Chrome | Safari | Firefox | Edge | Opera | IE | webView | Unknown',
    'browser_name' => 'Nome completo do navegador',
    'platformName' => 'Windows | Android | iOS | Linux | MacOS | etc',
    'geo_ip' => [
        'status' => '',
        'country' => '',
        'countryCode' => '',
        'region' => '',
        'regionName' => '',
        'city' => '',
        'zip' => '',
        'lat' => '',
        'lon' => '',
        'timezone' => '',
        'isp' => '',
        'org' => '',
        'as' => '',
        'query' => '',
    ]
]
```

---

🌍 Geolocalização por IP
-----------------------

[](#-geolocalização-por-ip)

A geolocalização é obtida através do serviço público:

- **ip-api.com**

O resultado é **cacheado por IP durante 24h** (via `Cache` do Laravel) e a chamada HTTP usa timeout (connect 2s / total 4s), evitando travar a request. Apenas respostas `status: success` são cacheadas.

⚠️ Observação:

- O serviço possui limites de requisição (~45 req/min no plano gratuito)
- O cache por IP reduz drasticamente o número de chamadas, mas requer um driver de cache persistente (não `array`)

---

🧠 Detecção de IP do Cliente
---------------------------

[](#-detecção-de-ip-do-cliente)

O método tenta identificar corretamente o IP público considerando:

- Cloudflare (`HTTP_CF_CONNECTING_IP`)
- Proxy reverso (`X-Forwarded-For`)
- IP real (`REMOTE_ADDR`)
- Fallback para `request()->ip()`

---

🧪 Métodos Disponíveis
---------------------

[](#-métodos-disponíveis)

```
Device::info(): array
Device::getClientPublicIp(): ?string
```

---

Domain
======

[](#domain)

Package utilitário para **análise e obtenção de informações de domínios**, incluindo subdomínio, IP, registros DNS, SSL, status de publicação e dados WHOIS.

Este recurso faz parte do ecossistema **RiseTools** e foi projetado para uso em aplicações Laravel.

---

📦 Instalação
------------

[](#-instalação-1)

Instale as dependências necessárias via Composer:

```
composer require spatie/dns jeremykendall/php-domain-parser iodev/whois
```

> O pacote utiliza a lista oficial do Public Suffix (`publicsuffix.org`).

### 🗂️ Cache do Public Suffix List

[](#️-cache-do-public-suffix-list)

A lista **não** é baixada a cada `new Domain()`. A resolução segue esta ordem:

1. Memo por processo (objeto `Rules` já parseado)
2. Cache do Laravel (`risetools:psl`, 7 dias)
3. Um único download remoto (timeout 5s), armazenado no cache
4. Cópia local empacotada (`src/Features/Domain/public_suffix_list.dat`) como fallback offline

Assim não há chamada de rede no caminho da request após o primeiro carregamento, e o recurso não quebra sem internet. O cache de 7 dias requer um driver de cache persistente (não `array`).

---

⚙️ Requisitos
-------------

[](#️-requisitos)

- PHP **8.4+**
- Laravel **12+**
- Extensões PHP:
    - `openssl`
    - `dns`

---

🚀 Uso Básico
------------

[](#-uso-básico)

### Criando a instância da classe Domain

[](#criando-a-instância-da-classe-domain)

```
use RiseTechApps\RiseTools\Features\Domain\Domain;

$domain = new Domain('blog.example.com');

$domain = domainTools('blog.example.com');
```

---

📌 Métodos Disponíveis
---------------------

[](#-métodos-disponíveis-1)

### Obter domínio principal (registrável)

[](#obter-domínio-principal-registrável)

```
$domain->getDomain();
// example.com
```

### Obter subdomínio

[](#obter-subdomínio)

```
$domain->getSubDomain();
// blog
```

### Obter IP do domínio

[](#obter-ip-do-domínio)

```
$domain->getIp();
// 93.184.216.34
```

### Obter registros DNS

[](#obter-registros-dns)

```
$domain->getDnsRecords();
// Retorna registros A, MX, TXT, CNAME, etc
```

---

🔐 Informações de SSL
--------------------

[](#-informações-de-ssl)

```
$domain->getSslInfo();
```

Retorno esperado:

```
[
    'status' => true,
    'issuer' => 'Let\'s Encrypt',
    'expires_at' => '2025-01-01 12:00:00',
    'is_expired' => false
]
```

---

🌐 Verificações de Domínio
-------------------------

[](#-verificações-de-domínio)

### Verificar se o domínio resolve no DNS

[](#verificar-se-o-domínio-resolve-no-dns)

```
$domain->isResolvable();
// true | false
```

### Verificar se o domínio está publicado

[](#verificar-se-o-domínio-está-publicado)

```
$domain->isPublished();
// true | false
```

---

🧾 WHOIS – Data de Expiração
---------------------------

[](#-whois--data-de-expiração)

```
$domain->getWhoisExpiration();
// 2026-03-15
```

> ⚠️ O WHOIS pode falhar dependendo do TLD ou indisponibilidade do servidor.

---

📊 Informações Completas do Domínio
----------------------------------

[](#-informações-completas-do-domínio)

```
$domain->getInfo();
```

Retorno:

```
[
    'domain' => 'example.com',
    'hasSubDomain' => true,
    'subDomain' => 'blog',
    'ip' => '93.184.216.34',
    'dns' => [],
    'ssl' => [],
    'resolve' => true,
    'status' => true,
    'expires_at' => '2026-03-15',
    'url' => 'http://blog.example.com',
    'fullUrl' => 'https://blog.example.com'
]
```

> `fullUrl` usa `https` apenas quando há certificado SSL válido; caso contrário, é igual a `url` (`http`).

---

AtomicJobChain
==============

[](#atomicjobchain)

O `AtomicJobChain` é uma poderosa classe utilitária do Laravel que permite encadear múltiplos Jobs de forma **atômica** e **sequencial**. Diferente do encadeamento nativo do Laravel, esta implementação oferece um controle mais refinado sobre o fluxo de execução e incorpora os callbacks de sucesso, falha e finalização (`then`, `catch`, `finally`), inspirados no recurso de Batches.

🌟 Funcionalidades Principais
----------------------------

[](#-funcionalidades-principais)

- **Execução Sequencial Atômica:** Os Jobs são executados um após o outro. A falha em qualquer Job interrompe imediatamente a execução da cadeia.
- **Callbacks de Fluxo de Controle:** Suporte a `then()`, `catch()` e `finally()` para reagir ao resultado final da cadeia.
- **Integração com Eventos:** Método `toListener()` para fácil despacho da cadeia a partir de Listeners de Eventos.
- **Visibilidade no Horizon:** Implementação do `displayName()` para uma visualização clara e descritiva no painel do Laravel Horizon.

🚀 Uso
-----

[](#-uso-1)

A cadeia é tipicamente construída usando o método estático `make()` e configurada com a *Fluent Interface*.

### 1. Construção e Despacho

[](#1-construção-e-despacho)

O uso mais comum é dentro de um Listener de Eventos, garantindo que a cadeia seja despachada de forma assíncrona.

```
use App\Jobs\Database\SeedDatabaseJob;
use App\Jobs\SubTenant\CreateSubTenantDefaultJob;
use App\Events\Database\DatabaseMigratedEvent;
use RiseTechApps\RiseTools\Features\AtomicJobChain\AtomicJobChain;

// Dentro de um EventServiceProvider ou Listener
Event::listen(DatabaseMigratedEvent::class, function (DatabaseMigratedEvent $event) {

    AtomicJobChain::make([
        SeedDatabaseJob::class,
        CreateSubTenantDefaultJob::class,
        // ... adicione quantos Jobs forem necessários
    ])
    // Transforma o evento em um objeto passável para os Jobs internos
    ->send(function (DatabaseMigratedEvent $event) {
        $event->tenancy->refresh();
        return $event->tenancy; // O objeto retornado será passado para os Jobs
    })
    ->shouldBeQueued(true) // Garante que a cadeia será enfileirada
    ->toListener(); // Retorna a Closure que o Laravel usa para despachar o Job
});
```

### 2. Utilizando Callbacks (`then`, `catch`, `finally`)

[](#2-utilizando-callbacks-then-catch-finally)

Os callbacks permitem que você execute ações após a conclusão ou falha da cadeia.

MétodoDescriçãoArgumentos Recebidos`->then(callable $callback)`Executado se **todos** os Jobs na cadeia forem concluídos com sucesso.Nenhum`->catch(callable $callback)`Executado se **qualquer** Job na cadeia falhar.`Throwable $exception` (a exceção que causou a falha)`->finally(callable $callback)`Executado **sempre** ao final da execução, independente do resultado.Nenhum**Exemplo:**

```
AtomicJobChain::make([...])
    ->send([...])
    ->then(function () {
        // Notifica o sucesso da operação
        Log::info('Cadeia de Jobs concluída com sucesso!');
    })
    ->catch(function (Throwable $e) {
        // Registra a falha e a exceção
        Log::error('A cadeia falhou: ' . $e->getMessage());
    })
    ->finally(function () {
        // Executa a limpeza ou notificação final
        Cache::forget('chain_running_flag');
    })
    ->toListener();
```

📊 Monitoramento com Laravel Horizon
-----------------------------------

[](#-monitoramento-com-laravel-horizon)

O `AtomicJobChain` implementa o método `displayName()`, garantindo que o painel do Horizon exiba um nome descritivo em vez do nome da classe.

AntesDepois`RiseTechApps\RiseTools\Features\AtomicJobChain\AtomicJobChain``Atomic Chain: SeedDatabaseJob, CreateSubTenantDefaultJob, ...`### Rastreamento de Falhas

[](#rastreamento-de-falhas)

Em caso de falha, o Horizon registrará o Job pai (`AtomicJobChain`) como falho. A exceção será encapsulada para indicar **qual Job interno** causou a interrupção, facilitando a depuração:

> **Exception:** `Job [App\Jobs\Database\SeedDatabaseJob] failed: SQLSTATE[HY000]: General error: ...`

Isso elimina a necessidade de vasculhar o Stack Trace para identificar o ponto exato da falha.

🛠️ Detalhes Técnicos
--------------------

[](#️-detalhes-técnicos)

A classe utiliza a interface `ShouldQueue` e garante a atomicidade da execução no método `handle()`.

```
// Trecho do método handle()
try {
    // ... execução do Job interno
} catch (Throwable $exception) {
    $hasFailed = true;

    // Executa o callback de falha
    if ($this->onFailure) {
        app()->call($this->onFailure, ['exception' => $exception]);
    }

    // Lança a exceção encapsulada para o Horizon
    throw $wrapperException;
}
// ...
```

O uso de `DB::afterCommit()` no método `toListener()` garante que a cadeia de Jobs só seja despachada para a fila **após** o commit de qualquer transação de banco de dados ativa, prevenindo problemas de concorrência.

```
// Trecho do método toListener()
if (DB::transactionLevel() > 0) {
    DB::afterCommit(function () use ($executable) {
        dispatch($executable);
    });
} else {
    dispatch($executable);
}
```

---

NPlusOneDetector
================

[](#nplusonedetector)

Detector automático do problema de **N+1 queries** em tempo de execução. Escuta todas as queries do banco (`DB::listen()`), agrupa por padrão, e quando um mesmo padrão se repete acima de um limite, reporta com uma **sugestão de eager loading**.

🧠 O que é N+1
-------------

[](#-o-que-é-n1)

Uma query para a lista + uma query por item ao acessar um relacionamento:

```
$posts = Post::all();          // 1 query
foreach ($posts as $post) {
    echo $post->author->name;  // +1 query POR post → N queries
}
// 100 posts = 101 queries. O ideal seriam 2.
```

Correção típica:

```
Post::with('author')->get();   // 2 queries
```

O `NPlusOneDetector` encontra esses casos automaticamente e sugere o `with()`/`whereIn()`.

🚀 Uso
-----

[](#-uso-2)

Ative no início do ciclo (ex.: um `ServiceProvider` em ambiente `local`/`staging`):

```
use RiseTechApps\RiseTools\Features\NPlusOneDetector\NPlusOneDetector;

NPlusOneDetector::enable()    // inicia a escuta (DB::listen) — obrigatório
    ->threshold(5)            // dispara após 5 repetições do mesmo padrão
    ->sampleRate(1.0)         // 0.0–1.0: fração das queries analisadas
    ->suggestEagerLoading()   // inclui sugestão de correção no relatório
    ->reportToLog();          // grava aviso via Log::warning
```

> A escuta só começa após `NPlusOneDetector::enable()` (método estático). O helper `n_plus_one_detector()` retorna a instância para configuração/consulta, mas **não** ativa a escuta sozinho — use-o após `enable()`:

```
NPlusOneDetector::enable();
n_plus_one_detector()->threshold(5)->suggestEagerLoading()->reportToLog();
```

Quando um N+1 é detectado, um aviso como este vai para o log:

```
[N+1 Query] 8 queries detected for table 'posts'. Adicione ->with(['relation']) ao carregar Post

```

📊 Estatísticas
--------------

[](#-estatísticas)

```
NPlusOneDetector::getStats();
/*
[
    'enabled' => true,
    'total_unique_patterns' => 12,
    'suspicious_patterns' => [...],
    'top_queries' => [...]   // padrões mais frequentes (até 10)
]
*/

NPlusOneDetector::clearStats();  // zera contadores
NPlusOneDetector::disable();     // para de escutar
```

⚙️ Métodos de configuração
--------------------------

[](#️-métodos-de-configuração)

MétodoDescrição`threshold(int)`Nº de repetições do padrão até reportar (default `5`)`sampleRate(float)`Amostragem de `0.0` a `1.0` (default `1.0`)`suggestEagerLoading()`Adiciona sugestão de `with()`/`whereIn()` ao relatório`reportToLog()`Reporta via `Log::warning``reportToSentry()`Reporta ao Sentry (se instalado)🔗 Integração com Sentry
-----------------------

[](#-integração-com-sentry)

Se o SDK do Sentry estiver presente, `reportToSentry()` envia o contexto (`table`, `count`, `suggestion`) e uma mensagem de aviso. Sem o SDK, é silenciosamente ignorado.

⚠️ Cuidados
-----------

[](#️-cuidados)

- **Ferramenta de desenvolvimento/diagnóstico.** Ative em `local`/`staging`. Em produção, use `sampleRate` baixo (ex.: `0.05`) — cada padrão novo captura um `debug_backtrace` (custo).
- **Estado interno é estático.** Em runtimes persistentes (Octane/Swoole) os contadores acumulam entre requests; chame `clearStats()`/`disable()` conforme o ciclo do worker.
- **Apenas detecta** — não altera queries nem código. Emite aviso + sugestão.

---

🛠️ Requisitos
-------------

[](#️-requisitos-1)

DependênciaVersão mínimaPHP8.4Laravel12.xGD + FreeTyperequiredOrchestra Testbench10.xPHPUnit11.xjeremykendall/php-domain-parser6.0spatie/dns2.8.1io-developer/php-whois4.1.10---

🧑‍💻 Autor
---------

[](#‍-autor)

**Rise Tech**
📧
🌐
💼

---

🪪 Licença
---------

[](#-licença)

MIT — veja arquivo LICENSE.

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance87

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~15 days

Recently: every ~27 days

Total

17

Last Release

19d ago

Major Versions

1.8.3 → 2.0.02026-04-28

2.0.0 → 3.0.02026-07-17

PHP version history (2 changes)1.0.0PHP ^8.3

3.0.0PHP ^8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/160299136?v=4)[Rise Tech](/maintainers/risetechapps)[@risetechapps](https://github.com/risetechapps)

---

Top Contributors

[![risetechapps](https://avatars.githubusercontent.com/u/160299136?v=4)](https://github.com/risetechapps "risetechapps (35 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/risetechapps-risetools/health.svg)

```
[![Health](https://phpackages.com/badges/risetechapps-risetools/health.svg)](https://phpackages.com/packages/risetechapps-risetools)
```

###  Alternatives

[spatie/laravel-export

Create a static site bundle from a Laravel app

679153.2k7](/packages/spatie-laravel-export)[spatie/laravel-health

Monitor the health of a Laravel application

88212.7M183](/packages/spatie-laravel-health)[craftcms/cms

Craft CMS

3.6k3.7M3.3k](/packages/craftcms-cms)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k19](/packages/tempest-framework)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

762297.9k49](/packages/civicrm-civicrm-core)[illuminate/process

The Illuminate Process package.

44926.6k120](/packages/illuminate-process)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
