|
2 | 2 |
|
3 | 3 | Ozu brings a nice solution to develop and maintain a static website with a dynamic content, keeping the productivity and great DX of Laravel.
|
4 | 4 |
|
5 |
| -The project is in private beta for now, but you can request an access on [its website](https://ozu.code16.fr). You can refer to this blog post to learn more about the project: [https://code16.fr/blog/en/ozu-static-websites-laravel/](https://code16.fr/blog/en/ozu-static-websites-laravel/) |
| 5 | +The project is in private beta for now, but you can request an access here: [ozu.code16.fr](https://ozu.code16.fr). You can also refer to [this blog post](https://code16.fr/posts/introducing-ozu-a-static-website-deployment-solution-for-laravel-projects/) to learn more about the project. |
6 | 6 |
|
| 7 | +## Installation |
| 8 | + |
| 9 | +Require the package: |
| 10 | + |
| 11 | +```bash |
| 12 | +composer require code16/ozu-client |
| 13 | +``` |
| 14 | + |
| 15 | +Publish the config file: |
| 16 | + |
| 17 | +```bash |
| 18 | +php artisan vendor:publish --tag="ozu-client-config" |
| 19 | +``` |
| 20 | + |
| 21 | +## Getting started |
| 22 | + |
| 23 | +### Routes, controllers, views |
| 24 | + |
| 25 | +Create your routes, controllers, views, etc. as you would do for a regular Laravel project — with a few restrictions in mind: |
| 26 | +- TODO |
| 27 | +- TODO |
| 28 | +- ... |
| 29 | + |
| 30 | +### Models are Ozu collections |
| 31 | + |
| 32 | +The Models you want to expose to Ozu (meaning: for which you want to configure the content management tool) must follow these rules: |
| 33 | + |
| 34 | +First your migration must use the `Code16\OzuClient\Support\Database\MigratesOzuTable` trait, and call `$this->createOzuTable('my-table');` in the `up()` method: this will create the table with the required columns for Ozu, and you can then add your own columns. |
| 35 | + |
| 36 | +```php |
| 37 | +use Code16\OzuClient\Support\Database\MigratesOzuTable; |
| 38 | +// ... |
| 39 | + |
| 40 | +return new class extends Migration |
| 41 | +{ |
| 42 | + use MigratesOzuTable; |
| 43 | + |
| 44 | + public function up(): void |
| 45 | + { |
| 46 | + $this->createOzuTable('projects'); |
| 47 | + |
| 48 | + Schema::table('projects', function (Blueprint $table) { |
| 49 | + $table->string('country')->nullable(); |
| 50 | + // ... |
| 51 | + }); |
| 52 | + } |
| 53 | +}; |
| 54 | +``` |
| 55 | + |
| 56 | +The base Ozu model comes with these attributes: |
| 57 | +- `title` |
| 58 | +- `content` |
| 59 | +- `slug` (automatically filled from the title) |
| 60 | +- `order` |
| 61 | +- `cover` (as a `Media`, see below) |
| 62 | + |
| 63 | +Second your Model must implement the `Code16\OzuClient\Eloquent\IsOzuModel` trait, and implement 3 static methods: |
| 64 | + |
| 65 | +- `configureOzuCollection` is where you can define the collection's label, icon, and some options like the publication state, the creatable state, and the deletable state. |
| 66 | +- `configureOzuCollectionList` is where you can define the columns to display in the list view. |
| 67 | +- `configureOzuCollectionForm` is where you can define the custom fields to display in the form view. |
| 68 | + |
| 69 | +Here's an example for a `Project` Model with one additional field (`country`) and some basic configuration: |
| 70 | + |
| 71 | +```php |
| 72 | +use Code16\OzuClient\Eloquent\IsOzuModel; |
| 73 | +// ... |
| 74 | + |
| 75 | +class Project extends Model |
| 76 | +{ |
| 77 | + use IsOzuModel; |
| 78 | + |
| 79 | + // ... |
| 80 | + |
| 81 | + public static function configureOzuCollection(OzuCollectionConfig $config): OzuCollectionConfig |
| 82 | + { |
| 83 | + return $config |
| 84 | + ->setLabel('Projects') |
| 85 | + ->setIcon('fa-ruler-combined') |
| 86 | + ->setHasPublicationState() |
| 87 | + ->setIsCreatable() |
| 88 | + ->setIsDeletable(false); |
| 89 | + } |
| 90 | + |
| 91 | + public static function configureOzuCollectionList(OzuCollectionListConfig $config): OzuCollectionListConfig |
| 92 | + { |
| 93 | + return $config |
| 94 | + ->addColumn(OzuColumn::makeImage('cover', 1)) |
| 95 | + ->addColumn(OzuColumn::makeText('title', 5)->setLabel('Title')) |
| 96 | + ->addColumn(OzuColumn::makeText('country', 6)->setLabel('Country')) |
| 97 | + ->setIsSearchable() |
| 98 | + ->setIsReorderable(); |
| 99 | + } |
| 100 | + |
| 101 | + public static function configureOzuCollectionForm(OzuCollectionFormConfig $config): OzuCollectionFormConfig |
| 102 | + { |
| 103 | + return $config |
| 104 | + ->addCustomField( |
| 105 | + OzuField::makeText('country') |
| 106 | + ->setLabel('Country') |
| 107 | + ->setValidationRules(['required']) |
| 108 | + ); |
| 109 | + } |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +> [!NOTE] |
| 114 | +> This configuration will be used by Ozu to properly display the collection in the content management tool. It has no effect in your local codebase. |
| 115 | +
|
| 116 | +### Attachments and visuals are `Media`s |
| 117 | + |
| 118 | +If you want to attach images to your Models, leverage the `Code16\OzuClient\Eloquent\Media` model via a `MorphOne` or a `MorphMany` relation: |
| 119 | + |
| 120 | +```php |
| 121 | +use Code16\OzuClient\Eloquent\Media; |
| 122 | +// ... |
| 123 | + |
| 124 | +class Project extends Model |
| 125 | +{ |
| 126 | + use IsOzuModel; |
| 127 | + |
| 128 | + public function visuals(): MorphMany |
| 129 | + { |
| 130 | + return $this->morphMany(Media::class, 'model') |
| 131 | + ->where('model_key', 'visuals') |
| 132 | + ->orderBy('order'); |
| 133 | + } |
| 134 | + |
| 135 | + public function ogImage(): MorphOne |
| 136 | + { |
| 137 | + return $this->morphOne(Media::class, 'model') |
| 138 | + ->where('model_key', 'ogImage'); |
| 139 | + } |
| 140 | + |
| 141 | + // ... |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +You must define the `model_key` in the relation to differentiate the different types of media you can attach to your models. |
| 146 | + |
| 147 | +You can then use this relation in your views to display the images, and leverage the `thumbnail()` method to get the URL of the image in the desired size: |
| 148 | + |
| 149 | +```php |
| 150 | +@if(count($project->visuals)) |
| 151 | + <div class="mt-12"> |
| 152 | + <div class="grid sm:grid-cols-3 grid-cols-2 gap-4"> |
| 153 | + @foreach($project->visuals as $visual) |
| 154 | + <img class="aspect-square" src="{{ $visual->thumbnail(400, fit: true) }}" alt=""> |
| 155 | + @endforeach |
| 156 | + </div> |
| 157 | + </div> |
| 158 | +@endif |
| 159 | +``` |
| 160 | + |
| 161 | +### Local (dev) seeder |
| 162 | + |
| 163 | +To ease the development of your project, you can use the `OzuSeeder` class to seed your local database with some dummy data: |
| 164 | + |
| 165 | +```php |
| 166 | +use Code16\OzuClient\Support\Database\OzuSeeder; |
| 167 | +// ... |
| 168 | + |
| 169 | +class DatabaseSeeder extends OzuSeeder |
| 170 | +{ |
| 171 | + public function run(): void |
| 172 | + { |
| 173 | + // this will delete any remaining seeded Media file |
| 174 | + $this->clearMediaDirectory(); |
| 175 | + |
| 176 | + Project::factory() |
| 177 | + ->count(12) |
| 178 | + ->has(Media::factory()->image('cover')->withFile(), 'cover') |
| 179 | + ->has(Media::factory()->image('visuals')->withFile()->count(3), 'visuals') |
| 180 | + ->sequence(fn ($sequence) => [ |
| 181 | + 'order' => $sequence->index + 1, |
| 182 | + 'country' => fake()->country(), |
| 183 | + ]) |
| 184 | + ->create(); |
| 185 | + |
| 186 | + // ... |
| 187 | + } |
| 188 | +} |
| 189 | +``` |
| 190 | + |
| 191 | +## Go for production |
| 192 | + |
| 193 | +Once your project is ready, you can deploy it to Ozu. |
| 194 | + |
| 195 | +### Configure the project in Ozu |
| 196 | + |
| 197 | +First declare your Ozu collection in the `config/ozu-client` configuration file: |
| 198 | + |
| 199 | +```bash |
| 200 | +php artisan vendor:publish --tag="ozu-client-config" |
| 201 | +``` |
| 202 | + |
| 203 | +```php |
| 204 | +// config/ozu-client.php |
| 205 | + |
| 206 | +return [ |
| 207 | + // ... |
| 208 | + 'collections' => [ |
| 209 | + App\Models\Project::class, |
| 210 | + // ... |
| 211 | + ], |
| 212 | +]; |
| 213 | +``` |
| 214 | + |
| 215 | +Next you need to configure your credentials in the `.env` file: |
| 216 | + |
| 217 | +```dotenv |
| 218 | +OZU_API_KEY=[your-api-key] |
| 219 | +OZU_WEBSITE_KEY=[your-website-key] |
| 220 | +``` |
| 221 | + |
| 222 | +Then launch the `ozu:configure-cms` command: |
| 223 | + |
| 224 | +```bash |
| 225 | +php artisan ozu:configure-cms |
| 226 | +``` |
| 227 | + |
| 228 | +This command will create a new collection in Ozu for each of your declared Models, and will configure the lists and forms according to the methods you defined in your Models. You must repeat this command each time you add or update an Ozu Model. |
| 229 | + |
| 230 | +At this stage, you should be able to see your custom CMS at the address https://ozu.code16.fr/sharp. Here you can manage the content of your collections. |
| 231 | + |
| 232 | +> [!NOTE] |
| 233 | +> For now there is no way to seed production data, but it's in the roadmap. |
| 234 | +
|
| 235 | +### Deploy your project |
| 236 | + |
| 237 | +To deploy your project in the actual production space, you'll need a few more steps: |
| 238 | + |
| 239 | +- attach you Github repository to your Ozu project |
| 240 | +- Netlify |
| 241 | +- ... |
0 commit comments