diff --git a/src/Controller/StatisticsController.php b/src/Controller/StatisticsController.php
new file mode 100644
index 00000000..2352db7f
--- /dev/null
+++ b/src/Controller/StatisticsController.php
@@ -0,0 +1,44 @@
+denyAccessUnlessGranted('@tools.statistics');
+
+ return $this->render('/Statistics/statistics.html.twig', [
+ 'helper' => $helper,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/Entity/Attachments/Attachment.php b/src/Entity/Attachments/Attachment.php
index 1e289547..3d886ce1 100644
--- a/src/Entity/Attachments/Attachment.php
+++ b/src/Entity/Attachments/Attachment.php
@@ -33,7 +33,7 @@ use LogicException;
/**
* Class Attachment.
*
- * @ORM\Entity
+ * @ORM\Entity(repositoryClass="App\Repository\AttachmentRepository")
* @ORM\Table(name="`attachments`")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="class_name", type="string")
diff --git a/src/Repository/AttachmentRepository.php b/src/Repository/AttachmentRepository.php
new file mode 100644
index 00000000..37900f2c
--- /dev/null
+++ b/src/Repository/AttachmentRepository.php
@@ -0,0 +1,80 @@
+createQueryBuilder('attachment');
+ $qb->select('COUNT(attachment)')
+ ->where('attachment.path LIKE :like');
+ $qb->setParameter('like', '\\%SECURE\\%%');
+ $query = $qb->getQuery();
+ return (int) $query->getSingleScalarResult();
+ }
+
+ /**
+ * Gets the count of all external attachments (attachments only containing an URL)
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getExternalAttachments(): int
+ {
+ $qb = $this->createQueryBuilder('attachment');
+ $qb->select('COUNT(attachment)')
+ ->where('attachment.path LIKE :http')
+ ->orWhere('attachment.path LIKE :https');
+ $qb->setParameter('http', 'http://%');
+ $qb->setParameter('https', 'https://%');
+ $query = $qb->getQuery();
+ return (int) $query->getSingleScalarResult();
+ }
+
+ /**
+ * Gets the count of all attachments where an user uploaded an file.
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getUserUploadedAttachments(): int
+ {
+ $qb = $this->createQueryBuilder('attachment');
+ $qb->select('COUNT(attachment)')
+ ->where('attachment.path LIKE :base')
+ ->orWhere('attachment.path LIKE :media')
+ ->orWhere('attachment.path LIKE :secure');
+ $qb->setParameter('secure', '\\%SECURE\\%%');
+ $qb->setParameter('base', '\\%BASE\\%%');
+ $qb->setParameter('media', '\\%MEDIA\\%%');
+ $query = $qb->getQuery();
+ return (int) $query->getSingleScalarResult();
+ }
+}
\ No newline at end of file
diff --git a/src/Repository/PartRepository.php b/src/Repository/PartRepository.php
index 91762310..f6ee3e94 100644
--- a/src/Repository/PartRepository.php
+++ b/src/Repository/PartRepository.php
@@ -24,9 +24,45 @@ declare(strict_types=1);
namespace App\Repository;
+use App\Entity\Parts\PartLot;
use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\QueryBuilder;
class PartRepository extends EntityRepository
{
- //TODO
+ /**
+ * Gets the summed up instock of all parts (only parts without an measurent unit)
+ * @return string
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getPartsInstockSum(): string
+ {
+ $qb = new QueryBuilder($this->getEntityManager());
+ $qb->select('SUM(part_lot.amount)')
+ ->from(PartLot::class, 'part_lot')
+ ->leftJoin('part_lot.part', 'part')
+ ->where('part.partUnit IS NULL');
+
+ $query = $qb->getQuery();
+ return $query->getSingleScalarResult();
+ }
+
+ /**
+ * Gets the number of parts that has price informations.
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getPartsCountWithPrice(): int
+ {
+ $qb = $this->createQueryBuilder('part');
+ $qb->select('COUNT(part)')
+ ->innerJoin('part.orderdetails', 'orderdetail')
+ ->innerJoin('orderdetail.pricedetails', 'pricedetail')
+ ->where('pricedetail.price > 0.0');
+
+ $query = $qb->getQuery();
+ return (int) $query->getSingleScalarResult();
+ }
}
diff --git a/src/Services/StatisticsHelper.php b/src/Services/StatisticsHelper.php
new file mode 100644
index 00000000..095c0479
--- /dev/null
+++ b/src/Services/StatisticsHelper.php
@@ -0,0 +1,149 @@
+em = $em;
+ $this->part_repo = $this->em->getRepository(Part::class);
+ $this->attachment_repo = $this->em->getRepository(Attachment::class);
+ }
+
+ /**
+ * Returns the count of distinct parts
+ */
+ public function getDistinctPartsCount(): int
+ {
+ return $this->part_repo->count([]);
+ }
+
+ /**
+ * Returns the summed instocked over all parts (only parts without a measurement unit)
+ * @return string
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getPartsInstockSum(): string
+ {
+ return $this->part_repo->getPartsInstockSum();
+ }
+
+ /**
+ * Returns the number of all parts which have price informations
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getPartsCountWithPrice(): int
+ {
+ return $this->part_repo->getPartsCountWithPrice();
+ }
+
+ /**
+ * Returns the number of datastructures for the given type.
+ * @param string $type
+ * @return int
+ */
+ public function getDataStructuresCount(string $type): int
+ {
+ $arr = [
+ 'attachment_type' => AttachmentType::class,
+ 'category' => Category::class,
+ 'device' => Device::class,
+ 'footprint' => Footprint::class,
+ 'manufacturer' => Manufacturer::class,
+ 'measurement_unit' => MeasurementUnit::class,
+ 'storelocation' => Storelocation::class,
+ 'supplier' => Supplier::class,
+ 'currency' => Currency::class,
+ ];
+
+ if (!isset($arr[$type])) {
+ throw new \InvalidArgumentException('No count for the given type available!');
+ }
+
+ /** @var EntityRepository $repo */
+ $repo = $this->em->getRepository($arr[$type]);
+ return $repo->count([]);
+ }
+
+ /**
+ * Gets the count of all attachments.
+ * @return int
+ */
+ public function getAttachmentsCount(): int
+ {
+ return $this->attachment_repo->count([]);
+ }
+
+ /**
+ * Gets the count of all private/secure attachments
+ * @return int
+ */
+ public function getPrivateAttachmentsCount(): int
+ {
+ return $this->attachment_repo->getPrivateAttachmentsCount();
+ }
+
+ /**
+ * Gets the count of all external (only containing an URL) attachments
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getExternalAttachmentsCount(): int
+ {
+ return $this->attachment_repo->getExternalAttachments();
+ }
+
+ /**
+ * Gets the count of all attachments where the user uploaded an file.
+ * @return int
+ * @throws \Doctrine\ORM\NoResultException
+ * @throws \Doctrine\ORM\NonUniqueResultException
+ */
+ public function getUserUploadedAttachmentsCount(): int
+ {
+ return $this->attachment_repo->getUserUploadedAttachments();
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Trees/ToolsTreeBuilder.php b/src/Services/Trees/ToolsTreeBuilder.php
index b482c8b2..b09111c7 100644
--- a/src/Services/Trees/ToolsTreeBuilder.php
+++ b/src/Services/Trees/ToolsTreeBuilder.php
@@ -58,8 +58,8 @@ class ToolsTreeBuilder
protected $security;
public function __construct(TranslatorInterface $translator, UrlGeneratorInterface $urlGenerator,
- TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator,
- Security $security)
+ TagAwareCacheInterface $treeCache, UserCacheKeyGenerator $keyGenerator,
+ Security $security)
{
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
@@ -187,6 +187,13 @@ class ToolsTreeBuilder
);
}
+ if ($this->security->isGranted('@tools.statistics')) {
+ $show_nodes[] = new TreeViewNode(
+ $this->translator->trans('tree.tools.show.statistics'),
+ $this->urlGenerator->generate('statistics_view')
+ );
+ }
+
return $show_nodes;
}
diff --git a/templates/Statistics/statistics.html.twig b/templates/Statistics/statistics.html.twig
new file mode 100644
index 00000000..5cc2f259
--- /dev/null
+++ b/templates/Statistics/statistics.html.twig
@@ -0,0 +1,134 @@
+{% extends "main_card.html.twig" %}
+
+{# @var StatisticsHelper helper #}
+
+{% block title %}{% trans %}statistics.title{% endtrans %}{% endblock %}
+
+{% block card_title %}
+ {% trans %}statistics.title{% endtrans %}{% endblock %}
+
+{% block card_body %}
+
+
+
+
+
+
+
+ {% trans %}statistics.property{% endtrans %} |
+ {% trans %}statistics.value{% endtrans %} |
+
+
+
+
+ {% trans %}statistics.distinct_parts_count{% endtrans %} |
+ {{ helper.distinctPartsCount }} |
+
+
+ {% trans %}statistics.parts_instock_sum{% endtrans %} |
+ {{ helper.PartsInstockSum }} |
+
+
+ {% trans %}statistics.parts_with_price{% endtrans %} |
+ {{ helper.partsCountWithPrice }} |
+
+
+
+
+
+
+
+
+
+ {% trans %}statistics.property{% endtrans %} |
+ {% trans %}statistics.value{% endtrans %} |
+
+
+
+
+ {% trans %}statistics.categories_count{% endtrans %} |
+ {{ helper.dataStructuresCount("category") }} |
+
+
+ {% trans %}statistics.footprints_count{% endtrans %} |
+ {{ helper.dataStructuresCount("footprint") }} |
+
+
+ {% trans %}statistics.manufacturers_count{% endtrans %} |
+ {{ helper.dataStructuresCount("manufacturer") }} |
+
+
+ {% trans %}statistics.storelocations_count{% endtrans %} |
+ {{ helper.dataStructuresCount("storelocation") }} |
+
+
+ {% trans %}statistics.suppliers_count{% endtrans %} |
+ {{ helper.dataStructuresCount("supplier") }} |
+
+
+ {% trans %}statistics.currencies_count{% endtrans %} |
+ {{ helper.dataStructuresCount("currency") }} |
+
+
+ {% trans %}statistics.measurement_units_count{% endtrans %} |
+ {{ helper.dataStructuresCount("measurement_unit") }} |
+
+
+ {% trans %}statistics.devices_count{% endtrans %} |
+ {{ helper.dataStructuresCount("device") }} |
+
+
+
+
+
+
+
+
+
+ {% trans %}statistics.property{% endtrans %} |
+ {% trans %}statistics.value{% endtrans %} |
+
+
+
+
+ {% trans %}statistics.attachment_types_count{% endtrans %} |
+ {{ helper.dataStructuresCount("attachment_type") }} |
+
+
+ {% trans %}statistics.all_attachments_count{% endtrans %} |
+ {{ helper.AttachmentsCount }} |
+
+
+ {% trans %}statistics.user_uploaded_attachments_count{% endtrans %} |
+ {{ helper.UserUploadedAttachmentsCount }} |
+
+
+ {% trans %}statistics.private_attachments_count{% endtrans %} |
+ {{ helper.PrivateAttachmentsCount }} |
+
+
+ {% trans %}statistics.external_attachments_count{% endtrans %} |
+ {{ helper.ExternalAttachmentsCount }} |
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file