{"id":20753644,"url":"https://github.com/dev-labs-bg/laravel-csv-importer","last_synced_at":"2025-04-28T16:26:23.575Z","repository":{"id":57086286,"uuid":"79239384","full_name":"dev-labs-bg/laravel-csv-importer","owner":"dev-labs-bg","description":"A CSV importer/exporter library for Laravel","archived":false,"fork":false,"pushed_at":"2017-04-26T11:06:07.000Z","size":37,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-30T11:21:09.269Z","etag":null,"topics":["csv","csv-files","database","export","import","laravel","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dev-labs-bg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-17T15:09:49.000Z","updated_at":"2018-06-02T21:15:23.000Z","dependencies_parsed_at":"2022-08-25T00:50:31.312Z","dependency_job_id":null,"html_url":"https://github.com/dev-labs-bg/laravel-csv-importer","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-labs-bg%2Flaravel-csv-importer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-labs-bg%2Flaravel-csv-importer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-labs-bg%2Flaravel-csv-importer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-labs-bg%2Flaravel-csv-importer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dev-labs-bg","download_url":"https://codeload.github.com/dev-labs-bg/laravel-csv-importer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251344383,"owners_count":21574530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv","csv-files","database","export","import","laravel","php"],"created_at":"2024-11-17T09:14:24.565Z","updated_at":"2025-04-28T16:26:23.556Z","avatar_url":"https://github.com/dev-labs-bg.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About Laravel CSV Importer\nA Laravel 4 library for importing/exporting CSV files into/out of database tables using Eloquent.\n\nNote: This library is still early in development. You may find functionality which is inflexible, altogether, poorly documented. You are welcome to open issues, but my schedule may prevent me from reacting to them in a timely fashion. Nevertheless, I've open sourced it, as none of the Laravel CSV import/export packages could handle cross-CSV references.\n\n# Features\n  - Automatic importer/exporter registration\n  - CSV field preprocessing\n  - CSV field validation\n  - Cross CSV references (relationships)\n  - Automatic dependency resolution\n  - Rollback on error\n\n# Requirements\n  - PHP \u003e=5.4\n  - Laravel Framework \u003e= 4\n  - Composer\n  - RDBMS supported by Eloquent (Laravel ORM)\n\n# Installation\n\nTo install, run: ```php composer.phar require yavor-ivanov/csv-importer``` in your laravel project root.\n\nAlternatively, you can manually add ```\"yavor-ivanov/csv-importer\": \"dev-master\"``` to your `composer.json` under the `require` field.\n\nThen, open `app/config/app.php` and add the following line in the `providers` array:\n\n```\n'providers' =\u003e array(\n    'YavorIvanov\\CsvImporter\\CsvImporterServiceProvider',\n)\n```\n\nThe package is configured by default to look for:\n  - CSV files in `app/csv/files`\n  - Importers in `app/csv/importers/`\n  - Exporters in `app/csv/exporters/`\n  - Place CSV backups in `app/csv/files/backup/`\n\nYou'll need to create all these folders by running these commands:\n```\nmkdir -p app/csv/files/backup\nmkdir app/csv/importers\nmkdir app/csv/exporters\n```\n\n# Examples\nI've set up an [examples repository](https://github.com/dev-labs-bg/laravel-csv-importer-examples) containing a Laravel 4 application with multiple importers and exporters.\n\n# Configuration\nThe importer package comes preconfigured to look for CSV files and importer/exporter scripts in the `app/csv/files/` and `app/csv/importer` (and exporter) folders. If you wish to change this, you'll need to first get your own (application) copy of the configuration by running the following command:\n\n```php artisan config:publish yavor-ivanov/csv-importer```\n\nYou will get a copy of the default configuration in `app/config/packages/yavor-ivanov/csv-importer/config.php`. Any changes to this file override the default configuration.\n\nThis is what the default config file looks like:\n```\n    'import' =\u003e [\n        'file_match' =\u003e '*Importer.php',\n        'register_path' =\u003e '\\\\csv\\\\importers\\\\',\n        'class_match_pattern' =\u003e '/^(?!CSV)(.*)Importer$/',\n        'default_csv_path' =\u003e '/csv/files/',\n    ],\n    'export' =\u003e [\n        'file_match' = '*Exporter.php',\n        'register_path' =\u003e '\\\\csv\\\\exporters\\\\',\n        'class_match_pattern' =\u003e '/^(?!CSV)(.*)Exporter$/',\n        'default_csv_path' =\u003e '/csv/files/',\n    ],\n```\n\nThe configuration options are ass follows:\n  - `file_match` - A regular expression that matches the file names to be considered importers/exporters. The package uses this to auto-register your importer/exporter classes.\n  - `register_path` - The location from which to include php scripts for the importers/exporters (relative to the `app` folder)\n  - `class_match_pattern` - The pattern by which the package distinguishes importers/exporters from other classes. This is used for the automatic importer/exporter registry.\n  - `default_csv_path` - The default directory the importer/exporter looks for CSV files (relative to the `app` folder)\n\n# Naming conventions\nThe package establishes the following file and class naming convention for the importer/exporters:\n\n  - All importers/exporters must be placed in their designated folders (`app/csv/importers` and `app/cs/exporters` by default). This location is controlled by the `register_path` configuration option.\n  - The PHP files themselves must end in `Importer.php` by default (`Exporter.php` for exporters). This is also controlled by the `file_match` configuration option.\n  - The classes in the files must match the `class_match_pattern`. Ending the class name with `Importer` or `Exporter` is enough for a valid class name by default.\n\nIn exchange for these limitation, the package is able to automatically register any importers/exporters that follow the convention. This allows you to:\n  - Create importer/exporter scripts and immediately use them in import/export commands\n  - Reference importers/exporters as dependencies of other importers/exporters and have the package automatically resolve them at runtime.\n  - Obtain a list of all registered importers/exporters.\n\n# Usage\n### Commands\nThe package comes with two commands `csv:import` and `csv:export`\n\nThe command format is: ```csv:import \u003cimporter_name\u003e [\u003cmode\u003e]```\n\nExample usage: ```php artisan csv:import categories``` or ```php artisan csv:import expenses validate```\n\nThe importer supports the following modes:\n  - `append` - Only adds **new** data to the table. Does not delete records that have been removed from the CSV, nor does it update records that have been changed.\n  - `overwrite` - Deletes everything in the table, and imports the CSV.\n  Note: Overwrite mode does not propagate to dependencies, as this may result in a cascading delete of the whole database. As of this moment there is no way to override this behaviour.\n  - `update` - Some as append, but updates records in the table.\n  - `validate` - Checks the CSV file for errors. Does not write to the database.\n\nThe `mode` parameter is optional. The importer always runs in `append` mode if one is not supplied.\n\n**NOTE:** As of the moment, the package doesn't support deleting records from the database when removed from a CSV file, as this is potentially error prone. A `prune` mode will be added in later versions that exclusively performs this operation. Right now, the only way to delete database records is with the `overwrite` option.\n\nFor more information on the command format, run `php artisan help csv:import`\n\n### CSV format\n\nThe only requirements for the CSV format are:\n1. The CSV must include a header row\n2. All columns in the header must be named\n3. There must be at least one unique column\n4. Cells which contain spaces must be quoted in the CSV output\n\nAn example of a valid CSV:\n```\nid,role_name\n1,\"super admin\"\n2,admin\n3,moderator\n4,user\n```\n\n| id  | role_name   |\n| --- | ----------- |\n| 1   | super admin |\n| 2   | admin       |\n| 3   | moderator   |\n| 4   | user        |\n*(Table view)*\n\n\n### Database table format\n\n| id  | role_name   | csv_id |\n| --- | ----------- | ------ |\n| 4   | super admin | 1      |\n| 5   | admin       | 2      |\n| 6   | moderator   | 3      |\n| 7   | user        | 4      |\n\nIn order to make use of caching, update mode, and cross-CSV references, the database table must include a `csv_id` column. This is used to find the database record for the corresponding CSV row.\n\n### Model\nThe package uses Laravel's Eloquent ORM to read and write to the database. This means that there is no configuration needed for database access. This also allows you to use Eloquent features (such as observers, validators, custom properties, etc.) while importing and exporting.\n\nIn order to make sure the `csv_id` column autoincrements when creating new records outside the importer, you must use the `CSVReferenceTrait` in your model like so:\n\n```\nclass UserRole extends Eloquent\n{\n    use YavorIvanov\\CsvImporter\\CSVReferenceTrait;\n\n    protected $fillable = ['role_name'];\n    protected $table = 'user_roles';\n\n    // ...\n}\n```\n\nThe [`CSVReferenceTrait`](src/YavorIvanov/CsvImporter/CSVReferenceTrait.php) registers a `save` hook, which sets the proper `csv_id` for models saved without one.\n\n**NOTE:** You **can** import to properties not listed in the `$fillable` array, as the importer turns off the Eloquent field guarding while importing. (Don't worry, it re-guards them when it's done.)\n\n# Importers\n### Minimum configuration importer example\nThe following is the minimum configuration needed to create an importer class, which creates a collection of `UserRole` models and imports them to the database, and supports `update` mode:\n\n```\n\u003c?php\nuse YavorIvanov\\CsvImporter\\CSVImporter;\nclass UserRolesImporter extends CSVImporter\n{\n    // Defualt name for the CSV to import.\n    public $file = 'user_roles.csv';\n\n    // Eloquent model name to create/update (case sensitive)\n    protected $model = 'UserRole';\n\n    // Maps an id field in the csv to a database id field. Format ['csv_column_name' =\u003e 'db_column_name']\n    protected $primary_key = ['id' =\u003e 'csv_id'];\n\n    // Maps an id field in the csv to a database id field. Format ['csv_column_name' =\u003e 'db_column_name']\n    protected $cache_key = ['id' =\u003e 'csv_id'];\n\n    // Maps csv columns to database columns. The importer uses these to automatically\n    // import/update The format here is:\n    //     csv_column_name =\u003e database_column_name\n    // or\n    //     csv_column_name\n    // if both column names happen to be the same. For more information on the mapping format,\n    // skip to the column mappings section of the documentation.\n    protected $column_mapping = [\n        ['csv_id' =\u003e 'id'],\n        'role_name',\n    ];\n}\n```\n\nAlternatively, you can forego the `$column_mapping` array, and define the import and update functions yourself (you can even mix them together):\n\n```\n\u003c?php\nuse YavorIvanov\\CsvImporter\\CSVImporter;\nclass UserRolesImporter extends CSVImporter\n{\n    // Defualt name for the CSV to import.\n    public $file = 'user_roles.csv';\n\n    // Eloquent model name to create/update (case sensitive)\n    protected $model = 'UserRole';\n\n    // Maps an id field in the csv to a database id field. Format ['csv_column_name' =\u003e 'db_column_name']\n    protected $primary_key = ['id' =\u003e 'csv_id'];\n\n    // Maps an id field in the csv to a database id field. Format ['csv_column_name' =\u003e 'db_column_name']\n    protected $cache_key = ['id' =\u003e 'csv_id'];\n\n    protected function update($row, $o)\n    {\n        $o-\u003ecsv_id = $row['id'];\n        $o-\u003erole_name = $row['role_name'];\n        $o-\u003esave();\n    }\n\n    protected function import_row($row)\n    {\n        return UserRole::create([\n            'role_name' =\u003e $row['role_name'],\n            'csv_id' =\u003e $row['id'],\n        ]);\n    }\n}\n```\nEvery importer name must end with `Importer` (controlled by the [`class_match_pattern`](https://github.com/dev-labs-bg/laravel-csv-importer#configuration) property) and extend the `CSVImporter` base class.\n\nField breakdown:\n  - `$file` - The name of the file to load from `app/csv/files/` (csv folder configurable)\n  - `$model` - The package uses the Eloquent ORM to load and save from/to the database. In order to call select and save functions, the package needs to know the model the importer corresponds to.\n  - `$cache_key` - The package caches entities already in the database as well as entities being imported in order to decrease the amount of database queries for self-referencing CSV files, update mode imports, as well as skip duplicate imports. In order to do that, the package needs to know the mapping between the primary unique column of the CSV and the database table.\n  - `$primary_key` - All importers share a `context`, from which you may retrieve entities of a dependency importer. This works exactly as foreign keys do, i.e.: CSV `A` references a row from CSV `B` by some unique column. The `$primary_key` is the mapping between that (CSV) unique column and a database table unique column.\n  By default, the CSV id column is named `id`, while the table column is `csv_id`.\n\n  **Note:** The importer cannot use the (more or less default) `id ` column in the table for comparison, because id collisions may occur when appending to a non-empty table.\n\n\n  - `import_row` - Once the importer diffs the database table and CSV it iterates over the **new** rows in the CSV file. For every new row found, the `import_row` function is called. The base importer passes the current row in the `$row` parameter, and expects an Eloquent model to be returned.\n\n  **Note:** At the moment, importer does not support conditional importing of rows. The `import_row` function must return a model instance.\n  - `update` - This function is called by the base importer for every record found in **both** the database table and the CSV. The importer passes the current CSV row in the `$row` parameter, as well as the Eloquent model from the database in the `$o` parameter.\n\n  **Note:** Currently, the importer doesn't check for actual changes to the model. **It will always call the function**. Because of this current limitation, you must manually call `save()` on your models.\n\n  **Note:** This function is only every called when running the importer in `update` mode.\n\n### Column mappings\nOften, the database table columns differ in name (or representation) from the CSV files you wish to import. For example, databases accept dates in the [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601) (`YYY-MM-DD`), but your CSV files may contain dates in the American date format (`MM/DD/YYYY`). The `$column_mapping` property allows you to define any name difference between CSV and database table, as well as transform and validate the CSV data before saving.\n\nThe `$column_mapping` format is flexible. It allows you to define a column with a name difference, multiple preprocessing steps, as well as validation functions:\n\n```\nprotected $column_mapping = [\n    'csv_column' =\u003e ['name' =\u003e 'table_column',\n                          'processors' =\u003e ['processor_name' =\u003e 'parameter'],\n                          'validators' =\u003e ['validator_name' =\u003e 'parameter']\n                ],\n];\n```\n\n\nThe `$column_mapping` is also used by the importer when no `import_row` or `update` function is defined. It performs the import by running the validator/processor functions on the `csv_column` and saving the result to the specified `table_column`. The `table_column` could also be a model property or model function:\n\n```\nprotected $column_mapping = [\n    'csv_column' =\u003e 'modelPropertyName',\n];\n```\n\n**Note:** In order to assign to model properties, the importer uses the `table_column` key as part of an [`eval()`](https://github.com/dev-labs-bg/laravel-csv-importer/blob/master/src/YavorIvanov/CsvImporter/CSVImporter.php#L62) call. The call is limited to the current model instance, **yet there are no checks for malicious intent**, such as calling `delete()` or using `id; call_malicious_function(); $variable_name` as a key.\n\n\nWhen the importer reads the CSV file, it looks at the `$column_mapping` to determine if it should transform the input data (or run validations against it).\n\nThe processor function are read from the result of the `get_processors` function:\n```\nprotected function get_processors()\n{\n    return [\n            'integer' =\u003e function ($v) { return intval($v); },\n\n            'to_datetime' =\u003e function ($v, $fmt='d/m/y H:i')\n            {\n                $created_at = DateTime::createFromFormat($fmt, $v);\n                return $created_at-\u003eformat('Y-m-d H:i:s');\n            },\n    ];\n}\n```\n\nThe function names of the preprocessors are determined by the array keys returned.\n\nThe validators are returned by the `get_validators` function.\n\nFor brevity, you can omit unused features from your column specification. For example, importing a column with only a name change can be condensed to the following:\n```\nprotected $column_mapping = [\n    'csv_column' =\u003e 'table_column',\n];\n```\n\nAnother example of this is using preprocessors without passing in parameters:\n```\nprotected $column_mapping = [\n    'csv_column' =\u003e ['name' =\u003e 'table_column',\n                    'processors' =\u003e ['processor1', 'processor2'],\n                ],\n];\n```\n\nOr omitting the array if there is only one processor:\n```\nprotected $column_mapping = [\n    'csv_column' =\u003e ['name' =\u003e 'table_column',\n                    'processors' =\u003e 'my_column_processor',\n                ],\n];\n```\n\n### Adding dependencies and referencing an importer\nOften times, the data in CSV files wants to be relational in nature. In order to resolve the relationships properly, the importer needs to import files in the correct order. For instance, if the `users.csv` makes a reference to a phone number from `phone_numbers.csv`, the importer should make sure to import the phone numbers before it imports the users, as well as fetch any phone numbers that may be in the database (but not in the `phone_numbers.csv` file).\n\nThe package evaluates the import order by reading the dependencies of each importer defined in the static `$deps` property. This collection of dependencies forms a dependency graph that can be [topologically sorted](https://en.wikipedia.org/wiki/Topological_sorting) to yield order in which the package must call the importers.\n\nWhenever you run an importer that has dependencies from the command line, you will see progress bars for the importer **and** its dependencies:\n```\nImporting: Book.\n 6/6 [============================] 100%\n 7/7 [============================] 100%\n```\n*Here, the `Book` importer depends on the `Author` importer. As of the moment, the progress bars are not labeled.*\n\nAside from declaring dependencies, an importer will need to access the data from the entities of its dependencies. In the Books and Authors example, a Books importer may wish to find its Author's id and use it as a foreign key.\n\nThe `get_from_context` function returns an Eloquent model instance from a dependency name and a search value:\n`protected function get_from_context($ctx, $key)`\n\nThe column on which to select on is determined by the `$primary_key` property of the dependent importer. If no `$primary_key` is defined, the `$cache_key` mapping is used instead. This allows you to cache a model by one column (most frequently `id`), yet refer to  if by another (unique) column from other importers. An example of this is caching a User model by `id`, but referring to it by `email` from an Order.\n\n### Caching\nIn the beginning of the import, the package selects all rows from the importer's `$model` table, and caches them by a unique CSV column in the `$cache_key` mapping:\n\n`protected $cache_key = ['table_column_name' =\u003e 'csv_column_name'];`\n\nThis allows the package to avoid importing CSV rows that are already in the database. Each CSV record can be checked for inclusion in the database by comparing the values of the unique keys defined in the `$cache_key` mapping. For example, a mapping of `id` \u003c--\u003e `csv_id` would search the cache for an Eloquent entity with an `id` equal to the current CSV row's `csv_id`.\n\nAside from the performance benefit of caching, you can query the cache in importers by calling the 'get_from_cache($hash)'. This is useful when importing self-referential CSVs. An example of this would be importing a tree structure in following format: `[id, name, parent_id]`, where each branch prepends its parent's name to its own.\n\n### Adding preprocessor functions\nYou can define processor functions for your importers by adding a `get_processors()` function, which returns an array of functions. The package will run these functions on the columns which list these processors in the the `$column_mapping`.\n\nYou can define the processor functions inline:\n```\nprotected function get_processors()\n{\n    return [\n        'null_or_datetime' =\u003e function ($v, $fmt='Y-m-d')\n        {\n            $v = $this-\u003eprocess('string_to_null', $v);\n            if ($v == Null)\n                return $v;\n            return $this-\u003eprocess('to_datetime', [$v, $fmt]);\n        },\n    ];\n}\n```\n\nOr, if you wish to share them across importers, you can define them in a shared file, and reference them:\n\n```\nprotected function get_processors()\n{\n    return [\n        'null_or_datetime' =\u003e my_datetime_function\n    ];\n}\n```\n\nThe [base importer](https://github.com/Yavor-Ivanov/laravel-csv-importer/blob/master/src/YavorIvanov/CsvImporter/CSVImporter.php#L39) also defines its own processors that can be used by all importers, [as they are 'inherited'](https://github.com/Yavor-Ivanov/laravel-csv-importer/blob/master/src/YavorIvanov/CsvImporter/CSVImporter.php#L189).\n\n**Note:** As of the moment there is no way to register global preprocessors like the base importer does.\n\n### Adding validation functions\nValidation functions are defined similarly to the preprocessors. The `get_validators` function of the importer returns an array of functions that can be defined to run when an importer runs via the `$column_mapping` property.\n\nBelow is an example validator which checks a column for uniqueness:\n```\nprotected function get_validators()\n{\n    return [\n        'unique' =\u003e function ($col, $row)\n        {\n            $val = $row[$col];\n            $current_obj = $this-\u003eget_from_cache($row);\n            $model_col = array_get($this-\u003ecolumn_mapping, \"$col.name\", $col);\n            $occurrences = $this-\u003ecache-\u003ereduce(function($carry, $o) use ($current_obj, $model_col, $val) {\n                if ($o != $current_obj \u0026\u0026 strtolower($o-\u003e$model_col) == strtolower($val))\n                    return $carry + 1;\n                return $carry;\n            }, 0);\n\n            if ($occurrences \u003e 0)\n            {\n                Log::error(\"A $this-\u003ename with $col = $val already exists in $this-\u003efile.\");\n                die;\n            }\n        },\n    ];\n}\n```\n\nThe validator functions receive both the column name they have been called on and the whole CSV row. This allows you to create validations rules such as: `property X is valid only if Y is NULL`.\n\n### Column pivoting\nSometimes your pivot CSV table nicely mirrors the database pivot table:\n\n| book_id |  genre_id |\n|---------|-----------|\n| 1       | 2         |\n| 1       | 1         |\n\nOther times, your many to many pivot CSV may come in a weird, multiple column format:\n\n| book_id |  genre1 |  genre2 |  ... |\n|---------|---------|---------|------|\n| 1       | 2       |  1      |      |\n\nAlthough changing the CSV format to be in tune with the database table layout would be ideal, you may not always have that luxury (widely used legacy formats, for instance).\n\nWhen this happens, you can do some preprocessing of the individual rows before the import/update function reads them.\n\nIn the example below, the `pivot_row` function takes a row in the `[book_id, genre1, genre2, ... genreN]` format and replaces it with multiple rows of `[book_id, genre_id]` tuples:\n```\nprotected function pivot_row($row)\n{\n    $pivoted_row = [];\n    $book_id = $row['book'];\n\n    // Loops over the genre columns only, as there is only one book column.\n    foreach (array_filter(array_slice($row, 1)) as $genre_id)\n    {\n        array_push($pivoted_row, [\n            'book_id'  =\u003e $book_id,\n            'genre_id' =\u003e $genre_id,\n        ]);\n    }\n    return $pivoted_row;\n}\n```\n\nThe pivot step is run before column processors and validators.\n\n# Exporters\n### Minimum configuration exporter example\n\nThe following is a minimal exporter example using the `$column_mapping` to drive the CSV export:\n\n```\n\u003c?php\nuse YavorIvanov\\CsvImporter\\CSVExporter;\nclass UserRolesImporter extends CSVExporter\n{\n    // Defualt name for the CSV to export.\n    public $file = 'user_roles.csv';\n\n    // Eloquent model to select from (case sensitive)\n    protected $model = 'UserRole';\n\n    protected $column_mapping = [\n        'csv_id' =\u003e 'id',\n        'role_name',\n    ];\n}\n```\n\n**Note:** Every exporter class name must end with Exporter (controlled by the [`class_match_pattern`](https://github.com/dev-labs-bg/laravel-csv-importer#configuration) property) and extend the CSVExporter base class.\n\n### Field breakdown:\n\n- `$file` - The name of the file to save to. The default path to file is `app/csv/files/` (csv folder configurable)\n- `$model` - The package uses the Eloquent ORM to read data from the database. In order to select records, the package needs to know the model the exporter corresponds to.\n\n### Column mappings\n\nThe exporter `$column_mapping` property serves the same purpose as the importer [`$column_mapping`](https://github.com/dev-labs-bg/laravel-csv-importer/#column-mappings). It allows you to define a relationship between the table columns (or model properties/methods) and CSV columns. The exporter uses this mapping to generate the CSV output.\n\nLike the importer, the exporter `$column_mapping` allows you to use model properties, as well as map model functions to CSV columns. Here's an example of a mappnig between a model property and a CSV column that uses a postprocessing function:\n\n```\nprotected $column_mapping = [\n    'model_property' =\u003e ['name' =\u003e 'csv_column', 'processors' =\u003e ['postprocessor_name' =\u003e 'parameter']],\n];\n```\n\nAnd an example of an exporter mapping a model function to a CSV column:\n\n```\nprotected $column_mapping = [\n    'compute_property()' =\u003e ['name' =\u003e 'csv_column_name', 'processors' =\u003e ['postprocessor_name' =\u003e 'parameter']],\n];\n```\n\nExporting is generally more straightforward than importing, so there's no need to use an `export_row` like function [(although the option is available)](https://github.com/dev-labs-bg/laravel-csv-importer/#generating-rows-programatically). The exporter can read the `$column_mapping` and automatically outputs the CSV file.\n\nIn order to support certain mappings, the exporter evaluates the key of the `$column_mapping` entry (`model_property` in the above example) and uses the result as the value of `csv_column` when exporting. Some examples of such mappings are: computed properties, aggregate functions, and relationship properties.\n\nThe [book exporter example](https://github.com/dev-labs-bg/laravel-csv-importer-examples/blob/master/app/csv/exporters/BookExporter.php#L35) uses such a mapping to get the csv id of its `authors` relationship:\n\n```\n    protected $column_mapping = [\n        ['authors()-\u003efirst()-\u003ecsv_id' =\u003e 'author'],\n        // ...\n    ];\n```\n\n**Note:** The exporter uses the `$column_mapping` key as part of an [`eval()`](https://github.com/dev-labs-bg/laravel-csv-importer/blob/master/src/YavorIvanov/CsvImporter/CSVExporter.php#L51) call. The call is limited to the current model instance, **yet there are no checks for malicious intent**, such as calling `delete()` or using `id; call_malicious_function()` as a key.\n\nLike the importer `$column_mapping` property, the exporter allows you to simplify the row declaration if you don't need to use a postprocessor, or the CSV and database columns coincide:\n\n```\nprotected $column_mapping = [\n    'name',                                                                                      // Column name in the CSV and database is the same\n    ['table_column' =\u003e 'csv_column'],                                                            // Table column to CSV column mapping with no postprocessor\n    ['table_column' =\u003e ['name' =\u003e 'csv_column', 'processors' =\u003e ['processor_name']]],             // Post-processor without paramers (use defaults).\n    ['table_column' =\u003e ['name' =\u003e 'csv_column', 'processors' =\u003e ['processor_name' =\u003e 'param']]], // Post-processor with parameters.\n    ['table_column' =\u003e ['name' =\u003e 'csv_column', 'processors' =\u003e [\n        'processor1' =\u003e ['param1', 'param2'],\n        'processor2' =\u003e 'param',\n        'processor3']\n    ]]],                                                                                         // Multiple post-processors with a differing number of parameters.\n];\n```\n\n### Post-processing\n\nLike the importer, the package reads post-processor functions from the result of the `get_processors` function:\n\n```\nprotected function get_processors()\n{\n    return [\n            'null_to_zero' =\u003e function ($v)\n            {\n                if ($v == Null)\n                    return 0;\n                return $v;\n            },\n    ];\n}\n```\nThe function names of the post-processors are determined by the array keys returned from `get_processors`.\n\n### Generating rows programatically\n\nSometimes, the column mappings just aren't flexible enough to handle your export logic. In such cases, you can use the `generate_row` function to generate the rows programatically. Cases where you may want to do this include: [exporting CSV files with a variable number of columns](https://github.com/dev-labs-bg/laravel-csv-importer-examples/blob/master/app/csv/exporters/BookGenreExporter.php#L58), exporting CSVs with data from multiple models, exporting data external to the model, etc.\n\nOnce the export process is started, the exporter selects all records from the `$model` entity, and calls `generate_row` on each record. The function should return an array in the following format: `['csv_column1' =\u003e 'value', 'csv_column2' =\u003e 'other_vaule']`.\n\nThe following is an example of exporting a CSV with a variable number of columns. [You can see the full code in the examples](https://github.com/dev-labs-bg/laravel-csv-importer-examples/blob/master/app/csv/exporters/BookGenreExporter.php#L58):\n\n```\nprotected function generate_row($o)\n{\n    $row = parent::generate_row($o);\n    $heading = 'genre';\n    $current = 1;\n    foreach ($o-\u003egenres as $genre)\n    {\n        $col_name = $heading . $current;\n        $current += 1;\n        $row[$col_name] = $genre-\u003ecsv_id;\n    }\n    return $row;\n}\n```\n\n**Note:** If you choose to override this function, the exporter will not process the `$column_mapping` property, unless you call `parent::generate_row()`. This allows you to mix custom row generation logic with column mappings if you want (or skip the automatic mapping entirely).\n\n# Licensed under the MIT license\nThe project license file can be found [here](/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-labs-bg%2Flaravel-csv-importer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdev-labs-bg%2Flaravel-csv-importer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-labs-bg%2Flaravel-csv-importer/lists"}