Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Goodby Csv Laravel Package

handcraftedinthealps/goodby-csv

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require handcraftedinthealps/goodby-csv
    

    Ensure your composer.json includes "require": {"php": "^8.1"}.

  2. First Use Case: Import a CSV file line-by-line into a database:

    use Goodby\CSV\Import\Standard\Lexer;
    use Goodby\CSV\Import\Standard\Interpreter;
    use Goodby\CSV\Import\Standard\LexerConfig;
    
    $lexer = new Lexer(new LexerConfig());
    $interpreter = new Interpreter();
    
    $interpreter->addObserver(function(array $row) {
        // Process each row (e.g., save to DB)
        DB::table('users')->insert($row);
    });
    
    $lexer->parse('users.csv', $interpreter);
    
  3. Where to Look First:

    • README.md: For basic setup and features.
    • Import/Standard/ and Export/Standard/ directories: Core classes for CSV handling.
    • Examples: Check the examples section in the README for practical use cases.

Implementation Patterns

Core Workflows

1. Streaming Imports (Memory-Efficient)

Use the Lexer + Interpreter pattern to process large files without loading them entirely into memory:

$lexer = new Lexer(new LexerConfig());
$interpreter = new Interpreter();

$interpreter->addObserver(function(array $row) {
    // Process row (e.g., queue job, log, or save)
    dispatch(new ProcessCsvRow($row));
});

$lexer->parse(storage_path('app/large_file.csv'), $interpreter);

2. Exporting Data

Export collections (arrays, PDO results, or custom objects) to CSV:

use Goodby\CSV\Export\Standard\Exporter;
use Goodby\CSV\Export\Standard\ExporterConfig;

$config = new ExporterConfig();
$config->setDelimiter("\t"); // TSV output

$exporter = new Exporter($config);
$exporter->export('php://output', User::all()->toArray());

3. Database Integration

Import:

$interpreter->addObserver(function(array $row) {
    User::create([
        'name' => $row[0],
        'email' => $row[1],
    ]);
});

Export:

$exporter->export('php://output', new PdoCollection(
    DB::connection()->prepare("SELECT * FROM users")
));

4. Symfony/Laravel HTTP Responses

Stream CSV directly to a response:

return response()->stream(function() {
    $exporter = new Exporter(new ExporterConfig());
    $exporter->export('php://output', User::all()->toArray());
}, 200, [
    'Content-Type' => 'text/csv',
    'Content-Disposition' => 'attachment; filename="users.csv"',
]);

5. Custom Collections

Transform data before export using CallbackCollection:

$collection = new CallbackCollection(User::all()->toArray(), function($row) {
    $row['full_name'] = $row['first_name'] . ' ' . $row['last_name'];
    return $row;
});
$exporter->export('php://output', $collection);

Integration Tips

  1. Laravel Service Provider: Bind the package for dependency injection:

    $this->app->bind(Exporter::class, function() {
        return new Exporter(new ExporterConfig());
    });
    
  2. Artisan Commands: Create a CSV import/export command:

    class ImportCsvCommand extends Command
    {
        protected $signature = 'csv:import {file}';
        protected $description = 'Import CSV file into database';
    
        public function handle()
        {
            $lexer = new Lexer(new LexerConfig());
            $interpreter = new Interpreter();
            $interpreter->addObserver([$this, 'processRow']);
            $lexer->parse($this->argument('file'), $interpreter);
        }
    
        public function processRow(array $row) { /* ... */ }
    }
    
  3. Queue Jobs: Offload CSV processing to queues for large files:

    $interpreter->addObserver(function(array $row) {
        ProcessCsvRowJob::dispatch($row);
    });
    
  4. Validation: Validate CSV rows before processing:

    $interpreter->addObserver(function(array $row) {
        $validator = Validator::make($row, [
            'email' => 'required|email',
        ]);
        if ($validator->fails()) {
            Log::error("Invalid row: " . json_encode($row));
            return;
        }
        // Proceed with valid row
    });
    

Gotchas and Tips

Pitfalls

  1. Memory Leaks:

    • Issue: Forgetting to close file handles or streams.
    • Fix: Use php://output or ensure streams are properly closed after export.
    • Example:
      $exporter->export('php://temp', $data); // Use temp streams for large exports
      
  2. Character Encoding:

    • Issue: Incorrect charset conversion causing garbled text.
    • Fix: Explicitly set fromCharset and toCharset in configs:
      $config->setFromCharset('ISO-8859-1')->setToCharset('UTF-8');
      
  3. Row Consistency:

    • Issue: StrictViolationException for inconsistent row lengths.
    • Fix: Use Interpreter::unstrict() if the CSV has irregular rows:
      $interpreter->unstrict();
      
  4. Large Files:

    • Issue: Timeouts or crashes with very large files.
    • Fix: Process in chunks or use Laravel queues:
      $lexer->parse($file, $interpreter, 1000); // Process 1000 rows at a time
      
  5. Delimiter Confusion:

    • Issue: Misconfigured delimiters (e.g., tabs vs. commas).
    • Fix: Test with a small file first:
      $config->setDelimiter("\t"); // For TSV
      

Debugging Tips

  1. Log Rows: Add a debug observer to log problematic rows:

    $interpreter->addObserver(function(array $row) {
        Log::debug('Row:', $row);
    });
    
  2. Validate Config: Ensure configs are applied before parsing:

    $config = new LexerConfig();
    $config->setDelimiter(';'); // Test with semicolon-delimited files
    
  3. Test with Small Files: Use a 2-3 row CSV to verify configs before processing large files.

Extension Points

  1. Custom Lexers/Interpreters: Extend Lexer or Interpreter for domain-specific parsing:

    class CustomLexer extends Lexer {
        public function parse($file, Interpreter $interpreter, $chunkSize = null) {
            // Custom logic (e.g., skip headers)
            parent::parse($file, $interpreter, $chunkSize);
        }
    }
    
  2. Observer Chaining: Chain observers for multi-step processing:

    $interpreter->addObserver(function(array $row) {
        $row['processed'] = true;
        return $row; // Pass to next observer
    });
    
  3. Event Dispatching: Use Laravel events for decoupled processing:

    $interpreter->addObserver(function(array $row) {
        event(new CsvRowProcessed($row));
    });
    

Config Quirks

  1. Default Values:

    • Delimiter: , (comma)
    • Enclosure: " (double quote)
    • Escape: \ (backslash)
    • Charset: null (no conversion)
  2. File Modes:

    • ExporterConfig::setFileMode(CsvFileObject::FILE_MODE_APPEND) for appending to files.
  3. Performance:

    • For export, use php://temp for large datasets to avoid memory issues:
      $exporter->export('php://temp', $data);
      file_put_contents('large_export.csv', $tempStream);
      

Security

  1. CSV Injection:

    • Sanitize user-uploaded CSV files to prevent malicious payloads (e.g., formulas in Excel CSV).
    • Use Interpreter::unstrict() cautiously—it may expose your app to malformed data.
  2. File Handling:

    • Validate file paths to prevent directory traversal:
      $file
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky