baks-dev/products-sign
Laravel/PHP module for handling “Честный знак” product marking codes. Installs with baks-dev/barcode, stores uploaded codes in public/upload/product_sign_code, supports PDF cropping (pdftk/pdfcrop) and ImageMagick PDF read/write for generating/processing labels.
Installation:
composer require baks-dev/barcode baks-dev/products-sign
php bin/console baks:assets:install
Setup Storage:
mkdir -p public/upload/product_sign_code
chown -R www-data:www-data public/upload/product_sign_code # Adjust user/group as needed
System Dependencies (Linux):
sudo apt install pdftk texlive-extra-utils
Configure sudo for pdfcrop (add to /etc/sudoers):
www-data ALL=(ALL) NOPASSWD: /usr/bin/pdfcrop
Update ImageMagick policy (/etc/ImageMagick-6/policy.xml):
<policy domain="coder" rights="read|write" pattern="PDF"/>
Database Migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case: Generate a product sign for a product via Artisan:
php bin/console products-sign:generate 1 # Product ID
Verify the output in public/upload/product_sign_code/.
Service Layer:
Use the ProductSignGenerator service to create signs for products:
$generator = app(\BaksDev\ProductsSign\Services\ProductSignGenerator::class);
$generator->generate($productId, $outputPath = null);
$outputPath: Optional. Defaults to storage/app/product_sign_code/.Batch Processing:
For bulk generation (e.g., during nightly jobs), use the BatchGenerator:
$batchGenerator = app(\BaksDev\ProductsSign\Services\BatchGenerator::class);
$batchGenerator->generateForProducts([1, 2, 3]);
Custom Templates: Override default templates by publishing assets:
php artisan vendor:publish --tag=products-sign-views
Modify templates in resources/views/vendor/products-sign/.
Manual Validation: Validate a generated sign via Artisan:
php bin/console products-sign:validate 1 # Product ID
Outputs validation status (e.g., valid, invalid, pending).
API Endpoint: Expose validation via a Laravel route:
Route::post('/api/products/{product}/sign/validate', [ProductSignController::class, 'validate']);
Controller example:
public function validate(Request $request, Product $product) {
$validator = app(\BaksDev\ProductsSign\Services\ProductSignValidator::class);
$result = $validator->validate($product);
return response()->json($result);
}
Webhook Listeners:
Listen for validation events (e.g., SignatureValidated):
public function handle(SignatureValidated $event) {
// Send notification, update UI, etc.
}
File Storage: Retrieve a generated sign:
$path = \BaksDev\ProductsSign\Services\ProductSignStorage::getPath($productId);
$file = Storage::disk('public')->get($path);
Serve via a route:
Route::get('/product-sign/{product}', [ProductSignController::class, 'show']);
Cloud Storage:
Configure config/products-sign.php:
'disk' => 's3',
'bucket' => 'my-product-signs',
Ensure AWS credentials are in .env:
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_DEFAULT_REGION=...
Laravel Nova: Publish Nova resources:
php artisan vendor:publish --tag=products-sign-nova
Customize the ProductSignResource in app/Nova/Resources/.
Custom Admin Panel:
Use the ProductSign model directly:
$signs = ProductSign::where('product_id', $productId)->get();
Display validation status in a table:
@foreach($signs as $sign)
<tr>
<td>{{ $sign->qr_code }}</td>
<td>{{ $sign->status }}</td>
<td>
<a href="{{ $sign->getUrl() }}">Download</a>
</td>
</tr>
@endforeach
public function handle(ProductCreated $event) {
$generator = app(\BaksDev\ProductsSign\Services\ProductSignGenerator::class);
$generator->generate($event->product->id);
}
sign-generation):
dispatch(new GenerateProductSign($productId));
Job example:
public function handle() {
$generator = app(\BaksDev\ProductsSign\Services\ProductSignGenerator::class);
$generator->generate($this->productId);
}
public function testProductSignGeneration() {
$product = Product::factory()->create();
$generator = app(\BaksDev\ProductsSign\Services\ProductSignGenerator::class);
$generator->generate($product->id);
$this->assertFileExists(storage_path("app/product_sign_code/{$product->id}.pdf"));
}
php bin/phpunit --group=products-sign
class CustomProductSignValidator extends \BaksDev\ProductsSign\Services\ProductSignValidator {
public function validate(Product $product) {
$result = parent::validate($product);
// Add custom checks
if ($product->isPremium()) {
$result['premium_check'] = $this->checkPremiumSign($product);
}
return $result;
}
}
Bind the custom validator in a service provider:
$this->app->bind(
\BaksDev\ProductsSign\Services\ProductSignValidator::class,
\App\Services\CustomProductSignValidator::class
);
pdftk/pdfcrop Missing:
If pdfcrop fails silently, check:
sudo chmod +x /usr/bin/pdfcrop).sudo configuration (ensure www-data can run pdfcrop without a password).setasign/fpdf for simpler PDF generation if pdftk is unavailable.ImageMagick Policy:
If PDF generation fails with PDF not allowed, verify /etc/ImageMagick-6/policy.xml has:
<policy domain="coder" rights="read|write" pattern="PDF"/>
Restart the web server after changes:
sudo systemctl restart apache2 # or nginx
Storage Directory:
Ensure public/upload/product_sign_code is writable by the web server user (e.g., www-data):
chown -R www-data:www-data public/upload/product_sign_code
chmod -R 755 public/upload/product_sign_code
Symlink Issue: If using storage:link, verify the symlink is correct:
php bin/console storage:link
Cloud Storage:
If using S3, ensure the IAM user has s3:PutObject and s3:GetObject permissions.
Schema Changes: Always run migrations after updating the package:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Rollback: If migrations fail, use:
php bin/console doctrine:migrations:migrate --down
Existing Data: If the schema changes (e.g., new columns), update existing records:
ProductSign::query()->update(['new_column' => null]);
How can I help you explore Laravel packages today?