1
0
mirror of https://github.com/ToxicCrack/PrintABrick.git synced 2025-05-17 21:00:09 -07:00

Change ZipStream to ZipArchive

This commit is contained in:
David Hübner 2017-05-05 21:04:25 +02:00
parent 6bf6752818
commit a20e31da9b
9 changed files with 241 additions and 51 deletions

View File

@ -0,0 +1,19 @@
<div class="ui modal">
<i class="close icon"></i>
{% if block('title') is not empty %}
<div class="header">
{% block title %}{% endblock %}
</div>
{% endif %}
<div class="content">
{% block content %}{% endblock %}
</div>
{% if block('actions') is not empty %}
<div class="actions">
{% block actions %}{% endblock %}
</div>
{% endif %}
</div>

View File

@ -17,11 +17,15 @@ services:
service.zip:
class: AppBundle\Service\ZipService
arguments: ['@oneup_flysystem.media_filesystem', '@service.set']
arguments: ['@oneup_flysystem.media_filesystem', '@service.set', '@service.model']
service.set:
class: AppBundle\Service\SetService
arguments: ['@repository.rebrickable.inventorypart'] arguments: ['@repository.rebrickable.inventorypart'] app.part_image_loader:
arguments: ['@repository.rebrickable.inventorypart']
service.model:
class: AppBundle\Service\ModelService
app.part_image_loader:
class: AppBundle\Imagine\PartImageLoader
arguments: ['@api.manager.rebrickable', '@oneup_flysystem.media_filesystem']

View File

@ -9,7 +9,9 @@ use AppBundle\Form\Filter\Model\ModelFilterType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
/**
* Part controller.
@ -59,11 +61,11 @@ class ModelController extends Controller
*/
public function detailAction($number)
{
$em = $this->getDoctrine()->getManager();
/** @var Model $model */
if ($model = $this->get('repository.ldraw.model')->findOneByNumber($number)) {
try {
$subparts = $this->get('service.model')->getAllSubparts($model);
$rbParts = $model != null ? $this->get('repository.rebrickable.part')->findAllByModel($model) : null;
$sets = $model != null ? $this->get('repository.rebrickable.set')->findAllByModel($model) : null;
@ -74,6 +76,7 @@ class ModelController extends Controller
'rbParts' => $rbParts,
'sets' => $sets,
'related' => $related,
'subparts' => $subparts,
]);
} catch (\Exception $e) {
$this->addFlash('error', $e->getMessage());
@ -87,8 +90,21 @@ class ModelController extends Controller
* @Route("/{number}/zip", name="model_zip")
* @Method("GET")
*/
public function zipAction(Model $model)
public function zipAction(Request $request, Model $model)
{
$zip = $this->get('service.zip')->createFromModel($model);
$zip = $this->get('service.zip')->createFromModel($model, true);
$response = new BinaryFileResponse($zip);
$response->headers->set('Content-Type', 'application/zip');
// Create the disposition of the file
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
"model_{$model->getNumber()}_{$model->getName()}.zip"
);
$response->headers->set('Content-Disposition', $disposition);
return $response;
}
}

View File

@ -3,14 +3,15 @@
namespace AppBundle\Controller;
use AppBundle\Api\Exception\ApiException;
use AppBundle\Api\Exception\EmptyResponseException;
use AppBundle\Entity\Rebrickable\Inventory_Set;
use AppBundle\Entity\Rebrickable\Set;
use AppBundle\Form\Filter\Set\SetFilterType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
/**
* @Route("/sets")
@ -55,10 +56,12 @@ class SetController extends Controller
public function detailAction(Request $request, Set $set)
{
$bricksetSet = null;
$colors = null;
$partCount = $this->get('repository.rebrickable.inventoryPart')->getPartCount($set->getNumber(), false);
try {
$bricksetSet = $this->get('api.manager.brickset')->getSetByNumber($set->getNumber());
if (!($bricksetSet = $this->get('api.manager.brickset')->getSetByNumber($set->getNumber()))) {
$this->addFlash('warning', "{$set->getNumber()} not found in Brickset database");
}
} catch (ApiException $e) {
$this->addFlash('error', $e->getService());
} catch (\Exception $e) {
@ -68,6 +71,7 @@ class SetController extends Controller
return $this->render('set/detail.html.twig', [
'set' => $set,
'brset' => $bricksetSet,
'partCount' => $partCount,
]);
}
@ -113,7 +117,8 @@ class SetController extends Controller
try {
$models = $this->get('service.set')->getModels($set, false);
$spareModels = $this->get('service.set')->getModels($set, true);
$missing = $this->get('repository.rebrickable.inventorypart')->findAllBySetNumber($set->getNumber(), false, false);
$missing = $this->get('service.set')->getParts($set, false, false);
// $missing = $this->get('repository.rebrickable.inventorypart')->findAllBySetNumber($set->getNumber(), false, false);
$missingSpare = $this->get('repository.rebrickable.inventorypart')->findAllBySetNumber($set->getNumber(), true, false);
} catch (\Exception $e) {
$this->addFlash('error', $e->getMessage());
@ -197,6 +202,22 @@ class SetController extends Controller
public function zipAction(Request $request, Set $set)
{
$sorted = $request->query->get('sorted') == 1 ? true : false;
$this->get('service.zip')->createFromSet($set, $sorted);
$sort = $sorted ? 'sorted' : 'unsorted';
$zip = $this->get('service.zip')->createFromSet($set, $sorted);
$response = new BinaryFileResponse($zip);
$response->headers->set('Content-Type', 'application/zip');
// Create the disposition of the file
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
"set_{$set->getNumber()}_{$set->getName()}({$sort}).zip"
);
$response->headers->set('Content-Disposition', $disposition);
return $response;
}
}

View File

@ -26,7 +26,9 @@ class Inventory_PartRepository extends BaseRepository
$queryBuilder = $this->createQueryBuilder('inventory_part')
->where('inventory_part.inventory = :inventory')
->setParameter('inventory', $inventory);
->setParameter('inventory', $inventory)
->join(Part::class, 'part', JOIN::WITH, 'inventory_part.part = part')
->andWhere('part.category != 17');
if ($spare !== null) {
$queryBuilder
@ -35,8 +37,6 @@ class Inventory_PartRepository extends BaseRepository
}
if ($model !== null) {
$queryBuilder
->join(Part::class, 'part', JOIN::WITH, 'inventory_part.part = part');
if ($model === true) {
$queryBuilder->andWhere('part.model IS NOT NULL');
} else {
@ -59,4 +59,32 @@ class Inventory_PartRepository extends BaseRepository
return $queryBuilder->getQuery()->getResult();
}
public function getPartCount($number, $spare = null, $model = null)
{
$inventory = $this->getEntityManager()->getRepository(Inventory::class)->findNewestInventoryBySetNumber($number);
$queryBuilder = $this->createQueryBuilder('inventory_part')
->where('inventory_part.inventory = :inventory')
->setParameter('inventory', $inventory)
->join(Part::class, 'part', JOIN::WITH, 'inventory_part.part = part')
->andWhere('part.category != 17')
->select('SUM(inventory_part.quantity) as parts');
if ($spare !== null) {
$queryBuilder
->andWhere('inventory_part.spare = :spare')
->setParameter('spare', $spare);
}
if ($model !== null) {
if ($model === true) {
$queryBuilder->andWhere('part.model IS NOT NULL');
} else {
$queryBuilder->andWhere('part.model IS NULL');
}
}
return $queryBuilder->getQuery()->getSingleScalarResult();
}
}

View File

@ -19,4 +19,12 @@ class ThemeRepository extends BaseRepository
return $queryBuilder->getQuery()->getResult();
}
public function findAllMain()
{
$queryBuilder = $this->createQueryBuilder('theme')
->where('theme.parent IS NULL');
return $queryBuilder->getQuery()->getResult();
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace AppBundle\Service;
use AppBundle\Entity\LDraw\Model;
class ModelService
{
private $models = [];
public function getAllSubparts(Model $model)
{
foreach ($model->getSubparts() as $subpart) {
$this->resursiveLoadModels($subpart->getSubpart(), $subpart->getCount());
}
return $this->models;
}
private function resursiveLoadModels(Model $model, $quantity = 1)
{
if (($model->getSubparts()->count() !== 0)) {
foreach ($model->getSubparts() as $subpart) {
$this->resursiveLoadModels($subpart->getSubpart(), $subpart->getCount());
}
} else {
$q = isset($this->models[$model->getNumber()]['quantity']) ? $this->models[$model->getNumber()]['quantity'] : 0;
$this->models[$model->getNumber()] = [
'quantity' => $q + $quantity,
'model' => $model,
];
}
}
}

View File

@ -110,7 +110,6 @@ use AppBundle\Entity\LDraw\Model;
return $models;
}
/**
* Get array models grouped by color.
* [
@ -163,4 +162,31 @@ use AppBundle\Entity\LDraw\Model;
return $colors;
}
/*
* @param Set $set
* @param bool $spare If true - add only spare parts, false - add only regular parts, null - add all parts
*
* @return array
*/
public function getParts(Set $set, $spare = null, $model = false)
{
$parts = [];
$inventoryParts = $this->inventoryPartRepository->findAllBySetNumber($set->getNumber(), $spare, $model);
/** @var Inventory_Part $inventoryPart */
foreach ($inventoryParts as $inventoryPart) {
if (isset($parts[$inventoryPart->getPart()->getNumber()])) {
$parts[$inventoryPart->getPart()->getNumber()]['quantity'] += $inventoryPart->getQuantity();
} else {
$parts[$inventoryPart->getPart()->getNumber()] = [
'part' => $inventoryPart->getPart(),
'quantity' => $inventoryPart->getQuantity(),
];
}
}
return $parts;
}
}

View File

@ -5,11 +5,10 @@ namespace AppBundle\Service;
use AppBundle\Entity\LDraw\Model;
use AppBundle\Entity\Rebrickable\Set;
use League\Flysystem\Filesystem;
use ZipStream\ZipStream;
class ZipService
{
/** @var ZipStream */
/** @var \ZipArchive */
private $archive;
/** @var Filesystem */
@ -18,26 +17,41 @@ class ZipService
/** @var SetService */
private $setService;
/** @var ModelService */
private $modelService;
private $zipName;
private $models;
/**
* ZipService constructor.
*
* @param $mediaFilesystem
* @param $setService
*/
public function __construct($mediaFilesystem, $setService)
public function __construct($mediaFilesystem, $setService, $modelService)
{
$this->mediaFilesystem = $mediaFilesystem;
$this->setService = $setService;
$this->modelService = $modelService;
}
private function createZip($path)
{
$archive = new \ZipArchive();
$archive->open($path, \ZipArchive::CREATE);
return $archive;
}
public function createFromSet(Set $set, $sorted = false)
{
$sort = $sorted ? 'sorted' : 'unsorted';
$this->zipName = "set_{$set->getNumber()}_{$set->getName()}({$sort})";
$filename = "set_{$set->getNumber()}_{$set->getName()}({$sort}).zip";
// Initialize zip stream
$this->archive = new ZipStream($filename);
$zipPath = tempnam(sys_get_temp_dir(), 'printabrick');
$this->archive = $this->createZip($zipPath);
if ($sorted) {
$this->addSetGroupedByColor($set);
@ -45,23 +59,35 @@ class ZipService
$this->addSet($set);
}
$this->archive->finish();
$this->addLicense();
$this->archive->close();
return $this->archive;
return $zipPath;
}
public function createFromModel(Model $model, $subparts = false)
{
$filename = "model_{$model->getNumber()}.zip";
$this->zipName = "model_{$model->getNumber()}";
// Initialize zip stream
$this->archive = new ZipStream($filename);
$zipPath = tempnam(sys_get_temp_dir(), 'printabrick');
$this->archive = $this->createZip($zipPath);
$this->addModel($model);
$filename = "{$this->zipName}/{$model->getNumber()}.stl";
$this->addModel($filename, $model);
$this->archive->finish();
if ($subparts) {
foreach ($this->modelService->getAllSubparts($model) as $subpart) {
$submodel = $subpart['model'];
$filename = "{$this->zipName}/submodels/{$submodel->getNumber()}_({$subpart['quantity']}x).stl";
return $this->archive;
$this->addModel($filename, $submodel);
}
}
$this->addLicense();
$this->archive->close();
return $zipPath;
}
/**
@ -81,9 +107,9 @@ class ZipService
$model = $modelArray['model'];
$quantity = $modelArray['quantity'];
$filename = "{$color->getName()}/{$model->getNumber()}_({$quantity}x).stl";
$filename = "{$this->zipName}/{$color->getName()}/{$model->getNumber()}_({$quantity}x).stl";
$this->archive->addFile($filename, $this->mediaFilesystem->read($model->getPath()));
$this->addModel($filename, $model);
}
}
}
@ -99,26 +125,33 @@ class ZipService
$models = $this->setService->getModels($set, $spare);
foreach ($models as $number => $array) {
$model = $array['model'];
$quantity = $array['quantity'];
$filename = $number."_({$quantity}x).stl";
$filename = "{$this->zipName}/{$number}_({$quantity}x).stl";
$this->models[$number] = $array['model'];
$this->archive->addFile($filename, $this->mediaFilesystem->read($array['model']->getPath()));
$this->addModel($filename, $model);
}
}
public function addModel(Model $model, $count = 1, $folder = '')
private function addModel($path, $model)
{
$filename = $folder.$model->getNumber()."_({$count}x).stl";
$this->archive->addFile($filename, $this->mediaFilesystem->read($model->getPath()));
foreach ($model->getSubparts() as $subpart) {
$this->addModel($subpart->getSubpart(), $subpart->getCount(), $folder.$model->getNumber().'_subparts/');
}
$this->archive->addFromString($path, $this->mediaFilesystem->read($model->getPath()));
$this->models[$model->getNumber()] = $model;
}
// TODO add licence file and information to zip file
public function addLicence()
private function addLicense()
{
$text = sprintf('All stl files in this archive were converted by LDView from LDraw Library http://www.ldraw.org/'."\n\n");
$text .= sprintf('Files are licensed under the Creative Commons - Attribution license.'."\n");
$text .= sprintf('http://creativecommons.org/licenses/by/2.0/'."\n\n");
$text .= sprintf('Attribution:'."\n"."\n");
foreach ($this->models as $model) {
$text .= sprintf('%s - "%s" by %s'."\n", $model->getNumber(), $model->getName(), $model->getAuthor()->getName());
}
$this->archive->addFromString("{$this->zipName}/LICENSE.txt", $text);
}
}