Fixes #24 XmlInco Full process of pictures

This commit is contained in:
Jérémy Munsch 2023-02-24 11:44:25 +01:00
parent 97361f7a56
commit 33d2f4e573
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
11 changed files with 153 additions and 83 deletions

View file

@ -313,8 +313,8 @@ class ProductController extends Controller
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$storagePublicDisk = Storage::disk('public');
$pictureBaseName = $picture['filename'];
$pictureExtension = \pathinfo($picture['filename'], \PATHINFO_EXTENSION);
$pictureBaseName = $picture['file_name'];
$pictureExtension = \pathinfo($picture['file_name'], \PATHINFO_EXTENSION);
/**
* We create one file in tmp to be resized

View file

@ -41,7 +41,7 @@ class XmlIncoController extends Controller
$stream = $disk->readStream($picturePath);
\fpassthru($stream);
\fclose($stream);
}, $inco_picture, [
}, \pathinfo($inco_picture, \PATHINFO_BASENAME), [
'Content-Type' => $disk->mimeType($picturePath),
'Content-Length' => $disk->size($picturePath),
'Content-Disposition' => 'inline',

View file

@ -3,8 +3,10 @@
namespace App\Jobs;
use App\Exceptions\AbortXmlImportException;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\XmlInco;
use SimpleXMLElement;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
class XmlIncoReader extends XmlJobs
{
@ -419,7 +421,7 @@ class XmlIncoReader extends XmlJobs
public function handle()
{
$this->parseData('INCO', XmlInco::class, function (SimpleXMLElement $xmlData, array &$line) {
$this->parseData('INCO', XmlInco::class, function (\SimpleXMLElement $xmlData, array &$line) {
// Merge columns.
foreach ($this->mergeColumns as $key => $values) {
@ -442,70 +444,83 @@ class XmlIncoReader extends XmlJobs
(strtolower($line['prod_saison']) == 'non' ? false : true) : false;
$arImgPaths = $this->parseImage($xmlData);
$line['picturse'] = $arImgPaths;
$line['pictures'] = $arImgPaths;
});
}
/**
* Extract Image form XML file
*
* @param SimpleXMLElement $xmlData
* @param \SimpleXMLElement $xmlData
* @return array
* @throws AbortXmlImportException When media tag does not contain an image.
*/
private function parseImage(SimpleXMLElement $xmlData)
private function parseImage(\SimpleXMLElement $xmlData)
{
$list_media = $xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI;
$arImgPaths = array();
$index = 1;
/** @var \Illuminate\Support\Collection<\SimpleXMLElement> */
$list_media = collect($xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI);
$arImgPaths = \collect();
foreach ($list_media as $media) {
$i = -1;
$list_media->each(function ($media) use ($xmlData, $arImgPaths, &$i) {
$i++;
/** @var \SimpleXMLElement|null */
$image = $media->img;
$imageData = trim((string)$image);
if (strlen($imageData)) {
$imageData = base64_decode($imageData);
$imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO);
if (empty($imgName)) {
$imgName = strval($xmlData->INCO->NO_ART);
}
// * Store only picture name.
$imgNamePath = $imgName . "_" . $index;
$disk = $this->getDisk();
if (!strlen($imageData)) {
return;
}
$info = getimagesizefromstring($imageData);
if ($info !== false) {
$mime = $info['mime'];
switch ($mime) {
case 'image/jpeg':
$imgExtension = 'jpg';
break;
case 'image/png':
$imgExtension = 'png';
break;
case 'image/gif':
$imgExtension = 'gif';
break;
default:
throw new AbortXmlImportException(sprintf('Unknown image type %s', $imgName));
}
$imageData = \strval(base64_decode($imageData));
$imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO ?? $xmlData->INCO->NO_ART);
$imgNamePath = "{$imgName}_" . \uniqid();
$imgNamePath = sprintf('%s.%s', $imgNamePath, $imgExtension);
$info = getimagesizefromstring($imageData);
if ($info === false) {
Log::debug("Skipping file {$imgNamePath} on index {$i} as could not determine picture info.");
return;
}
if (!$disk->put($imgNamePath, $imageData)) {
throw new AbortXmlImportException(sprintf('The image %s could not be saved', $imgNamePath));
}
$mime = $info['mime'];
switch ($mime) {
case 'image/jpeg':
$imgExtension = 'jpg';
break;
case 'image/png':
$imgExtension = 'png';
break;
case 'image/gif':
$imgExtension = 'gif';
break;
default:
throw new AbortXmlImportException(sprintf('Unknown image type %s', $imgName));
}
$arImgPaths[$index] = sprintf('%s/%s', $this->disk, $imgNamePath);
$index++;
}//end if
}//end if
}//end foreach
$imgNamePath = FileStorageHelper::sanitizeFileName("{$imgNamePath}-{$i}.{$imgExtension}");
return $arImgPaths;
if (!($file = tempnam(sys_get_temp_dir(), $imgNamePath))) {
throw new \RuntimeException('Could not initiate a php temp file');
}
if (!File::put($file, $imageData)) {
throw new \RuntimeException('Could not write to the php temp file');
}
$arImgPaths->push(FileStorageHelper::storeFile(
new XmlInco(),
new \SplFileInfo($file),
true,
$imgNamePath,
true
));
});
return $arImgPaths->all();
}
/**
* Recursive extract to array
* introduce sort of Hook to transform
@ -530,7 +545,7 @@ class XmlIncoReader extends XmlJobs
protected function extract($sxe = null): array
{
if (!$sxe instanceof SimpleXMLElement) {
if (!$sxe instanceof \SimpleXMLElement) {
return array();
}
$extract = array();

View file

@ -330,7 +330,7 @@ abstract class XmlJobs extends XArcadiaFlux
*/
protected function sendErrorParseEmailToServiceWeb(Throwable $e)
{
Mail::send('emails.exception', [
Mail::send('back::emails.exception', [
'exception' => $e,
'appName' => config('app.name'),
], function ($m) {
@ -351,7 +351,7 @@ abstract class XmlJobs extends XArcadiaFlux
protected function sendInvalidXmlEmail(string $filename, Throwable $e)
{
$message = $e->getPrevious()->getMessage();
Mail::send('emails.invalidxml', [
Mail::send('back::emails.invalidxml', [
'strError' => sprintf(
'File %s could not be parsed => %s on line %d',
$filename,

View file

@ -82,13 +82,22 @@ class FileStorageHelper
* @param \Illuminate\Http\UploadedFile|\SplFileInfo|string $file The file, will just return itself is string.
* @param boolean $slugify Force filename slugification.
* @param string|null $filename This string may be used to store the file.
* @param boolean $private To store the file in a private space.
* @return string
* @throws \RuntimeException If file copy fails.
*/
public static function storeFile(Model $model, $file, bool $slugify = false, string $filename = null): string
{
public static function storeFile(
Model $model,
$file,
bool $slugify = false,
string $filename = null,
bool $private = false
): string {
$tableName = $model->getTable();
if (\is_object($file) and $file instanceof \Illuminate\Http\UploadedFile) {
if ($private) {
throw new \RuntimeException('Private storage for uploaded files is unhandled');
}
/** @var \Illuminate\Http\UploadedFile $file */
$filename = $filename ?: $file->getClientOriginalName();
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
@ -104,7 +113,7 @@ class FileStorageHelper
/** @var \SplFileInfo $file */
$filename = $filename ?: $file->getBaseName();
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
$newPath = self::prepareMoveFile($tableName, $filename);
$newPath = self::prepareMoveFile($tableName, $filename, $private);
if (!File::copy($file->getRealPath(), $newPath)) {
throw new \RuntimeException(sprintf(
'Failed to copy file %s to %s',
@ -112,7 +121,9 @@ class FileStorageHelper
$newPath
));
}
return \ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/');
return $private ?
\ltrim(str_replace(\storage_path('app/private'), '/storage/app/private', $newPath), '/') :
\ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/');
}
return strval($file);
}
@ -268,11 +279,12 @@ class FileStorageHelper
* Prepare storage path and return
* the file full path
*
* @param string $tableName Model table name.
* @param string $filename The basename for the file.
* @param string $tableName Model table name.
* @param string $filename The basename for the file.
* @param boolean $private May the file be stored in a private dir.
* @return string
*/
private static function prepareMoveFile(string $tableName, string $filename): string
private static function prepareMoveFile(string $tableName, string $filename, bool $private = false): string
{
// * Security filter + beautifier
$filename = self::sanitizeFileName($filename);
@ -283,7 +295,12 @@ class FileStorageHelper
$filename = Str::slug(\pathinfo($filename, \PATHINFO_FILENAME)) .
(\strlen($ext) ? ".{$ext}" : '');
$folderPath = self::getStoragePath($tableName, $filename);
$folderPath = self::getStoragePath(
$private ? 'app/private/modelfiles' : 'app/public/modelfiles',
$tableName,
$filename,
$private
);
$filename = self::getFileUniqueName($folderPath, $filename);
return "{$folderPath}/{$filename}";
}
@ -293,15 +310,17 @@ class FileStorageHelper
* storage/modelfiles/posts/10/04/19/5f
* year/month/day/md5 first 2 letters
*
* @param string $storage_dir
* @param string $table
* @param string $filename
* @return string
*/
private static function getStoragePath(string $table, string $filename): string
private static function getStoragePath(string $storage_dir, string $table, string $filename): string
{
$filenameHash = \md5($filename);
$pathFolder = \storage_path(sprintf(
'app/public/modelfiles/%s/%s/%s/%s/%s',
'%s/%s/%s/%s/%s/%s',
$storage_dir,
$table,
gmdate('y'),
gmdate('m'),

View file

@ -53,29 +53,22 @@ class XmlInco extends Model
*
* @var string
*/
protected static $disk = 'inco';
/**
* Storage path
*
* @var string
*/
protected static $imagesPath = 'images';
protected static $disk = 'private';
// * METHODS
/**
* Get xml inco picture path
*
* @param string $pictureName
* @param string $inco_picture
* @return null|string
*/
public static function getXmlIncoPicturePath(string $pictureName): ?string
public static function getXmlIncoPicturePath(string $inco_picture): ?string
{
$disk = static::getDisk();
$picturePath = static::$imagesPath . "/{$pictureName}";
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = static::getDisk();
return $disk->exists($picturePath) ? $picturePath : null;
return $disk->exists($inco_picture) ? $inco_picture : null;
}
/**
@ -85,16 +78,15 @@ class XmlInco extends Model
*/
public function getMediaListAttribute(): Collection
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = static::getDisk();
/** @var \Illuminate\Support\Collection<array<string,string> */
$collFiles = new Collection();
foreach ($this->pictures as $pictureName) {
$collFiles->add([
'filename' => $pictureName,
'imgdata' => base64_encode($disk->get(
static::$imagesPath . "/{$pictureName}"
))
$collFiles = \collect();
foreach ($this->pictures as $picture_path) {
$collFiles->add(['file_name' => \pathinfo($picture_path, \PATHINFO_BASENAME),
'file_path' => $picture_path,
'imgdata' => base64_encode($disk->get($picture_path))
]);
}
return $collFiles;

View file

@ -65,6 +65,12 @@ return [
'endpoint' => env('AWS_ENDPOINT'),
],
'private' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'url' => env('APP_URL') . '/storage'
],
'inco' => [
'driver' => 'local',
'root' => storage_path('inco')

View file

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class MoveInfoFiles extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$private_disk = Storage::disk('private');
collect(File::glob(storage_path('inco/images/*')))->each(function ($file_path) use ($private_disk) {
if (
!$private_disk->put(
pathinfo($file_path, PATHINFO_BASENAME),
File::get($file_path)
)
) {
throw new \RuntimeException('Failed to move inco file');
}
});
File::deleteDirectory(storage_path('inco/images'));
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

View file

@ -22,7 +22,7 @@
</button>
<div class="form-control alert-info">
<img class="img-fluid" src="{{ route('bo.xml_incos.getXmlIncoPicture', [
'inco_picture' => $picture['filename'],
'inco_picture' => $picture['file_path'],
'resize' => true
]) }}" alt="visuel Inco">
</div>

View file

@ -92,7 +92,7 @@ Route::prefix('bo')->name('bo.')->group(function () {
// * XML INCO
Route::get('/xml_incos/search', [XmlIncoController::class, 'getXmlIncos'])->name('xml_incos.getXmlIncos');
Route::get('/xml_incos/picture/{inco_picture}', [XmlIncoController::class, 'getXmlIncoPicture'])
->where('inco_picture', '[a-zA-Z0-9_-]+\.(png|jpg|jpeg)')
->where('inco_picture', '.+[a-zA-Z0-9_-]+\.(png|jpg|jpeg)')
->name('xml_incos.getXmlIncoPicture');
// * Tags