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:
parent
6bf6752818
commit
a20e31da9b
19
app/Resources/views/embeds/modal.html.twig
Normal file
19
app/Resources/views/embeds/modal.html.twig
Normal 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>
|
@ -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']
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
35
src/AppBundle/Service/ModelService.php
Normal file
35
src/AppBundle/Service/ModelService.php
Normal 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,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user