├── src ├── Exceptions │ └── FragmentFileNotFound.php ├── Commands │ └── ImportFragments.php ├── Exporter.php └── Importer.php ├── .editorconfig ├── LICENSE.md ├── composer.json ├── CHANGELOG.md └── README.md /src/Exceptions/FragmentFileNotFound.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/fragment-importer", 3 | "description": "Import fragments with excel files", 4 | "keywords": [ 5 | "spatie", 6 | "fragment-importer" 7 | ], 8 | "homepage": "https://github.com/spatie/fragment-importer", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Freek Van der Herten", 13 | "email": "freek@spatie.be", 14 | "homepage": "https://spatie.be", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php" : "^7.0", 20 | "illuminate/console": "^5.2", 21 | "maatwebsite/excel": "^2.1", 22 | "illuminate/support": "^5.2" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^5.7", 26 | "spatie/laravel-translation-loader": "^1.0", 27 | "orchestra/testbench": "^3.2" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Spatie\\FragmentImporter\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Spatie\\FragmentImporter\\Test\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "vendor/bin/phpunit" 41 | }, 42 | "minimum-stability": "dev", 43 | "prefer-stable": true 44 | } 45 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `fragment-importer` will be documented in this file 4 | 5 | ## 3.2.0 - 2017-03-09 6 | - make output more verbose 7 | 8 | ## 3.1.1 - 2016-01-26 9 | - fix deps 10 | 11 | ## 3.0.1 - 2016-01-25 12 | - fix deps 13 | 14 | ## 3.0.0 - 2016-10-10 15 | - make compatible with `laravel-translation-loader` 16 | 17 | ## 2.0.6 - 2016-09-22 18 | - Fixed an issue that would create duplicates when updating fragments 19 | - Internal refactors & integration tests 20 | 21 | ## 2.0.5 - 2016-08-23 22 | - L5.3 23 | 24 | ## 2.0.4 - 2016-08-11 25 | - Stability improvements 26 | 27 | ## 2.0.3 - 2016-06-17 28 | 29 | - Restore importer 30 | 31 | ## 2.0.2 - 2016-06-15 32 | 33 | **This version is bugged, do not use** 34 | 35 | - Bugfixes 36 | 37 | ## 2.0.1 - 2016-06-15 38 | 39 | - Replaced translation api with `spatie/laravel-translatable`'s 40 | - Separated Excel load from import 41 | 42 | ## 1.0.6 - 2016-03-01 43 | 44 | - Import all languages set in `app.locales` 45 | 46 | ## 1.0.5 - 2016-03-01 47 | 48 | - Export all languages set in `app.locales` 49 | 50 | ## 1.0.4 - 2016-02-18 51 | 52 | - Added some margin for errors when Excel rows are empty 53 | 54 | 55 | ## 1.0.3 - 2016-02-04 56 | 57 | - Fixed syntax error 58 | 59 | ## 1.0.2 - 2016-02-04 60 | 61 | ### this version is broken, do not use 62 | 63 | - Set draft column to false by default 64 | 65 | ## 1.0.1 - 2016-02-02 66 | 67 | - Remove usages of fragment repository 68 | 69 | ## 1.0.0 - 2016-02-02 70 | 71 | - Initial release 72 | -------------------------------------------------------------------------------- /src/Commands/ImportFragments.php: -------------------------------------------------------------------------------- 1 | option('update')) { 21 | Artisan::call('backup:run', ['--only-db' => true]); 22 | $this->comment('Database dumped'); 23 | $importer->updateExistingFragments(); 24 | } 25 | 26 | Cache::flush(); 27 | $this->comment('Cache cleared'); 28 | 29 | $latestExcelFile = $this->getLatestFragmentExcel(); 30 | 31 | $this->comment("Importing fragments from {$latestExcelFile}"); 32 | $importer->import($latestExcelFile); 33 | 34 | $this->info($this->getImportMessage($importer)); 35 | } 36 | 37 | public function getLatestFragmentExcel() : string 38 | { 39 | $directory = database_path('seeds/data'); 40 | 41 | $files = collect(glob("{$directory}/fragments*.xlsx")); 42 | 43 | if ($files->isEmpty()) { 44 | throw new \Exception("could not find any fragment files in directory `{$directory}`"); 45 | } 46 | 47 | return $files->last(); 48 | } 49 | 50 | protected function getImportMessage($importer): string 51 | { 52 | $newFragments = $importer->getNewFragments()->implode('key', ', '); 53 | 54 | if ($this->option('update')) { 55 | return 'Imported all fragments'.($newFragments ? " including new fragments: {$newFragments}" : '.'); 56 | } 57 | 58 | if ($newFragments) { 59 | return "Imported only the following new fragments: {$newFragments}"; 60 | } 61 | 62 | return 'No new fragments imported.'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Exporter.php: -------------------------------------------------------------------------------- 1 | generateExcel(); 17 | } 18 | 19 | public function generateExcel() 20 | { 21 | Excel::create('fragments '.date('Y-m-d H:i:s'), function ($excel) { 22 | $this->addSheet($excel, 'fragments', $this->getVisibleFragments()); 23 | $this->addSheet($excel, 'hidden', $this->getHiddenFragments()); 24 | })->download('xlsx'); 25 | } 26 | 27 | protected function addSheet(LaravelExcelWriter $excel, string $name, Collection $fragments) 28 | { 29 | $excel->sheet($name, function ($sheet) use ($fragments) { 30 | $sheet->freezeFirstRow(); 31 | 32 | $sheet->cells('A1:Z1', function ($cells) { 33 | $cells->setFontWeight('bold'); 34 | $cells->setBorder('node', 'none', 'solid', 'none'); 35 | }); 36 | 37 | $rowCounter = 1; 38 | 39 | $sheet->row($rowCounter++, $this->getHeaderColumns()); 40 | 41 | foreach ($fragments as $fragment) { 42 | $fragmentProperties = [ 43 | $fragment['group'], 44 | $fragment['key'], 45 | $fragment['contains_html'] ? 0 : 1, 46 | $fragment['description'], 47 | ]; 48 | 49 | $translatedFragmentProperties = locales() 50 | ->map(function (string $locale) use ($fragment) { 51 | return $fragment->getTranslation($locale); 52 | }) 53 | ->toArray(); 54 | 55 | $sheet->row($rowCounter++, array_merge($fragmentProperties, $translatedFragmentProperties)); 56 | } 57 | }); 58 | } 59 | 60 | protected function getHeaderColumns(): array 61 | { 62 | return collect(['group', 'key', 'contains_html', 'description'])->merge( 63 | locales()->map(function (string $locale) { 64 | return "text_{$locale}"; 65 | }) 66 | )->toArray(); 67 | } 68 | 69 | public function getVisibleFragments(): Collection 70 | { 71 | return $this->getFragments($hidden = false); 72 | } 73 | 74 | public function getHiddenFragments(): Collection 75 | { 76 | return $this->getFragments($hidden = true); 77 | } 78 | 79 | public function getFragments(bool $hidden): Collection 80 | { 81 | return Fragment::where('hidden', $hidden) 82 | ->orderBy('group') 83 | ->orderBy('key') 84 | ->get(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Importer.php: -------------------------------------------------------------------------------- 1 | newFragments = new Collection(); 23 | } 24 | 25 | public function updateExistingFragments() 26 | { 27 | $this->updateExistingFragments = true; 28 | } 29 | 30 | public function import(string $path) 31 | { 32 | $this->guardAgainstInvalidPath($path); 33 | 34 | $this->loadFragments($path)->each(function (array $data) { 35 | $fragment = Fragment::firstOrNew(['group' => $data['group'], 'key' => $data['key']]); 36 | 37 | if (!$this->shouldImport($fragment)) { 38 | return; 39 | } 40 | 41 | if (! $fragment->exists) { 42 | $this->newFragments->push($fragment); 43 | } 44 | 45 | $fragment->group = $data['group']; 46 | $fragment->key = $data['key']; 47 | $fragment->hidden = $data['hidden']; 48 | $fragment->contains_html = $data['contains_html'] ?? false; 49 | $fragment->description = $data['description'] ?? ''; 50 | $fragment->draft = false; 51 | 52 | $this->locales()->each(function (string $locale) use ($fragment, $data) { 53 | $fragment->setTranslation($locale, $data["text_{$locale}"] ?? ''); 54 | }); 55 | 56 | $fragment->save(); 57 | }); 58 | } 59 | 60 | public function getNewFragments(): Collection 61 | { 62 | return $this->newFragments; 63 | } 64 | 65 | protected function guardAgainstInvalidPath(string $path) 66 | { 67 | if (!file_exists($path)) { 68 | throw FragmentFileNotFound::inPath($path); 69 | } 70 | } 71 | 72 | protected function loadFragments(string $path): Collection 73 | { 74 | return Excel::load($path)->all()->flatMap(function (RowCollection $sheet) { 75 | return $sheet->reject(function (CellCollection $row) { 76 | return empty(trim($row->group)); 77 | })->map(function (CellCollection $row) use ($sheet) { 78 | return $row->put('hidden', $sheet->getTitle() === 'hidden')->toArray(); 79 | }); 80 | }); 81 | } 82 | 83 | protected function shouldImport(Fragment $fragment): bool 84 | { 85 | if (!$fragment->exists) { 86 | return true; 87 | } 88 | 89 | return $this->updateExistingFragments; 90 | } 91 | 92 | protected function locales(): Collection 93 | { 94 | return collect(config('app.locales')) 95 | ->merge(config('app.backLocales')) 96 | ->unique(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [](https://supportukrainenow.org) 3 | 4 | # Import fragments from an excel file 5 | 6 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 7 | [![SensioLabsInsight](https://img.shields.io/sensiolabs/i/9012cf42-8d1a-4649-b5ab-b96db48eed21.svg?style=flat-square)](https://insight.sensiolabs.com/projects/9012cf42-8d1a-4649-b5ab-b96db48eed21) 8 | [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/fragment-importer.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie-custom/fragment-importer) 9 | [![StyleCI](https://styleci.io/repos/50928093/shield?branch=master)](https://styleci.io/repos/50928093) 10 | 11 | This Blender specific package provides some classes and commands to easily import fragments 12 | using an excel file. An exporter is included too. 13 | 14 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 15 | 16 | ## Support us 17 | 18 | [](https://spatie.be/github-ad-click/fragment-importer) 19 | 20 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 21 | 22 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 23 | 24 | ## Install 25 | 26 | This package is custom built for [Spatie](https://spatie.be) projects and is therefore not registered on packagist. 27 | In order to install it via composer you must specify this extra repository in `composer.json`: 28 | 29 | ```json 30 | "repositories": [ { "type": "composer", "url": "https://satis.spatie.be/" } ] 31 | ``` 32 | 33 | You can install the package via composer: 34 | ``` bash 35 | $ composer require spatie/fragment-importer 36 | ``` 37 | 38 | ## Usage 39 | 40 | Fragments not yet present in the database can be imported using: 41 | ``` console 42 | php artisan fragment:import 43 | ``` 44 | 45 | If you want to update the existing ones as well, run this command: 46 | ``` console 47 | php artisan fragment:import --update 48 | ``` 49 | 50 | ## Changelog 51 | 52 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 53 | 54 | ## Contributing 55 | 56 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 57 | 58 | ## Security 59 | 60 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 61 | 62 | ## Credits 63 | 64 | - [Freek Van der Herten](https://github.com/freekmurze) 65 | - [All Contributors](../../contributors) 66 | 67 | ## About Spatie 68 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 69 | 70 | ## License 71 | 72 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 73 | --------------------------------------------------------------------------------