Thursday, May 13, 2021

Simple PHP CSV Class | Digipiph

Simple PHP CSV Class | Digipiph

🔥 Save unlimited web pages along with a full PDF snapshot of each page.
Unlock Premium →

Throughout my years in programming I've dealt a lot with reading and importing CSV files, exporting queries into CSV files, and building dynamic CSV files. I decided it was time to create a simple PHP class to do all this work for me.

With this class you can change the terminator, separator, enclosed, and escaped characters as well as mime type. You decide the file name and there are simple built in functions to let you easily navigate the rows and columns of the CSV.

The class is compatible with newer AND older (less than 5.3.0) versions of PHP.

Download the PHP CSV Class from Bitbucket here.

Here are some examples of how to use the simple PHP CSV Class.

Reading a CSV File

include('class-CSV.php');     //Start the CSV object and provide a filename  $csv = new CSV("testfile");  $csv->readCSV("/home/example/public_html/files/test.csv");     //if the file had a header row you would use  //$csv->readCSV("/home/example/public_html/files/test.csv", true);     //access the data  $totalRows = $csv->totalRows();  $totalCols = $csv->totalCols();  for($row=0; $row<$totalRows; $row++) {    for($col=0; $col<$totalCols; $col++) {      $value = $csv->getRowCol($row, $col);      echo 'Row: '.$row.' Col: '.$col.' Value: '.$value.'<br />';    }    }

Building and Adding to a CSV Object

include('class-CSV.php');     //Start the CSV object and provide a filename  $csv = new CSV("testfile");     //create the header row  $headerRow = array("ID", "NAME", "POSITION");  $csv->headerColumns($headerRow);     //add some data  $data = array(1, "John Doe", "Sales");  $csv->addRow($data);

Retrieving a Specific Row and Column Value

include('class-CSV.php');     //Start the CSV object and provide a filename  $csv = new CSV("testfile");     //create the header row  $headerRow = array("ID", "NAME", "POSITION");  $csv->headerColumns($headerRow);     //add some data  $data = array(1, "John Doe", "Sales");  $csv->addRow($data);  $dataTwo = array(2, "Bobby Bush", "Admin");  $csv->addRow($data);     //show the value of specific row and column  echo $csv->getRowCol(0, 1); //outputs "John Doe"     //show the value of specific row and column using header values  echo $csv->getRowCol(1, $csv->getHeaderIndex("NAME")); //outputs "Bobby Bush"

Exporting a CSV File

include('class-CSV.php');     //Start the CSV object and provide a filename  $csv = new CSV("testfile");     //create the header row  $headerRow = array("ID", "NAME", "POSITION");  $csv->headerColumns($headerRow);     //add some data  $data = array(1, "John Doe", "Sales");  $csv->addRow($data);  $dataTwo = array(2, "Bobby Bush", "Admin");  $csv->addRow($data);     //export the data to a CSV file  $csv->export();

Source: https://digipiph.com/blog/simple-php-csv-class
This web page was saved on Wednesday, May 12 2021.

Upgrade to Premium Plan

✔ Save unlimited bookmarks.

✔ Get a complete PDF copy of each web page

✔ Save PDFs, DOCX files, images and Excel sheets as email attachments.

✔ Get priority support and access to latest features.

Upgrade now →

Thursday, May 06, 2021

VSCode prevent file Explorer from jumping

VSCode prevent file Explorer from jumping

🔥 Save unlimited web pages along with a full PDF snapshot of each page.
Unlock Premium →

Is there a way to prevent VSCode from jumping all over the place when closing a tab? It jumps to the location of the selected tab, but this is very disorienting when opening various files to inspect within a lib.

0

This behaviour is controlled by the following setting:

"explorer.autoReveal": false  

There is currently no setting for keeping the selected file in the explorer, but this one at least keeps the scroll position fixed and prevents the "jumping".

Update

In current versions, the same setting now keeps the selected file.

2

After you apply "explorer.autoReveal": false, as mentioned above, you can also set up

a shortcut to force show the current file in Explorer:

{ "key": "cmd+e", "command": "workbench.files.action.showActiveFileInExplorer" }  

3

As commented in issue 23902 (Option to keep file selected in sidebar without forcing a scroll)

  • If set autoReveal to true, the jumping inside file explorer is confusing;
  • If set autoReveal to false, I have to use showActiveFileInExplorer keybinding or right click menu every time when switch between tabs

But with VSCode 1.46 (May 2020) you now have:

Explorer auto reveal focus without forcing a scroll

There is a new option focusNoScroll for the explorer.autoReveal setting.

When using this option, the Explorer will automatically select files when opening them but will not scroll to reveal them in the Explorer view.

Not the answer you're looking for? Browse other questions tagged or ask your own question.

Source: https://stackoverflow.com/questions/40336835/vscode-prevent-file-explorer-from-jumping
This web page was saved on Thursday, May 06 2021.

Upgrade to Premium Plan

✔ Save unlimited bookmarks.

✔ Get a complete PDF copy of each web page

✔ Save PDFs, DOCX files, images and Excel sheets as email attachments.

✔ Get priority support and access to latest features.

Upgrade now →

Tuesday, May 04, 2021

09. Test factories - stitcher.io

09. Test factories - stitcher.io

🔥 Save unlimited web pages along with a full PDF snapshot of each page.
Unlock Premium →

Scout APM helps PHP developers pinpoint N+1 queries, memory leaks & more so you can troubleshoot fast & get back to coding faster. Start your free 14-day trial today.

Note: this chapter mostly addresses domain-related code. We'll come back to the application layer in future chapters.

In this chapter of Laravel beyond CRUD, we're going to look at how we can manage domain data for tests. Test factories in Laravel are a known concept, though they lack in many areas: they aren't very flexible and are also kind of a black box to the user.

Take the example of factory states, a powerful pattern, yet poorly implemented in Laravel.

$factory->state(Invoice::class, 'pending', [      'status' => PaidInvoiceState::class,  ]);

First of all: your IDE has no clue what kind of object $factory actually is. It magically exists in factory files, though there's no autocompletion on it. A quick fix is to add this docblock, though that's cumbersome.

  $factory->state();

Second, states are defined as strings, making them a black box when actually using a factory in tests.

public function test_case()  {      $invoice = factory(Invoice::class)          ->states()          ->create();  }

Third, there's no type hinting on the result of a factory, your IDE doesn't know that $invoice actually is an Invoice model; again: a black box.

And finally, given a large enough domain, you might need more than just a few states in your test suite, which become difficult to manage over time.

In this chapter we'll look at an alternative way of implementing this factory pattern, to allow much more flexibility and improve their user experience significantly. The actual goal of these factory classes is to help you write integration tests, without having to spend too much time on setting up the system for it.

Note that I say "integration tests" and not "unit tests": when we're testing our domain code, we're testing the core business logic. More often than not, testing this business logic means we won't be testing an isolated piece of a class, but rather a complex and intricate business rule which requires some (or lots of) data to be present in the database.

As I've mentioned before: we're talking about large and complex systems in this book; it's important to keep that in mind. In particular, that's why I decided to call these tests integration tests in this chapter; it was in order to avoid going into discussions about what unit tests are and what they aren't.

# A basic factory

A test factory is nothing more than a simple class. There's no package to require, no interfaces to implement or abstract classes to extend. The power of a factory is not the complexity of the code, but rather one or two patterns properly applied.

Here's what such a class looks like, simplified:

class InvoiceFactory  {      public static function new(): self      {          return new self();      }            public function create(array $extra = []): Invoice      {          return Invoice::create(array_merge(              [                  'number' => 'I-1',                  'status' => PendingInvoiceState::class,                                ],              $extra          ));         }  }

Let's discuss a few design decisions.

First of all, the static constructor new. You might be confused as to why we need it, as we could simply make the create method static. I'll answer that question in depth later in this chapter, but for now you should know that we want this factory to be highly configurable before actually creating an invoice. So rest assured, it will become clearer soon.

Secondly, why the name new for the static constructor? The answer is a practical one: within the context of factories, make and create are often associated with a factory actually producing a result. new helps us avoid unnecessary confusion.

Finally, the create method: it takes an optional array of extra data to ensure we can always make some last-minute changes in our tests.

With our simple example, we can now create invoices like so:

public function test_case()  {      $invoice = InvoiceFactory::new()->create();  }

Before looking at configurability, let's address a little improvement we can make right away: invoice numbers should be unique, so if we create two invoices in one test case, it will break. We don't want to worry about keeping track of invoice numbers in most cases though, so let's have the factory take care of those:

class InvoiceFactory  {      private static int $number = 0;        public function create(array $extra = []): Invoice      {          self::$number += 1;            return Invoice::create(array_merge(              [                  'number' => 'I-' . self::$number,                                ],              $extra          ));         }  }

# Factories in factories

In the original example, I showed that we might want to create a paid invoice. I was a little naive previously when I assumed this simply meant changing the status field on the invoice model. We also need an actual payment to be saved in the database! Laravel's default factories can handle this with callbacks, which trigger after a model was created; though imagine what happens if you're managing several, maybe even tens of states, each with their own side effects. A simple $factory->afterCreating hook just isn't robust enough to manage all this in a sane way.

So, let's turn things around. Let's properly configure our invoice factory, before creating the actual invoice.

class InvoiceFactory  {      private string $status = null;        public function create(array $extra = []): Invoice      {          $invoice = Invoice::create(array_merge(              [                  'status' => $this->status ?? PendingInvoiceState::class              ],              $extra          ));                    if ($invoice->status->isPaid()) {              PaymentFactory::new()->forInvoice($invoice)->create();          }                    return $invoice;      }        public function paid(): self      {          $clone = clone $this;                    $clone->status = PaidInvoiceState::class;                    return $clone;      }  }

If you're wondering about that clone by the way, we'll look at it later.

The thing we've made configurable is the invoice status, just like factory states in Laravel would do, but in our case there's the advantage that our IDE actually knows what we're dealing with:

public function test_case()  {      $invoice = InvoiceFactory::new()          ->paid()          ->create();  }

Still, there's room for improvement. Have you seen that check we do after the invoice is created?

if ($invoice->status->isPaid()) {      PaymentFactory::new()->forInvoice($invoice)->create();  }

This can be made more flexible still. We're using a PaymentFactory underneath, but what if we want more fine-grained control about how that payment was made? You can imagine there are some business rules about paid invoices that behave differently depending on the type of payment, for example.

Also, we want to avoid passing too much configuration directly into the InvoiceFactory, because it will become a mess very quickly. So how do we solve this?

Here's the answer: we allow the developer to optionally pass a PaymentFactory to InvoiceFactory so that this factory can be configured however the developer wants. Here's how that looks:

public function paid(PaymentFactory $paymentFactory = null): self  {      $clone = clone $this;            $clone->status = PaidInvoiceState::class;      $clone->paymentFactory = $paymentFactory ?? PaymentFactory::new();            return $clone;  }

And here's how it's used in the create method:

if ($this->paymentFactory) {      $this->paymentFactory->forInvoice($invoice)->create();  }

By doing so, a lot of possibilities arise. In this example we're making an invoice that's paid, specifically with a Bancontact payment.

public function test_case()  {      $invoice = InvoiceFactory::new()          ->paid(              PaymentFactory::new()->type(BancontactPaymentType::class)          )          ->create();  }

Another example: we want to test how an invoice is handled when it has been paid, but only after the invoice expiration date:

public function test_case()  {      $invoice = InvoiceFactory::new()          ->expiresAt('2020-01-01')          ->paid(              PaymentFactory::new()->at('2020-01-20')          )          ->create();  }

With just a few lines of code, we get a lot more flexibility.

# Immutable factories

Now what about that cloning earlier? Why is it important to make factories immutable? See, sometimes you need to make several models with the same factory, but with small differences. Instead of creating a new factory object for each model, you could reuse the original factory object, and only change the things you need.

If you're not using immutable factories though, there's a chance that you'll end up with data you didn't actually want. Take the example of the invoice payments: say we need two invoices on the same date, one paid and one pending.

$invoiceFactory = InvoiceFactory::new()      ->expiresAt(Carbon::make('2020-01-01'));    $invoiceA = $invoiceFactory->paid()->create();  $invoiceB = $invoiceFactory->create();

If our paid method wasn't immutable, it would mean that $invoiceB would also be a paid invoice! Sure, we could micro-manage every model creation, but that takes away from the flexibility of this pattern. That's why immutable functions are great: you can set up a base factory, and reuse it throughout your tests, without worrying about unintended side effects!


Built upon these two principles (configuring factories within factories and making them immutable), a lot of possibilities arise. Sure, it takes some time to actually write these factories, but they also save lots of time over the course of development. In my experience, they are well worth the overhead, as there's much more to gain from them compared to their cost.

Ever since using this pattern, I never looked back at Laravel's built-in factories. There's just too much to gain from this approach.

One downside I can come up with is that you'll need a little more extra code to create several models at once. If you want to, however, you can easily add a small piece of code in a base factory class such as this:

abstract class Factory  {            abstract public function create(array $extra = []);        public function times(int $times, array $extra = []): Collection      {          return collect()              ->times($times)              ->map(fn() => $this->create($extra));      }  }

Also keep in mind that you can use these factories for other stuff too, not just models. I've been also using them extensively to set up DTOs, and sometimes even request classes.

I'd suggest to play around with them the next time you're in need of test factories. I can assure you they will not disappoint!

Source: https://stitcher.io/blog/laravel-beyond-crud-09-test-factories
This web page was saved on Monday, May 03 2021.

Upgrade to Premium Plan

✔ Save unlimited bookmarks.

✔ Get a complete PDF copy of each web page

✔ Save PDFs, DOCX files, images and Excel sheets as email attachments.

✔ Get priority support and access to latest features.

Upgrade now →