code16/sharp
Code-driven CMS framework for Laravel (PHP 8.3+/Laravel 11+). Build admin/CMS sections with a clean UI and strong DX: CRUD with validation, search/sort/filter, bulk or custom commands, and authorization—no front-end code required, data-agnostic.
Installation:
composer require code16/sharp
php artisan vendor:publish --tag=sharp-assets --force
php artisan migrate
Configure Provider:
Create a service provider extending SharpAppServiceProvider:
// app/Providers/SharpServiceProvider.php
use Code16\Sharp\SharpAppServiceProvider;
class SharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->setName('My CMS')
->declareEntity(\App\Sharp\Entities\PostEntity::class);
}
}
Define an Entity:
// app/Sharp/Entities/PostEntity.php
use Code16\Sharp\Entities\Entity;
class PostEntity extends Entity
{
public static function fields(): array
{
return [
'title' => 'string',
'content' => 'markdown',
'published_at' => 'datetime',
];
}
}
Route Access:
Add to routes/web.php:
use Code16\Sharp\SharpRoutes;
SharpRoutes::register();
Create a CRUD interface for PostEntity with zero frontend code:
php artisan sharp:make:entity Post
This generates a fully functional admin panel at /sharp/posts.
Field Types: Use built-in types (string, markdown, datetime, relationship, autocomplete, etc.) or extend with custom fields.
public static function fields(): array
{
return [
'author' => 'relationship:users',
'tags' => 'autocomplete:tags',
];
}
Validation: Define rules in rules() method:
public static function rules(): array
{
return [
'title' => 'required|max:255',
'content' => 'required',
];
}
Actions: Add custom actions to lists/forms:
public static function listActions(): array
{
return [
'publish' => 'Publish',
'archive' => 'Archive',
];
}
configureSharp:
$config->enableGlobalSearch(\App\Sharp\AppSearchEngine::class, 'Search...');
public static function filters(): array
{
return [
'published' => 'boolean',
'author' => 'relationship:users',
];
}
authorize():
public static function authorize(): array
{
return [
'create' => 'can:create-posts',
'update' => 'can:edit-posts',
];
}
EntityCommand:
class PublishPostsCommand extends EntityCommand
{
use Code16\Sharp\Commands\Traits\PublishPostsCommandTrait;
}
class ImportPostsWizard extends WizardCommand
{
use Code16\Sharp\Commands\Traits\ImportPostsWizardTrait;
}
protected static function model(): string
{
return \App\Models\Post::class;
}
query() in entities:
public static function query(): Builder
{
return parent::query()->where('status', 'active');
}
Conditional Fields: Use visible()/hidden():
public static function fields(): array
{
return [
'excerpt' => 'string|visible:isPreview',
];
}
Dynamic Forms: Extend FormBuilder:
public function buildForm(FormBuilder $builder): void
{
if ($builder->isEditing()) {
$builder->addField('previous_version', 'relationship:posts');
}
}
SharpRoutes::register(['api' => true]);
ApiResource:
class PostApiResource extends ApiResource
{
public function toArray($request, Post $post): array
{
return [
'title' => $post->title,
'slug' => Str::slug($post->title),
];
}
}
php artisan vendor:publish --tag=sharp-assets --force
vendor/code16/sharp/resources/views to resources/views/vendor/sharp.$config->setMiddleware([
'common' => [
\App\Http\Middleware\SetTenant::class,
],
]);
Middleware Order:
SubstituteBindings after HandleGlobalFilters in common middleware.SetSharpLocale from api middleware group (Sharp 9+ uses Inertia).Icon Migration:
blade-icons. Update icons from fas fa-user to fas-user.owenvoke/blade-fontawesome if you need legacy FontAwesome support.Asset Caching:
php artisan view:clear and php artisan vendor:publish --tag=sharp-assets --force after updates.Entity Declaration:
$config->declareEntity(PostEntity::class)
->declareEntity(AuthorEntity::class);
2FA Quirks:
enable2faByTotp(), ensure two_factor_secret is stored as a base32-encoded string.two_factor_recovery_codes field.Inertia Integration:
app/Http/Middleware/HandleInertiaRequests is configured:public function rootView(): string
{
return config('sharp.inertia_root_view', 'app');
}
Log Sharp Events:
Enable Sharp’s debug mode in configureSharp:
$config->setDebug(true);
Or use Laravel’s logging:
\Log::debug('Sharp event:', ['event' => $event]);
Check Entity Resolution:
php artisan sharp:list to verify registered entities.configureSharp.Validation Errors:
storage/logs/laravel.log for validation messages.rules() or use validate() in custom commands:public function handle(): void
{
$this->validate([
'title' => 'required|unique:posts',
]);
}
Permission Denied:
php artisan gate:list
authorize() methods in entities.Asset Loading Issues:
php artisan cache:clear
php artisan view:clear
php artisan config:clear
sharp-assets are published to public/vendor/sharp.Custom Field Types:
Code16\Sharp\Fields\Field:class RichTextField extends Field
{
public function render(FieldRenderer $renderer): string
{
return $renderer->renderTrixEditor($this);
}
}
Custom Search Engines:
Code16\Sharp\Search\SearchEngineInterface:class AlgoliaSearchEngine implements SearchEngineInterface
{
public function search(string $query, array $filters): array
{
return Algolia::search($
How can I help you explore Laravel packages today?