diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig index e19c635..4473593 100644 --- a/app/Resources/views/base.html.twig +++ b/app/Resources/views/base.html.twig @@ -9,8 +9,16 @@ - {{ knp_menu_render('AppBundle:Builder:mainMenu') }} - {% block body %}{% endblock %} + {% block body %} + +
+ {% block content %} + + {% endblock %} +
+ {% endblock %} + {% block javascripts %} diff --git a/app/Resources/views/ldraw/part/index.html.twig b/app/Resources/views/ldraw/part/index.html.twig new file mode 100644 index 0000000..97c3226 --- /dev/null +++ b/app/Resources/views/ldraw/part/index.html.twig @@ -0,0 +1,31 @@ +{% extends 'base.html.twig' %} + +{% import 'macro/part.html.twig' as macro %} + +{% block content %} +
+ {{ form_start(form) }} + + {{ form_row(form.search) }} + +
+ +
+ {{ form_end(form) }} +
+ +
+
+ {% for part in parts %} +
+ {{ macro.part(part) }} +
+ {% endfor %} +
+
+ + {{ knp_pagination_render(parts) }} +{% endblock %} diff --git a/app/Resources/views/ldraw/part/show.html.twig b/app/Resources/views/ldraw/part/show.html.twig new file mode 100644 index 0000000..ff093f9 --- /dev/null +++ b/app/Resources/views/ldraw/part/show.html.twig @@ -0,0 +1,90 @@ +{% extends 'base.html.twig' %} + +{% import 'macro/part.html.twig' as macro %} + +{% block content %} +
+
number:
{{ part.number }}
+
name:
{{ part.name }}
+
category:
{{ part.category.name }}
+
type:
{{ part.type.name }}
+
model:
{{ part.model ? part.model.number }}
+
+ +
+ {% for keyword in part.keywords %} + {{ keyword.name }} + {% endfor %} +
+ +
+ {% if apiPart is not null %} +
+ +
+ {% endif %} + + {% if part is defined and part is not null %} +
+
+ +
+ +

alias of

+ {% if part.aliasOf is not null %} + {{ macro.part(part.aliasOf) }} + {% endif %} + +

aliases

+ {% for alias in part.aliases %} + {{ macro.part(alias) }} + {% endfor %} + +

subparts

+ {% for subpart in part.subparts %} + {{ macro.part(subpart) }} + {% endfor %} + +

subpart of

+ {% for subpart in part.subpartOf %} + {{ macro.part(subpart) }} + {% endfor %} + + {% if part.printOf is not null %} +

print of

+ {{ macro.part(part.printOf) }} + {% endif %} + + {% if part.prints is not empty %} +

prints

+ {% for print in part.prints %} + {{ macro.part(print) }} + {% endfor %} + {% endif %} + + {% endif %} +

in sets

+ {% for set in sets %} + {{ set.number }} + {% endfor %} +
+ + {{ dump(rbPart) }} + {{ dump(apiPart) }} + +{% endblock %} + +{% block javascripts %} + {{ parent() }} + + +{% endblock %} \ No newline at end of file diff --git a/app/Resources/views/macro/part.html.twig b/app/Resources/views/macro/part.html.twig new file mode 100644 index 0000000..e9cf053 --- /dev/null +++ b/app/Resources/views/macro/part.html.twig @@ -0,0 +1,6 @@ +{% macro part(part) %} +
+ +

{{ part.number }}

+
+{% endmacro %} \ No newline at end of file diff --git a/app/Resources/views/part/detail.html.twig b/app/Resources/views/part/detail.html.twig deleted file mode 100644 index 9fbd654..0000000 --- a/app/Resources/views/part/detail.html.twig +++ /dev/null @@ -1,96 +0,0 @@ -{% extends 'base.html.twig' %} - -{% block body %} - - {{ dump(part) }} - {{ dump(rbPart) }} - - {{ dump(apiPart) }} - - -
- {% if apiPart is not null %} -
- -
- {% endif %} - - {% if part is not null %} -
-
- -
- -

alias of

- {% if part.aliasOf is not null %} -
- -

{{ part.aliasOf.id }}

-
- {% endif %} - -

aliases

- {% for alias in part.aliases %} -
- -

{{ alias.id }}

-
- {% endfor %} - -

subparts

- {% for subpart in part.subparts %} -
- -

{{ subpart.id }}

-
- {% endfor %} - -

subpart of

- {% for subpart in part.subpartOf %} -
- -

{{ subpart.id }}

-
- {% endfor %} - - {% if part.printOf is not null %} -

print of

-
- -

{{ part.printOf.id }}

-
- {% endif %} - - {% if part.prints is not empty %} -

prints

- {% for print in part.prints %} -
- -

{{ print.id }}

-
- {% endfor %} - {% endif %} - - {% endif %} -

in sets

- {% for inventory in inventories %} - {{ inventory.set.number }} - {% endfor %} -
- -{% endblock %} - -{% block javascripts %} - {{ parent() }} - - -{% endblock %} \ No newline at end of file diff --git a/app/Resources/views/part/index.html.twig b/app/Resources/views/part/index.html.twig deleted file mode 100644 index 007f3ad..0000000 --- a/app/Resources/views/part/index.html.twig +++ /dev/null @@ -1,30 +0,0 @@ -{% extends 'base.html.twig' %} - - -{% block body %} -

- total parts {{ parts.TotalItemCount }} - -

- - -
- {% for part in parts %} -
- -

{{ part.id }}

-

{{ part.name }}

-
- {% endfor %} -
- -

- -

- - -{% endblock %} \ No newline at end of file diff --git a/app/config/service/form.yml b/app/config/service/form.yml new file mode 100644 index 0000000..8dcc806 --- /dev/null +++ b/app/config/service/form.yml @@ -0,0 +1,7 @@ +services: + form.filter.category: + class: AppBundle\Form\Filter\CategoryFilterType + arguments: + - '@manager.ldraw.category' + tags: + - { name: form.type } \ No newline at end of file diff --git a/app/config/services.yml b/app/config/services.yml index eba0605..213c66c 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -4,3 +4,4 @@ imports: - { resource: service/loader.yml } - { resource: service/manager.yml } - { resource: service/service.yml } + - { resource: service/form.yml } diff --git a/src/AppBundle/Controller/LDraw/PartController.php b/src/AppBundle/Controller/LDraw/PartController.php new file mode 100644 index 0000000..e794c8a --- /dev/null +++ b/src/AppBundle/Controller/LDraw/PartController.php @@ -0,0 +1,88 @@ +getDoctrine()->getManager(); + + $form = $this->get('form.factory')->create(PartFilterType::class); + + $filterBuilder = $this->get('repository.ldraw.part') + ->createQueryBuilder('part'); + +// $filterBuilder->where('part.type = 1'); + + if ($request->query->has($form->getName())) { + // manually bind values from the request + $form->submit($request->query->get($form->getName())); + + // build the query from the given form object + $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $filterBuilder); + } + + $paginator = $this->get('knp_paginator'); + $parts = $paginator->paginate( + $filterBuilder->getQuery(), + $request->query->getInt('page', 1)/*page number*/, + $request->query->getInt('limit', 100)/*limit per page*/ + ); + + return $this->render('ldraw/part/index.html.twig', [ + 'parts' => $parts, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a part entity. + * + * @Route("/{number}", name="ldraw_part_show") + * @Method("GET") + */ + public function showAction($number) + { + $em = $this->getDoctrine()->getManager(); + + $rbPart = $em->getRepository(\AppBundle\Entity\Rebrickable\Part::class)->find($number); + + $part = $em->getRepository(Part::class)->find($number); + + $apiPart = null; + try { + $apiPart = $this->get('manager.rebrickable')->getPart($number); + } catch (\Exception $e) { + dump($e); + } + + $sets = $em->getRepository(Set::class)->findAllByPartNumber($number); + + return $this->render('ldraw/part/show.html.twig', [ + 'part' => $part, + 'rbPart' => $rbPart, + 'apiPart' => $apiPart, + 'sets' => $sets, + ]); + } +} diff --git a/src/AppBundle/Controller/PartController.php b/src/AppBundle/Controller/PartController.php deleted file mode 100644 index c25e8c9..0000000 --- a/src/AppBundle/Controller/PartController.php +++ /dev/null @@ -1,80 +0,0 @@ -get('doctrine.orm.default_entity_manager'); - - $part = $em->getRepository(Part::class)->find($id); - $rbPart = $em->getRepository(\AppBundle\Entity\Rebrickable\Part::class)->find($id); - - $apiPart = null; - try { - $apiPart = $this->get('manager.rebrickable')->getPart($id); - } catch (\Exception $e) { - dump($e); - } - - $qb = $em->getRepository('AppBundle:Rebrickable\Inventory')->createQueryBuilder('i'); - - $qb->innerJoin(Inventory_Part::class, 'ip', Join::WITH, 'i.id = ip.inventory') - ->where('ip.part = :part') - ->setParameter('part', $id)->distinct(true); - - $inventries = $qb->getQuery()->getResult(); - - return $this->render('part/detail.html.twig', [ - 'part' => $part, - 'rbPart' => $rbPart, - 'apiPart' => $apiPart, - 'inventories' => $inventries, - ]); - } - - /** - * @Route("/", name="parts_index") - */ - public function indexAction(Request $request) - { - $em = $this->getDoctrine()->getManager(); - - $queryBuilder = $em->getRepository(Part::class)->createQueryBuilder('p'); - - /** @var QueryBuilder $queryBuilder */ -// $queryBuilder->where('p.model is not null'); - $queryBuilder->join(Type::class,'type', JOIN::WITH, 'p.type = type.id')->where( $queryBuilder->expr()->notIn('type.name', ['Alias', 'Obsolete/Subpart'])); - - $query = $queryBuilder->getQuery(); - - $paginator = $this->get('knp_paginator'); - - $parts = $paginator->paginate( - $query, - $request->query->getInt('page', 1)/*page number*/, - $request->query->getInt('limit', 100)/*limit per page*/ - ); - - return $this->render('part/index.html.twig', [ - 'parts' => $parts, - ]); - } -} diff --git a/src/AppBundle/Form/Filter/CategoryFilterType.php b/src/AppBundle/Form/Filter/CategoryFilterType.php new file mode 100644 index 0000000..90f068f --- /dev/null +++ b/src/AppBundle/Form/Filter/CategoryFilterType.php @@ -0,0 +1,49 @@ +categoryManager = $categoryManager; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('id', Filters\ChoiceFilterType::class, [ + 'choices' => $this->categoryManager->findAll(), + 'choice_label' => 'name', + 'label' => 'filter.part.category', + ]); + } + + public function getParent() + { + return Filters\SharedableFilterType::class; // this allow us to use the "add_shared" option + } + + public function getBlockPrefix() + { + return 'category_filter'; + } + + public function setDefaultOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Category::class, + 'csrf_protection' => false, + 'validation_groups' => ['filtering'], // avoid NotBlank() constraint-related message + 'method' => 'GET', + ]); + } +} diff --git a/src/AppBundle/Form/Filter/PartFilterType.php b/src/AppBundle/Form/Filter/PartFilterType.php new file mode 100644 index 0000000..ce12c92 --- /dev/null +++ b/src/AppBundle/Form/Filter/PartFilterType.php @@ -0,0 +1,58 @@ +add('search', Filters\TextFilterType::class, [ + 'apply_filter' => [$this, 'partSearchCallback'], + 'label' => 'filter.part.search', + ]); + + $builder->add('category', CategoryFilterType::class, [ + 'add_shared' => function (FilterBuilderExecuterInterface $builderExecuter) { + $builderExecuter->addOnce($builderExecuter->getAlias().'.category', 'c', function (QueryBuilder $filterBuilder, $alias, $joinAlias, $expr) { + $filterBuilder->leftJoin($alias.'.category', $joinAlias); + }); + }, + ]); + } + + public function getBlockPrefix() + { + return 'part_filter'; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'csrf_protection' => false, + 'validation_groups' => ['filtering'], // avoid NotBlank() constraint-related message + ]); + } + + public function partSearchCallback(QueryInterface $filterQuery, $field, $values) + { + if (empty($values['value'])) { + return null; + } + + // expression that represent the condition + $expression = $filterQuery->getExpr()->orX( + $filterQuery->getExpr()->like('part.number', ':value'), + $filterQuery->getExpr()->like('part.name', ':value') + ); + + return $filterQuery->createCondition($expression, ['value' => '%'.$values['value'].'%']); + } +}