1. Go to this page and download the library: Download ttskch/bulkony library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
ttskch / bulkony example snippets
use Ttskch\Bulkony\Import\Importer;
$importer = new Importer();
$rowVisitor = new App\ValidatableRowVisitor();
$importer->import('/path/to/input.csv', $rowVisitor);
if ($importer->getErrorListCollection()->isEmpty()) {
echo "Successfully imported!\n";
}
use Ttskch\Bulkony\Export\Exporter;
$exporter = new Exporter();
$rowGenerator = new App\UserRowGenerator();
$exporter->exportAndOutput('users.csv', $rowGenerator); // send HTTP response for downloading
namespace App;
use Ttskch\Bulkony\Export\RowGenerator\RowGeneratorInterface;
class UserRowGenerator implements RowGeneratorInterface
{
public function __construct(private $userRepository)
{
}
public function getHeadingRows(): array
{
// return 2D array so that you can export multiple header rows
return [['id', 'name', 'email']];
}
public function getBodyRowsIterator(): iterable
{
while ($user = $this->userRepository->findNext()) {
// yield 2D array so that you can export multiple rows for one data
yield [
[$user->getId(), $user->getName(), $user->getEmail()],
];
}
}
}
use Ttskch\Bulkony\Export\Exporter;
$exporter = new Exporter();
$rowGenerator = new App\UserRowGenerator();
$exporter->export('/path/to/output.csv', $rowGenerator);
$response = new StreamedResponse();
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', HeaderUtils::makeDisposition(HeaderUtils::DISPOSITION_ATTACHMENT, 'users.csv'));
$response->setCallback(function () use ($exporter, $rowGenerator) {
$exporter->export('php://output', $rowGenerator);
});
return $response->send();
$stream = new CallbackStream(function () use ($exporter, $rowGenerator) {
$exporter->export('php://output', $rowGenerator);
});
return $response
->withType('csv')
->withDownload('users.csv')
->withBody($stream);
use Ttskch\Bulkony\Import\Importer;
$importer = new Importer();
$rowVisitor = new App\UserRowVisitor();
$importer->import('/path/to/input.csv', $rowVisitor);
namespace App;
use Ttskch\Bulkony\Import\RowVisitor\Context;
use Ttskch\Bulkony\Import\RowVisitor\RowVisitorInterface;
class UserRowVisitor implements RowVisitorInterface
{
public function __constructor(private $userRepository)
{
}
public function import(array $csvRow, int $csvLineNumber, Context $context): void
{
$this->userRepository->persist($this->hydrate($csvRow));
}
private function hydrate(array $csvRow): App\User
{
// create App\User instance from csv row in some way
return new App\User($csvRow);
}
}
use Ttskch\Bulkony\Import\Importer;
$importer = new Importer();
$rowVisitor = new App\UserRowVisitor();
$importer->import('/path/to/input.csv', $rowVisitor);
if ($importer->getErrorListCollection()->isEmpty()) {
echo "Successfully imported!\n";
} else {
// you can access to validation errors by csv line number and column (heading) name
// in other words,
// ErrorListCollection : errors in whole csv file
// ErrorList : errors in one csv row
// Error : errors in one csv cell (can contain multiple error messages)
foreach ($importer->getErrorListCollection() as $errorList) {
foreach ($errorList as $error) {
foreach ($error->getMessages() as $message) {
echo sprintf("Error: row %d col `%s`: %s\n", $errorList->getCsvLineNumber(), $error->getCsvHeading(), $message);
}
}
}
}
namespace App;
use Ttskch\Bulkony\Import\RowVisitor\Context;
use Ttskch\Bulkony\Import\RowVisitor\ValidatableRowVisitorInterface;
use Ttskch\Bulkony\Import\Validation\ErrorList;
class UserRowVisitor implements ValidatableRowVisitorInterface
{
public function __constructor(private $userRepository, private $validator)
{
}
public function import(array $csvRow, int $csvLineNumber, Context $context): void
{
$this->userRepository->persist($this->hydrate($csvRow));
}
public function validate(array $csvRow, int $csvLineNumber, ErrorList $errorList, Context $context): void
{
$user = $this->hydrate($csvRow);
foreach ($this->validator->validate($user) as $validationError) {
// get csv heading name from validation error in some way
$csvHeading = $this->getCsvHeadingFromValidationError($validationError);
// upsert Error into ErrorList
$errorList->get($csvHeading, true)->addMessage($validationError->getMessage());
}
}
public function onError(array $csvRow, int $csvLineNumber, ErrorList $errorList, Context $context): bool
{
// you can log errors for one csv row or do something here...
// you can choose continue or abort on error occurred
return ValidatableRowVisitorInterface::CONTINUE_ON_ERROR;
// return ValidatableRowVisitorInterface::ABORT_ON_ERROR;
}
private function hydrate(array $csvRow): App\User
{
// create App\User instance from csv row in some way
return new App\User($csvRow);
}
}
public function import(array $csvRow, int $csvLineNumber, Context $context): void
{
// get hydrated $user
$user = $context['user'];
$this->userRepository->persist($user);
}
public function validate(array $csvRow, int $csvLineNumber, ErrorList $errorList, Context $context): void
{
$user = $this->hydrate($csvRow);
// pass hydrated $user
$context['user'] = $user;
// validate $user ...
}
use Ttskch\Bulkony\Import\Importer;
use Ttskch\Bulkony\Import\Preview\Preview;
$importer = new Importer();
$rowVisitor = new App\UserRowVisitor();
/** @var Preview $preview */
$preview = $importer->preview('/path/to/input.csv', $rowVisitor);
// $preview contains whole csv data and knows WHICH CELL WILL BE CHANGED after importing
render('some/template', [
'preview' => $preview,
]);
namespace App;
use Ttskch\Bulkony\Import\Preview\Row;
use Ttskch\Bulkony\Import\RowVisitor\Context;
use Ttskch\Bulkony\Import\RowVisitor\PreviewableRowVisitorInterface;
class UserRowVisitor implements PreviewableRowVisitorInterface
{
// ...
public function preview(array $csvRow, int $csvLineNumber, Row $previewRow, Context $context): void
{
$originalUser = $this->repository->find($csvRow['id']);
$importedUser = $this->hydrate($csvRow);
if ($originalUser->name !== $importedUser->name) {
$previewRow->get('name')->setChanged();
}
if ($originalUser->email !== $importedUser->email) {
$previewRow->get('email')->setChanged();
}
}
}
namespace App;
use Ttskch\Bulkony\Import\Preview\Row;
use Ttskch\Bulkony\Import\RowVisitor\Context;
use Ttskch\Bulkony\Import\RowVisitor\PreprocessableRowVisitorInterface;
use Ttskch\Bulkony\Import\RowVisitor\PreviewableRowVisitorInterface;
class UserRowVisitor implements PreprocessableRowVisitorInterface, PreviewableRowVisitorInterface
{
// ...
public function preprocess(array $csvRow, int $csvLineNumber, Context $context): void
{
$originalUser = $this->repository->find($csvRow['id']);
$importedUser = $this->hydrate($csvRow);
$context[sprintf('originalUser%d', $csvLineNumber)] = $originalUser;
$context[sprintf('importedUser%d', $csvLineNumber)] = $importedUser;
}
public function import(array $csvRow, int $csvLineNumber, Context $context): void
{
$user = $context[sprintf('originalUser%d', $csvLineNumber)];
$this->userRepository->persist($user);
}
public function preview(array $csvRow, int $csvLineNumber, Row $previewRow, Context $context): void
{
$originalUser = $context[sprintf('originalUser%d', $csvLineNumber)];
$importedUser = $context[sprintf('importedUser%d', $csvLineNumber)];
if ($originalUser->name !== $importedUser->name) {
$previewRow->get('name')->setChanged();
}
if ($originalUser->email !== $importedUser->email) {
$previewRow->get('email')->setChanged();
}
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.