├── src ├── ServiceProvider.php ├── Utils.php ├── Commands │ └── RunFactory.php ├── Mapper.php └── Factory.php ├── LICENSE.md ├── config └── factory.php ├── composer.json └── README.md /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | $value) { 17 | if (is_array($value)) { 18 | $output[$key] = self::array_map_recursive($value, $callback); 19 | } else { 20 | $output[$key] = $callback($value, $key); 21 | } 22 | } 23 | 24 | return $output; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Michael Aerni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /config/factory.php: -------------------------------------------------------------------------------- 1 | true, 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Title Fallback Settings 22 | |-------------------------------------------------------------------------- 23 | | 24 | | These title settings will function as a fallback to create titles for 25 | | your collection entries and taxonomy terms, if you didn't explicitly set 26 | | a 'title' field in the respective blueprint. 27 | | 28 | | 'chars': The character count of the title will be in this range. 29 | | 'real_text': Use real english words instead of Lorem Ipsum. 30 | | 31 | */ 32 | 33 | 'title' => [ 34 | 'chars' => [$min = 20, $max = 30], 35 | 'real_text' => true, 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aerni/factory", 3 | "description": "Quickly whip up fake content", 4 | "keywords": [ 5 | "statamic", 6 | "factory" 7 | ], 8 | "homepage": "https://github.com/aerni/statamic-factory", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Michael Aerni", 13 | "email": "hello@michaelaerni.ch", 14 | "homepage": "https://www.michaelaerni.ch", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.1", 20 | "fakerphp/faker": "^1.23.0", 21 | "laravel/prompts": "^0.1.17", 22 | "statamic/cms": "^5.0", 23 | "stillat/primitives": "^2.0" 24 | }, 25 | "require-dev": { 26 | "orchestra/testbench": "^8.0|^9.0", 27 | "phpunit/phpunit": "^10.0" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Aerni\\Factory\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Aerni\\Factory\\Tests\\": "tests" 37 | }, 38 | "classmap": [ 39 | "tests/TestCase.php" 40 | ] 41 | }, 42 | "scripts": { 43 | "test": "vendor/bin/phpunit", 44 | "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" 45 | }, 46 | "config": { 47 | "optimize-autoloader": true, 48 | "preferred-install": "dist", 49 | "sort-packages": true, 50 | "allow-plugins": { 51 | "pixelfear/composer-dist-plugin": true 52 | } 53 | }, 54 | "extra": { 55 | "statamic": { 56 | "name": "Factory", 57 | "description": "Quicly whip up fake content" 58 | }, 59 | "laravel": { 60 | "providers": [ 61 | "Aerni\\Factory\\ServiceProvider" 62 | ] 63 | } 64 | }, 65 | "minimum-stability": "dev", 66 | "prefer-stable": true 67 | } 68 | -------------------------------------------------------------------------------- /src/Commands/RunFactory.php: -------------------------------------------------------------------------------- 1 | 'Entry', 42 | 'term' => 'Term', 43 | 'global' => 'Global', 44 | ], 45 | validate: fn (string $value) => match ($value) { 46 | 'entry' => Collection::all()->isEmpty() 47 | ? 'You need to create at least one collection to use the factory.' 48 | : null, 49 | 'term' => Taxonomy::all()->isEmpty() 50 | ? 'You need to create at least one taxonomy to use the factory.' 51 | : null, 52 | 'global' => GlobalSet::all()->isEmpty() 53 | ? 'You need to create at least one global set to use the factory.' 54 | : null, 55 | }, 56 | ); 57 | 58 | match ($type) { 59 | 'entry' => $this->runEntryFactory(), 60 | 'term' => $this->runTermFactory(), 61 | 'global' => $this->runGlobalFactory(), 62 | }; 63 | 64 | info('The content was successfully created!'); 65 | } 66 | 67 | protected function runEntryFactory(): void 68 | { 69 | $collections = Collection::all(); 70 | 71 | $handle = $this->selectContent('Select the collection for which you want to create entries.', $collections); 72 | 73 | $blueprint = select( 74 | label: 'Select the blueprint to use for creating the entries.', 75 | options: $collections->firstWhere('handle', $handle) 76 | ->entryBlueprints() 77 | ->mapWithKeys(fn ($blueprint) => [$blueprint->handle() => $blueprint->title()]), 78 | ); 79 | 80 | $amount = $this->selectAmount('How many entries do you want to create?'); 81 | 82 | Factory::run('entry', $handle, $blueprint, $amount); 83 | } 84 | 85 | protected function runTermFactory(): void 86 | { 87 | $taxonomies = Taxonomy::all(); 88 | 89 | $handle = $this->selectContent('Select the taxonomy for which you want to create terms.', $taxonomies); 90 | 91 | $blueprint = select( 92 | label: 'Select the blueprint to use for creating the terms.', 93 | options: $taxonomies->firstWhere('handle', $handle) 94 | ->termBlueprints() 95 | ->mapWithKeys(fn ($blueprint) => [$blueprint->handle() => $blueprint->title()]), 96 | ); 97 | 98 | $amount = $this->selectAmount('How many terms do you want to create?'); 99 | 100 | Factory::run('term', $handle, $blueprint, $amount); 101 | } 102 | 103 | protected function runGlobalFactory(): void 104 | { 105 | $globals = GlobalSet::all(); 106 | 107 | $handle = $this->selectContent('Select the global set you want to run the factory on.', $globals); 108 | 109 | $blueprint = $globals->firstWhere(fn ($global) => $global->handle() === $handle)->blueprint(); 110 | 111 | if (is_null($blueprint)) { 112 | error('The selected global set has no blueprint. Create a blueprint to use the factory.'); 113 | exit; 114 | } 115 | 116 | Factory::run('global', $handle, $blueprint, 1); 117 | } 118 | 119 | protected function selectContent(string $label, LaravelCollection $options): string 120 | { 121 | return select( 122 | label: $label, 123 | options: $options->mapWithKeys(fn ($option) => [$option->handle() => $option->title()]), 124 | ); 125 | } 126 | 127 | protected function selectAmount(string $label): int 128 | { 129 | return text( 130 | label: $label, 131 | default: 1, 132 | validate: fn (string $value) => match (true) { 133 | ! is_numeric($value) => 'The value must be a number.', 134 | $value < 1 => 'The value must be at least 1.', 135 | default => null 136 | } 137 | ); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Mapper.php: -------------------------------------------------------------------------------- 1 | flatMap(function ($item) { 17 | if ($this->isSpecialFieldtype($item)) { 18 | return $this->handleSpecialFieldtype($item); 19 | } 20 | 21 | return $this->mapSimple($item); 22 | })->toArray(); 23 | } 24 | 25 | /** 26 | * Handle special fieldtype. 27 | */ 28 | protected function handleSpecialFieldtype(array $item): array 29 | { 30 | if ($item['field']['type'] === 'grid') { 31 | return $this->mapGrid($item); 32 | } 33 | 34 | if ($item['field']['type'] === 'bard') { 35 | return $this->mapBardAndReplicator($item); 36 | } 37 | 38 | if ($item['field']['type'] === 'replicator') { 39 | return $this->mapBardAndReplicator($item); 40 | } 41 | 42 | if ($item['field']['type'] === 'table') { 43 | return $this->mapTable($item); 44 | } 45 | } 46 | 47 | /** 48 | * Map bard and replicator fieldtype to its expected data structure. 49 | */ 50 | protected function mapBardAndReplicator(array $item): array 51 | { 52 | $handle = $item['handle']; 53 | $sets = $item['field']['sets']; 54 | 55 | $setCount = collect($sets)->map(function ($item, $key) { 56 | $minSets = $item['factory']['min_sets']; 57 | $maxSets = $item['factory']['max_sets']; 58 | 59 | return random_int($minSets, $maxSets); 60 | })->toArray(); 61 | 62 | $sets = collect($item['field']['sets'])->map(function ($set, $key) { 63 | $fields = collect($set['fields'])->flatMap(function ($item) { 64 | return $this->mapItems([$item]); 65 | }); 66 | 67 | return $fields->merge([ 68 | 'type' => $key, 69 | 'enabled' => true, 70 | ]); 71 | })->toArray(); 72 | 73 | $items = collect($sets)->flatMap(function ($set, $key) use ($setCount, $sets) { 74 | $items = []; 75 | 76 | for ($i = 0; $i < $setCount[$key]; $i++) { 77 | array_push($items, $sets[$key]); 78 | } 79 | 80 | return $items; 81 | })->toArray(); 82 | 83 | return [ 84 | $handle => $items, 85 | ]; 86 | } 87 | 88 | /** 89 | * Map grid fieldtype to its expected data structure. 90 | */ 91 | protected function mapGrid(array $item): array 92 | { 93 | $handle = $item['handle']; 94 | 95 | $minRows = $item['field']['factory']['min_rows']; 96 | $maxRows = $item['field']['factory']['max_rows']; 97 | $rowCount = random_int($minRows, $maxRows); 98 | 99 | $fields = collect($item['field']['fields'])->flatMap(function ($item) { 100 | return $this->mapItems([$item]); 101 | })->toArray(); 102 | 103 | $grid = [ 104 | $handle => [], 105 | ]; 106 | 107 | for ($i = 0; $i < $rowCount; $i++) { 108 | array_push($grid[$handle], $fields); 109 | } 110 | 111 | return $grid; 112 | } 113 | 114 | /** 115 | * Map table fieldtype to its expected data structure. 116 | */ 117 | protected function mapTable(array $item): array 118 | { 119 | $handle = $item['handle']; 120 | 121 | $minRows = $item['field']['factory']['min_rows']; 122 | $maxRows = $item['field']['factory']['max_rows']; 123 | $minCells = $item['field']['factory']['min_cells']; 124 | $maxCells = $item['field']['factory']['max_cells']; 125 | $rowCount = random_int($minRows, $maxRows); 126 | $cellCount = random_int($minCells, $maxCells); 127 | 128 | $formatter = $this->formatter($item); 129 | 130 | $table = [ 131 | $handle => [], 132 | ]; 133 | 134 | for ($i = 0; $i < $rowCount; $i++) { 135 | array_push($table[$handle], [ 136 | 'cells' => [], 137 | ]); 138 | } 139 | 140 | $table[$handle] = array_map(function ($item) use ($cellCount, $formatter) { 141 | for ($i = 0; $i < $cellCount; $i++) { 142 | array_push($item['cells'], $formatter); 143 | } 144 | 145 | return $item; 146 | }, $table[$handle]); 147 | 148 | return $table; 149 | } 150 | 151 | /** 152 | * Map a simple fieldtype to its expected data structure. 153 | */ 154 | protected function mapSimple(array $item): array 155 | { 156 | return [ 157 | $item['handle'] => $this->formatter($item), 158 | ]; 159 | } 160 | 161 | /** 162 | * Get the faker formatter from an item. 163 | */ 164 | protected function formatter(array $item): string 165 | { 166 | if (is_array($item['field']['factory'])) { 167 | return $item['field']['factory']['formatter']; 168 | } 169 | 170 | return $item['field']['factory']; 171 | } 172 | 173 | /** 174 | * Check if the item is a fieldtype that needs special handling. 175 | */ 176 | protected function isSpecialFieldtype(array $item): bool 177 | { 178 | $specialFieldtypes = ['bard', 'grid', 'replicator', 'table']; 179 | 180 | if (in_array($item['field']['type'], $specialFieldtypes)) { 181 | return true; 182 | } 183 | 184 | return false; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Statamic](https://flat.badgen.net/badge/Statamic/4.0+/FF269E) ![Packagist version](https://flat.badgen.net/packagist/v/aerni/factory/latest) ![Packagist Total Downloads](https://flat.badgen.net/packagist/dt/aerni/factory) 2 | 3 | # Factory 4 | 5 | This addon provides an easy way to quickly whip up fake data for your `Collection Entries`, `Taxonomy Terms` and `Globals` using [Faker](https://github.com/FakerPHP/Faker). 6 | 7 | 8 | ## Installation 9 | Install the addon using Composer: 10 | 11 | ```bash 12 | composer require aerni/factory 13 | ``` 14 | 15 | Publish the config of the package: 16 | 17 | ```bash 18 | php please vendor:publish --tag=factory-config 19 | ``` 20 | 21 | The following config will be published to `config/factory.php`: 22 | 23 | ```php 24 | return [ 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Publish Status 29 | |-------------------------------------------------------------------------- 30 | | 31 | | The publish status of collection entries and taxonomy terms 32 | | created by the factory. 33 | | 34 | | Tip: Randomize the status by setting this to '(bool) random_int(0, 1)'. 35 | | 36 | */ 37 | 38 | 'published' => true, 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Title Fallback Settings 43 | |-------------------------------------------------------------------------- 44 | | 45 | | These title settings will function as a fallback to create titles for 46 | | your collection entries and taxonomy terms, if you didn't explicitly set 47 | | a 'title' field in the respective blueprint. 48 | | 49 | | 'chars': The character count of the title will be in this range. 50 | | 'real_text': Use real english words instead of Lorem Ipsum. 51 | | 52 | */ 53 | 54 | 'title' => [ 55 | 'chars' => [$min = 20, $max = 30], 56 | 'real_text' => true, 57 | ], 58 | 59 | ]; 60 | ``` 61 | 62 | ## Basic Usage 63 | 64 | Before you go crazy whipping up fake goodies, you need to let the Factory know what fields you want it to create. You do so by defining a `factory` key on each field in your blueprint that you want to fake. The value of the key is a Faker formatter for simple fieldtypes and an array of options for advanced fieldtypes like a grid. Please consult the [Faker Documentation](https://github.com/FakerPHP/Faker) for available formatters. 65 | 66 | This is an example blueprint for a collection of people: 67 | ```yaml 68 | title: Person 69 | sections: 70 | main: 71 | display: Main 72 | fields: 73 | - 74 | handle: first_name 75 | field: 76 | type: text 77 | factory: firstName 78 | - 79 | handle: last_name 80 | field: 81 | type: text 82 | factory: lastName 83 | - 84 | handle: age 85 | field: 86 | type: number 87 | factory: numberBetween(20, 50) 88 | - 89 | handle: bio 90 | field: 91 | type: textarea 92 | factory: paragraph(3, true) 93 | ``` 94 | 95 | Run the factory in your terminal and follow the instructions: 96 | 97 | ```bash 98 | php please factory 99 | ``` 100 | 101 | ## Special Fieldtypes 102 | 103 | The above example works great for basic fieldtypes. But what about Bard, Replicator, Grid and Tables? I'm glad you asked. To fake content for these "Special Fieldtypes" you need to change the blueprint according to the examples below. 104 | 105 | ### Bard & Replicator 106 | `min_sets` defines the minimum number of sets to create. 107 | `max_sets` defines the maximum number of sets to create. 108 | 109 | ```yaml 110 | title: 'Bard & Replicator' 111 | sections: 112 | main: 113 | display: Main 114 | fields: 115 | - 116 | handle: replicator 117 | field: 118 | type: replicator 119 | sets: 120 | text: 121 | display: Text 122 | factory: 123 | min_sets: 1 124 | max_sets: 3 125 | fields: 126 | - 127 | handle: text 128 | field: 129 | type: text 130 | factory: word 131 | - 132 | handle: textarea 133 | field: 134 | type: textarea 135 | factory: 'paragraph(3, true)' 136 | 137 | ``` 138 | 139 | ### Grid 140 | `min_rows` defines the minimum number of rows to create. 141 | `max_rows` defines the maximum number of rows to create. 142 | 143 | ```yaml 144 | title: Table 145 | sections: 146 | main: 147 | display: Main 148 | fields: 149 | - 150 | handle: grid 151 | field: 152 | type: grid 153 | factory: 154 | min_rows: 1 155 | max_rows: 4 156 | fields: 157 | - 158 | handle: first_name 159 | field: 160 | type: text 161 | factory: firstName 162 | - 163 | handle: last_name 164 | field: 165 | type: text 166 | factory: lastName 167 | ``` 168 | 169 | ### Table 170 | `min_rows` defines the minimum number of rows you want to create. 171 | `max_rows` defines the maximum number of rows you want to create. 172 | `min_cells` defines the minimum number of cells you want to create. 173 | `max_cells` defines the maximum number of cells you want to create. 174 | `formatter` defines the faker formatter to use. 175 | 176 | ```yaml 177 | title: Table 178 | sections: 179 | main: 180 | display: Main 181 | fields: 182 | - 183 | handle: table 184 | field: 185 | type: table 186 | factory: 187 | min_rows: 1 188 | max_rows: 3 189 | min_cells: 3 190 | max_cells: 5 191 | formatter: word 192 | ``` 193 | -------------------------------------------------------------------------------- /src/Factory.php: -------------------------------------------------------------------------------- 1 | faker = $faker; 92 | $this->mapper = $mapper; 93 | $this->parser = $parser; 94 | $this->runner = $runner; 95 | 96 | $this->config = config('factory'); 97 | } 98 | 99 | /** 100 | * Run the factory. 101 | */ 102 | public function run(string $contentType, string $contentHandle, string $blueprintHandle, int $amount): void 103 | { 104 | $this->contentType = $contentType; 105 | $this->contentHandle = $contentHandle; 106 | $this->blueprintHandle = $blueprintHandle; 107 | $this->amount = $amount; 108 | 109 | $this->makeContent(); 110 | } 111 | 112 | /** 113 | * Get the fakeable items from the blueprint. 114 | */ 115 | protected function fakeableItems(): array 116 | { 117 | $blueprintItems = $this->blueprint()->fields()->items(); 118 | $filtered = $this->filterItems($blueprintItems); 119 | $mapped = $this->mapper->mapItems($filtered); 120 | 121 | return $mapped; 122 | } 123 | 124 | protected function blueprint(): \Statamic\Fields\Blueprint 125 | { 126 | if ($this->contentType === 'entry') { 127 | return Blueprint::find("collections/{$this->contentHandle}/{$this->blueprintHandle}"); 128 | } 129 | 130 | if ($this->contentType === 'term') { 131 | return Blueprint::find("taxonomies/{$this->contentHandle}/{$this->blueprintHandle}"); 132 | } 133 | 134 | if ($this->contentType === 'global') { 135 | return Blueprint::find("globals/{$this->contentHandle}"); 136 | } 137 | } 138 | 139 | /** 140 | * Filter the blueprint items. 141 | */ 142 | protected function filterItems(Collection $items): array 143 | { 144 | return $items->map(function ($item) { 145 | if ($this->isBardOrReplicator($item)) { 146 | $item['field']['sets'] = $this->sets($item) 147 | ->map(function ($set) { 148 | $set['fields'] = $this->filterItems($this->fields($set)); 149 | 150 | return $set; 151 | }) 152 | ->filter(function ($set) { 153 | return $this->hasFactory($set) && $this->hasFields($set); 154 | })->toArray(); 155 | } 156 | 157 | if ($this->isGrid($item)) { 158 | $item['field']['fields'] = $this->filterItems($this->fields($item)); 159 | } 160 | 161 | return $item; 162 | })->filter(function ($item) { 163 | if ($this->isBardOrReplicator($item)) { 164 | return $this->hasSets($item); 165 | } 166 | 167 | if ($this->isGrid($item)) { 168 | return $this->hasFactory($item) && $this->hasFields($item); 169 | } 170 | 171 | return $this->hasFactory($item); 172 | })->toArray(); 173 | } 174 | 175 | /** 176 | * Get the fields or an empty array. 177 | */ 178 | protected function fields(array $item): Collection 179 | { 180 | if (array_key_exists('field', $item)) { 181 | return collect($item['field']['fields'] ?? []); 182 | } 183 | 184 | if (array_key_exists('fields', $item)) { 185 | return collect($item['fields'] ?? []); 186 | } 187 | } 188 | 189 | /** 190 | * Collect the sets from an item. 191 | */ 192 | protected function sets(array $item): Collection 193 | { 194 | return collect($item['field']['sets'] ?? []); 195 | } 196 | 197 | /** 198 | * Make content based on its type. 199 | */ 200 | protected function makeContent(): void 201 | { 202 | if ($this->contentType === 'Asset') { 203 | $this->makeAsset($this->amount); 204 | } 205 | 206 | if ($this->contentType === 'entry') { 207 | $this->makeEntry($this->amount); 208 | } 209 | 210 | if ($this->contentType === 'global') { 211 | $this->makeGlobal(); 212 | } 213 | 214 | if ($this->contentType === 'term') { 215 | $this->makeTerm($this->amount); 216 | } 217 | } 218 | 219 | /** 220 | * TODO: Fakers image implementation is unstable. Use another implementation to create fake images. 221 | * TODO: Make image creation optional and instead focus on creating fake data for existing assets based on the container's blueprint. 222 | * 223 | * Create $amount of assets with fake data. 224 | */ 225 | protected function makeAsset(int $amount): void 226 | { 227 | $diskPath = AssetContainer::find($this->contentHandle)->diskPath(); 228 | 229 | for ($i = 0; $i < $amount; $i++) { 230 | $fakeData = $this->fakeData(); 231 | 232 | $image = $this->faker->image( 233 | $diskPath, 234 | $this->config['assets']['width'], 235 | $this->config['assets']['height'], 236 | $this->config['assets']['category'], 237 | false 238 | ); 239 | 240 | Asset::findById($this->contentHandle.'::'.$image) 241 | ->data($fakeData) 242 | ->save(); 243 | } 244 | } 245 | 246 | /** 247 | * Create $amount of entries with fake data. 248 | */ 249 | protected function makeEntry(int $amount): void 250 | { 251 | for ($i = 0; $i < $amount; $i++) { 252 | $fakeData = collect([ 253 | 'title' => $this->title(), 254 | ])->merge($this->fakeData()); 255 | 256 | Entry::make() 257 | ->collection($this->contentHandle) 258 | ->blueprint($this->blueprintHandle) 259 | ->locale(Site::default()->handle()) 260 | ->published($this->config['published']) 261 | ->slug(Str::slug($fakeData['title'])) 262 | ->data($fakeData) 263 | ->set('updated_by', User::all()->random()->id()) 264 | ->set('updated_at', now()->timestamp) 265 | ->save(); 266 | } 267 | } 268 | 269 | /** 270 | * Fill the global set with fake data. 271 | */ 272 | protected function makeGlobal(): void 273 | { 274 | GlobalSet::findByHandle($this->contentHandle) 275 | ->inDefaultSite() 276 | ->data($this->fakeData()) 277 | ->save(); 278 | } 279 | 280 | /** 281 | * Create $amount of terms with fake data. 282 | */ 283 | protected function makeTerm(int $amount): void 284 | { 285 | for ($i = 0; $i < $amount; $i++) { 286 | $fakeData = collect([ 287 | 'title' => $this->title(), 288 | ])->merge($this->fakeData()); 289 | 290 | Term::make() 291 | ->taxonomy($this->contentHandle) 292 | ->blueprint($this->blueprintHandle) 293 | ->slug(Str::slug($fakeData['title'])) 294 | ->data($fakeData) 295 | ->set('updated_by', User::all()->random()->id()) 296 | ->set('updated_at', now()->timestamp) 297 | ->save(); 298 | } 299 | } 300 | 301 | /** 302 | * Create fake data for the fakeable items. 303 | */ 304 | protected function fakeData(): array 305 | { 306 | return Utils::array_map_recursive($this->fakeableItems(), function ($value, $key) { 307 | if ($this->isFakerFormatter($value, $key)) { 308 | return $this->fakeItem($value); 309 | } 310 | 311 | return $value; 312 | }); 313 | } 314 | 315 | /** 316 | * Create fake data with the given Faker formatter. 317 | * 318 | * @return mixed 319 | */ 320 | protected function fakeItem(string $fakerFormatter) 321 | { 322 | return $this->runner->run( 323 | $this->parser->parseMethods($fakerFormatter), 324 | $this->faker 325 | ); 326 | } 327 | 328 | /** 329 | * Create a fake title. 330 | */ 331 | protected function title(): string 332 | { 333 | $realText = $this->config['title']['real_text']; 334 | $minChars = $this->config['title']['chars'][0]; 335 | $maxChars = $this->config['title']['chars'][1]; 336 | 337 | if ($realText) { 338 | $title = $this->faker->realText($this->faker->numberBetween($minChars, $maxChars)); 339 | 340 | return Str::removeRight($title, '.'); 341 | } 342 | 343 | $title = $this->faker->text($this->faker->numberBetween($minChars, $maxChars)); 344 | 345 | return Str::removeRight($title, '.'); 346 | } 347 | 348 | /** 349 | * Check if an item is of fieldtype bard or replicator. 350 | */ 351 | protected function isBardOrReplicator(array $item): bool 352 | { 353 | if ($item['field']['type'] === 'bard') { 354 | return true; 355 | } 356 | 357 | if ($item['field']['type'] === 'replicator') { 358 | return true; 359 | } 360 | 361 | return false; 362 | } 363 | 364 | /** 365 | * Check if an item is of fieldtype grid. 366 | */ 367 | protected function isGrid(array $item): bool 368 | { 369 | if ($item['field']['type'] === 'grid') { 370 | return true; 371 | } 372 | 373 | return false; 374 | } 375 | 376 | /** 377 | * Check if an item has factory key. 378 | */ 379 | protected function hasFactory(array $item): bool 380 | { 381 | if (array_key_exists('field', $item)) { 382 | return collect($item['field'])->has('factory'); 383 | } 384 | 385 | if (array_key_exists('factory', $item)) { 386 | return collect($item)->has('factory'); 387 | } 388 | 389 | return false; 390 | } 391 | 392 | /** 393 | * Check if an item has fields. 394 | */ 395 | protected function hasFields(array $item): bool 396 | { 397 | if (array_key_exists('field', $item)) { 398 | return collect($item['field']['fields'])->isNotEmpty(); 399 | } 400 | 401 | if (array_key_exists('fields', $item)) { 402 | return collect($item['fields'])->isNotEmpty(); 403 | } 404 | 405 | return false; 406 | } 407 | 408 | /** 409 | * Check if an item has sets. 410 | */ 411 | protected function hasSets(array $item): bool 412 | { 413 | if (collect($item['field']['sets'])->isEmpty()) { 414 | return false; 415 | } 416 | 417 | return true; 418 | } 419 | 420 | /** 421 | * Check if the passed value is a faker formatter. 422 | * 423 | * @param mixed $value 424 | */ 425 | protected function isFakerFormatter($value, string $key): bool 426 | { 427 | if (is_array($value)) { 428 | return false; 429 | } 430 | 431 | if ($key === 'type') { 432 | return false; 433 | } 434 | 435 | if ($key === 'enabled') { 436 | return false; 437 | } 438 | 439 | return true; 440 | } 441 | } 442 | --------------------------------------------------------------------------------