Recently, I have been working on a project that involves exporting transaction records in two formats(PDF and CSV).

I wrote a simple PDF class to manage exports in that format. When I need to export to CSV, I wanted to use an existing PHP library like Leage\CSV but, I felt I should write a simple class to do that.

CSV is a simple file format used to store tabular data, such as a spreadsheet or database. Files in the CSV format can be imported to and exported from programs that store data in tables, such as Microsoft Excel or OpenOffice Calc. CSV stands for “comma-separated values”.

Computer Hope

Let’s get started

So, this simple class, will be able to add headers as a row, append a new header to the headers, add blank spaces, add rows, add a row as well as add title.

Creating the class

<?php
declare(strict_types=1);

class SimpleCsv
{
//...
}

Here, we are declaring PHP strict_type using the declare directive and setting it to true. You can read about that Here.

Class properties

/** @var array $data */
    protected $data = [];

    /** @var array $headers */
    protected $headers = [];

    /** @var array $rows */
    protected $rows = [];

The properties are self explanatory.

Add Header method

/**
     * Adds a new column to the headers row
     *
     * @param string $header
     * @return $this
     */
    public function addHeader(string $header): self
    {
        $this->headers[] = $header;

        $this->data[] = $this->headers;

        $this->headers = [];

        return $this;
    }

This method, accepts the header name as a string, we then append the header to existing headers array. Then, add the headers to our data array. Then, empty our headers array so we don’t affect the next headers to be added and finally return the class instance ($this).

Add title method

     /**
     * Adds a new row to the sheet
     *
     * @param string $title
     * @param int $dashes
     * @param int $margin_left
     * @param string $dash_type
     * @return $this
     */
    public function addTitle(string $title, $dashes = 0, $margin_left = 0, $dash_type = '-'): self
    {
        $newTitle = [];
        $titleDashes = '';

        for ($margin = 0; $margin < $margin_left; $margin++) {
            $newTitle[] = '';
        }

        for ($dash = 0; $dash < $dashes; $dash++) {
            $titleDashes .= $dash_type;
        }

        if ($titleDashes !== '') {
            $title = " {$title} ";
        }

        $newTitle[] = "{$titleDashes}{$title}{$titleDashes}";

        $this->data[] = $newTitle;


        return $this;
    }

The addTitle() method, adds a new row to the sheet. The method takes the title as a string, dashes or some sort of symbols before and after the title and the number of gap(margin) from the left (margin left).

Here is how you can use it

$simpleCsv->addTitle('My sample title', 3, 0, '=');

//Output: === My sample title ===

Add headers method

/**
 * Adds header row to the sheet
 *
 * @param iterable $headers
 * @return $this
 */
public function addHeaders(iterable $headers): self
{
    foreach ($headers as $header) {
        $this->headers[] = $header;
    }

    $this->data[] = $this->headers;
    $this->headers = [];

    return $this;
}

This method adds header row to the sheet. It takes an iterable which is an array of the headers. If you look closely, you see that we reset $this->headers array after adding it to our data array. We are doing that to prevent appending the header to an existing one.

See how you can use it:

$simpleCsv->addHeaders(['Name', 'Email', 'Phone']);

/* Ouput: Name, Email, Phone or Name | Email | Phone */

Add row method

/**
 * Adds a new row as body to the sheet
 *
 * @param iterable $columns
 * @return $this
 */
public function addRow(iterable $columns): self
{
    foreach ($columns as $column) {
        $this->rows[] = $column;
    }

    $this->data[] = $this->rows;
    $this->rows = [];

    return $this;
}

From the docBlock, you will know that this method adds a new row as body to the sheet. This method basically adds new row of record according to your headers. Here also, we are resetting $this->rows so we don’t add the next rows on same line.

See how to use:

$simpleCsv->addRow([
   'Josiah Yahaya', '[email protected]', '08123456789'
]);

Add rows method

/**
 * Adds rows as body to the sheet
 *
 * @param iterable $rows
 * @return SimpleCsv
 */
public function addRows(iterable $rows): self
{
    foreach ($rows as $row) {
        $this->addRow($row);
    }

    return $this;
}

This method is similar to addRow() but this takes a multi-dimensional array i.e array of arrays.

See example below:

$simpleCsv->addRows([
  ['Josiah Yahaya', '[email protected]', '08123456789'],
  ['John Doe', '[email protected]', '08012345678'],
]);

Add space method

/**
 * Adds a blank row or number of rows as provided to the sheet
 *
 * @param int $spaces
 * @return $this
 */
public function addSpace(int $spaces = 0): self
{
    for ($number = 0; $number < $spaces; $number++) {
        $this->data[] = [];
    }

    return $this;
}

This method adds blank spaces to the sheet as specified.

See example:

$simpleCsv->addSpace(2);

//Output will be: 2 empty spaces on the sheet

Download method

/**
 * Downloads the prepared csv file
 *
 * @param string $fileName
 * @return void
 * @throws Exception
 */
public function download(string $fileName = ''): void
{
    if ($fileName === '') {
        $fileName = 'simple_csv_file_' . str_shuffle('sample_csv');
    }

    header('Content-Type: application/csv');
    header('Content-Disposition: attachement; filename="' . $fileName . '.csv"');

    ob_start();
    $file = fopen('php://output', 'wb');

    $number = 0;

    foreach ($this->data as $line) {
        $number++;

        if (!fputcsv($file, $line)) {
            throw new RuntimeException("Can't write line {$number}: {$line}");
        }
    }

    if (!fclose($file)) {
        throw new RuntimeException("Can't close php://output");
    }

    $csvContents = ob_get_clean();

    echo $csvContents;
    exit;
}

This method accepts the filename. If it’s not provided, a random name is generated. Here, we use PHPin-built csv writer function fputcsv() to write the data prepared unto the specified or auto-generated filename. This method will force download since we added Content-Disposition header.

Usage

(new SimpleCsv())
->addTitle('My sample csv file')
->addSpace(3)
->addHeaders(['Name', 'Email', 'Phone'])
->addRow['Josiah Yahaya', '[email protected]', '08123456789'])
->download('simplecsv');

So, that will be all for this tutorial. If you need the file, hit me up here and I will send it to you immediately.

Or take a look below for all the codes.

Cheers!

<?php
declare(strict_types=1);

class SimpleCsv
{
    /** @var array $data */
    protected $data = [];

    /** @var array $headers */
    protected $headers = [];

    /** @var array $rows */
    protected $rows = [];

    /**
     * Adds a new column to the headers row
     *
     * @param string $header
     * @return $this
     */
    public function addHeader(string $header): self
    {
        $this->headers[] = $header;

        $this->data[] = $this->headers;

        $this->headers = [];

        return $this;
    }

    /**
     * Adds a new row to the sheet
     *
     * @param string $title
     * @param int $dashes
     * @param int $margin_left
     * @param string $dash_type
     * @return $this
     */
    public function addTitle(string $title, $dashes = 0, $margin_left = 0, $dash_type = '-'): self
    {
        $newTitle = [];
        $titleDashes = '';

        for ($margin = 0; $margin < $margin_left; $margin++) {
            $newTitle[] = '';
        }

        for ($dash = 0; $dash < $dashes; $dash++) {
            $titleDashes .= $dash_type;
        }

        if ($titleDashes !== '') {
            $title = " {$title} ";
        }

        $newTitle[] = "{$titleDashes}{$title}{$titleDashes}";

        $this->data[] = $newTitle;


        return $this;
    }

    /**
     * Adds header row to the sheet
     *
     * @param iterable $headers
     * @return $this
     */
    public function addHeaders(iterable $headers): self
    {
        foreach ($headers as $header) {
            $this->headers[] = $header;
        }

        $this->data[] = $this->headers;
        $this->headers = [];

        return $this;
    }

    /**
     * Adds a new row as body to the sheet
     *
     * @param iterable $columns
     * @return $this
     */
    public function addRow(iterable $columns): self
    {
        foreach ($columns as $column) {
            $this->rows[] = $column;
        }

        $this->data[] = $this->rows;
        $this->rows = [];

        return $this;
    }

    /**
     * Adds rows as body to the sheet
     *
     * @param iterable $rows
     * @return SimpleCsv
     */
    public function addRows(iterable $rows): self
    {
        foreach ($rows as $row) {
            $this->addRow($row);
        }

        return $this;
    }

    /**
     * Adds a blank row or number of rows as provided to the sheet
     *
     * @param int $spaces
     * @return $this
     */
    public function addSpace(int $spaces = 0): self
    {
        for ($number = 0; $number < $spaces; $number++) {
            $this->data[] = [];
        }

        return $this;
    }

    /**
     * Get the prepared data
     *
     * @return array
     */
    public function getData(): array
    {
        return $this->data;
    }

    /**
     * Downloads the prepared csv file
     *
     * @param string $fileName
     * @return void
     * @throws Exception
     */
    public function download(string $fileName = ''): void
    {
        if ($fileName === '') {
            $fileName = 'simple_csv_file_' . str_shuffle('sample_csv');
        }

        header('Content-Type: application/csv');
        header('Content-Disposition: attachement; filename="' . $fileName . '.csv"');

        ob_start();
        $file = fopen('php://output', 'wb');

        $number = 0;

        foreach ($this->data as $line) {
            $number++;

            if (!fputcsv($file, $line)) {
                throw new RuntimeException("Can't write line {$number}: {$line}");
            }
        }

        if (!fclose($file)) {
            throw new RuntimeException("Can't close php://output");
        }

        $csvContents = ob_get_clean();

        echo $csvContents;
        exit;
    }
}
(Visited 63 times, 1 visits today)

Leave A Comment

Your email address will not be published. Required fields are marked *