<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
power-vending / laravel-api-query-builder example snippets
// Sem o pacote - você precisa tratar cada caso manualmente
if ($request->has('name')) {
$query->where('name', 'like', '%' . $request->name . '%');
}
if ($request->has('min_price')) {
$query->where('price', '>=', $request->min_price);
}
if ($request->has('category')) {
$query->where('category_id', $request->category);
}
// Com o pacote - uma linha resolve tudo
return Product::query()->requestPaginate();
return [
// Operadores de busca disponíveis
'operators' => [
// Lista de classes de operadores
],
// Colunas que nunca podem ser acessadas via query
'global_forbidden_columns' => [
'password',
'remember_token',
],
// Relacionamentos que nunca podem ser carregados ou expostos por schema
'global_forbidden_relations' => [
'internalRelation',
'company.users',
],
// Outras configurações...
];
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use PowerVending\LaravelApiQueryBuilder\Traits\ApiQueryBuilder;
class Product extends Model
{
use ApiQueryBuilder;
}
'global_forbidden_columns' => [
'password', // Senhas nunca devem ser retornadas
'remember_token', // Tokens de sessão
'api_token', // Tokens de API
'secret_key', // Chaves secretas
'credit_card', // Dados bancários
'cpf', // Dados pessoais sensíveis
],
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use PowerVending\LaravelApiQueryBuilder\Traits\ApiQueryBuilder;
class User extends Model
{
use ApiQueryBuilder;
/**
* Colunas que não podem ser acessadas via API query
*/
protected $apiQueryBuilderForbiddenColumns = [
'password',
'remember_token',
'two_factor_secret',
'api_token',
];
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $apiQueryBuilderForbiddenRelations = [
'profile',
'company.users',
];
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use PowerVending\LaravelApiQueryBuilder\Traits\ApiQueryBuilder;
class Product extends Model
{
use ApiQueryBuilder;
protected $fillable = [
'name',
'description',
'price',
'category_id',
'stock',
];
}
namespace App\Http\Controllers\Api;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function index(Request $request)
{
// Método requestPaginate() - retorna resultados paginados
return Product::query()->requestPaginate();
}
public function search(Request $request)
{
// Método requestQuery() - retorna o Builder para customizações
$query = Product::query()->requestQuery();
// Você pode adicionar condições extras ao Builder
$query->where('company_id', auth()->user()->company_id);
return $query->get();
}
}
class Product extends Model
{
use ApiQueryBuilder;
public function category()
{
return $this->belongsTo(Category::class);
}
}
class Record extends Model
{
use ApiQueryBuilder;
public function entries()
{
return $this->hasMany(Entry::class);
}
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use PowerVending\LaravelApiQueryBuilder\Traits\ApiQueryBuilder;
class Product extends Model
{
use ApiQueryBuilder;
public function brand()
{
return $this->belongsTo(Brand::class);
}
}
// No Model
public function brand() // método em camelCase
{
return $this->belongsTo(Brand::class);
}
class Product extends Model
{
use ApiQueryBuilder;
public function category()
{
return $this->belongsTo(Category::class);
}
public function brand()
{
return $this->belongsTo(Brand::class);
}
}
class Customer extends Model
{
use ApiQueryBuilder;
public function orders()
{
return $this->hasMany(Order::class);
}
}
class Product extends Model
{
use ApiQueryBuilder;
public function reviews()
{
return $this->hasMany(Review::class);
}
}
public function index()
{
return Product::query()->requestPaginate();
}
class Customer extends Model
{
use ApiQueryBuilder;
public function orders()
{
return $this->hasMany(Order::class);
}
public function address()
{
return $this->belongsTo(Address::class);
}
}
public function index()
{
return Customer::requestPaginate();
}
namespace App\SearchCallbacks;
use PowerVending\LaravelApiQueryBuilder\SearchCallbacks\AbstractCallback;
class CustomOperator extends AbstractCallback
{
// Define o prefixo do operador
public const OPERATOR = 'CUSTOM:';
/**
* Executa a lógica do operador
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @param string $column
* @param string $value
* @return void
*/
public function __invoke($builder, string $column, string $value)
{
// Sua lógica customizada aqui
// Exemplo: busca case-sensitive
$builder->whereRaw("BINARY {$column} = ?", [$value]);
}
}
use App\SearchCallbacks\CustomOperator;
return [
'operators' => [
CustomOperator::class, // Adicione no topo (lembre da ordem!)
// ... outros operadores
],
];
class InOperator extends AbstractCallback
{
public const OPERATOR = 'IN:';
public function __invoke($builder, string $column, string $value)
{
// Espera valores separados por vírgula: "IN:1,2,3,4"
$values = explode(',', $value);
$builder->whereIn($column, $values);
}
}
class IsNullOperator extends AbstractCallback
{
public const OPERATOR = 'NULL:';
public function __invoke($builder, string $column, string $value)
{
if ($value === 'true' || $value === '1') {
$builder->whereNull($column);
} else {
$builder->whereNotNull($column);
}
}
}
public function index(Request $request)
{
// Adiciona condições adicionais
$query = Product::query()
->where('company_id', auth()->user()->company_id)
->where('is_deleted', false);
// Processa os parâmetros JSON na query existente
return $query->requestPaginate();
}
public function index(Request $request)
{
// Valida os parâmetros
$request->validate([
'search' => 'sometimes|json',
'order_by' => 'sometimes|json',
'_per_page' => 'sometimes|integer|min:1|max:100',
]);
return Product::requestPaginate();
}
namespace App\Types;
use PowerVending\LaravelApiQueryBuilder\Types\AbstractType;
use PowerVending\LaravelApiQueryBuilder\SearchParserInterface;
class JsonColumnType extends AbstractType
{
public static function name(): string
{
// Deve ser o FQCN (caminho completo) do seu cast no Model
return \App\Casts\JsonColumn::class;
}
public function prepare(array $values, ?SearchParserInterface $searchParser = null): array
{
$operator = $searchParser?->getOperator();
// Operadores de texto: mantém o valor cru para buscas parciais
if (in_array($operator, ['LIKE:', 'STARTS_WITH:', 'ENDS_WITH:'], true)) {
return $values;
}
// Operador de comparação exata (EQ): serializa o valor para JSON
return array_map(function ($value) {
return json_encode($value, JSON_THROW_ON_ERROR);
}, $values);
}
}
'types' => [
\PowerVending\LaravelApiQueryBuilder\Types\GenericType::class,
\PowerVending\LaravelApiQueryBuilder\Types\BooleanType::class,
\App\Types\JsonColumnType::class, // Registro do seu tipo customizado
],
use App\Casts\DynamicConfiguration;
use App\Casts\DynamicProperty;
use PowerVending\LaravelApiQueryBuilder\SearchCallbacks\{
Equals, Like, Between, LessThan, GreaterThan, StartsWith, EndsWith, NotEquals, NotBetween, LessThanOrEqual, GreaterThanOrEqual
};
return [
// ...
'cast_operators' => [
// Restrição para o cast de configurações dinâmicas
DynamicConfiguration::class => [
Equals::class,
Like::class,
Between::class,
LessThan::class,
GreaterThan::class,
StartsWith::class,
EndsWith::class,
NotEquals::class,
NotBetween::class,
LessThanOrEqual::class,
GreaterThanOrEqual::class,
],
// Restrição para o cast de propriedades dinâmicas
DynamicProperty::class => [
Equals::class,
Like::class,
Between::class,
LessThan::class,
GreaterThan::class,
StartsWith::class,
EndsWith::class,
NotEquals::class,
NotBetween::class,
LessThanOrEqual::class,
GreaterThanOrEqual::class,
],
],
];
'operators' => [
// MAIORES PRIMEIRO
\PowerVending\LaravelApiQueryBuilder\SearchCallbacks\StartsWith::class,
\PowerVending\LaravelApiQueryBuilder\SearchCallbacks\EndsWith::class,
// ... depois os menores
],
http
GET /api-query-builder/tickets/schema?relations[]=requester_user&relations[]=requester_operator
json
{"price": "BT:100;500"} -> WHERE price BETWEEN 100 AND 500
{"stock": "BT:10;100"} -> WHERE stock BETWEEN 10 AND 100
{"created_at": "BT:2024-01-01;2024-12-31"} -> WHERE created_at BETWEEN '2024-01-01' AND '2024-12-31'
json
{"discount": "EQ:null"} -> WHERE discount IS NULL
{"discount": "EQ:!null"} -> WHERE discount IS NOT NULL