Skip to content

Commit

Permalink
Merge pull request #42 from scolandrea/adding-magento_products_by_typ…
Browse files Browse the repository at this point in the history
…e_count_total

Add new metric magento_products_by_type_count_total
  • Loading branch information
VladyslavSikailo authored Nov 22, 2023
2 parents 013b002 + 3f80303 commit 02093df
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The following metrics will be collected:
| magento_catalog_category_count_total | status, menu_status, store_code | gauge | Count of Categories by store, status and menu status. |
| magento_store_count_total | status | gauge | Total count of Stores by status. |
| magento_website_count_total | | gauge | Total count websites. |
| magento_products_by_type_count_total | project_type | gauge | Total count of products by type. |

## Add you own Metric

Expand Down
140 changes: 140 additions & 0 deletions Test/Unit/Aggregator/Product/ProductByTypeCountAggregatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

declare(strict_types=1);

namespace RunAsRoot\PrometheusExporter\Test\Unit\Aggregator\Product;

use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use RunAsRoot\PrometheusExporter\Aggregator\Product\ProductByTypeCountAggregator;
use RunAsRoot\PrometheusExporter\Api\Data\MetricInterface;
use RunAsRoot\PrometheusExporter\Repository\MetricRepository;
use RunAsRoot\PrometheusExporter\Service\UpdateMetricService;

final class ProductByTypeCountAggregatorTest extends TestCase
{
private const METRIC_CODE = 'magento_products_by_type_count_total';
private const TABLE_PRODUCT = 'm2_catalog_product_entity';

private ProductByTypeCountAggregator $subject;

private MetricRepository $metricRepository;

private SearchCriteriaBuilder $searchCriteriaBuilder;

private SearchCriteriaInterface $searchCriteria;

private MockObject|UpdateMetricService $updateMetricService;

private MockObject|ResourceConnection $resourceConnection;

protected function setUp(): void
{
$this->metricRepository = $this->createMock(MetricRepository::class);
$this->searchCriteriaBuilder = $this->createMock(SearchCriteriaBuilder::class);
$this->updateMetricService = $this->createMock(UpdateMetricService::class);
$this->resourceConnection = $this->createMock(ResourceConnection::class);
$this->searchCriteria = $this->createMock(SearchCriteriaInterface::class);

$this->searchCriteriaBuilder->method('create')->willReturn($this->searchCriteria);
$this->searchCriteriaBuilder
->expects($this->once())
->method('addFilter')
->with('code', self::METRIC_CODE)
->willReturnSelf();

$metric = $this->createMock(MetricInterface::class);
$metric->expects($this->once())
->method('setValue')
->with('0');

$searchResultsMock = $this->createMock(\Magento\Framework\Api\SearchResultsInterface::class);
$searchResultsMock->expects($this->once())
->method('getItems')
->willReturn([$metric]);

$this->metricRepository->expects($this->once())
->method('getList')
->with($this->searchCriteria)
->willReturn($searchResultsMock);

$this->metricRepository->expects($this->once())
->method('save')
->with($metric);

$this->subject = new ProductByTypeCountAggregator(
$this->metricRepository,
$this->searchCriteriaBuilder,
$this->updateMetricService,
$this->resourceConnection
);
}

private function getStatisticData(): array
{
return [
['PRODUCT_COUNT' => 111, 'PRODUCT_TYPE' => 'bundle'],
['PRODUCT_COUNT' => 222, 'PRODUCT_TYPE' => 'configurable'],
['PRODUCT_COUNT' => 333, 'PRODUCT_TYPE' => 'giftcard'],
['PRODUCT_COUNT' => 444, 'PRODUCT_TYPE' => 'grouped'],
['PRODUCT_COUNT' => 555, 'PRODUCT_TYPE' => 'simple'],
['PRODUCT_COUNT' => 666, 'PRODUCT_TYPE' => 'virtual']
];
}

private function getSelectMock(): MockObject
{
$select = $this->createMock(Select::class);
$select->expects($this->once())
->method('from')
->with(['p' => self::TABLE_PRODUCT])
->willReturn($select);

$select->expects($this->once())->method('reset')->with(Select::COLUMNS)->willReturn($select);
$select->expects($this->once())->method('group')->with(['p.type_id']);
$select->expects($this->once())
->method('columns')
->with(['PRODUCT_COUNT' => 'COUNT(*)', 'PRODUCT_TYPE' => 'p.type_id'])
->willReturn($select);

return $select;
}

public function testAggregate(): void
{
$connection = $this->createMock(AdapterInterface::class);
$statisticData = $this->getStatisticData();
$select = $this->getSelectMock();

$this->resourceConnection->expects($this->once())
->method('getConnection')
->with()
->willReturn($connection);

$connection->expects($this->once())->method('select')->willReturn($select);
$connection->method('getTableName')
->with('catalog_product_entity')
->willReturn(self::TABLE_PRODUCT);
$connection->expects($this->once())->method('fetchAll')->with($select)->willReturn($statisticData);

$params = [];
foreach ($statisticData as $data) {
$params[] = [
self::METRIC_CODE,
(string)$data['PRODUCT_COUNT'],
['product_type' => $data['PRODUCT_TYPE']]
];
}

$this->updateMetricService->expects($this->exactly(6))
->method('update')
->withConsecutive(...$params);

$this->subject->aggregate();
}
}
103 changes: 103 additions & 0 deletions src/Aggregator/Product/ProductByTypeCountAggregator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

namespace RunAsRoot\PrometheusExporter\Aggregator\Product;

use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use RunAsRoot\PrometheusExporter\Api\Data\MetricInterface;
use RunAsRoot\PrometheusExporter\Api\MetricAggregatorInterface;
use RunAsRoot\PrometheusExporter\Repository\MetricRepository;
use RunAsRoot\PrometheusExporter\Service\UpdateMetricService;

class ProductByTypeCountAggregator implements MetricAggregatorInterface
{
private const METRIC_CODE = 'magento_products_by_type_count_total';

private MetricRepository $metricRepository;
private SearchCriteriaBuilder $searchCriteriaBuilder;
private UpdateMetricService $updateMetricService;
private ResourceConnection $resourceConnection;

public function __construct(
MetricRepository $metricRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
UpdateMetricService $updateMetricService,
ResourceConnection $resourceConnection
) {
$this->metricRepository = $metricRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->updateMetricService = $updateMetricService;
$this->resourceConnection = $resourceConnection;
}

public function getCode(): string
{
return self::METRIC_CODE;
}

public function getHelp(): string
{
return 'Magento 2 Product by type Count';
}

public function getType(): string
{
return 'gauge';
}

public function aggregate(): bool
{
$this->resetMetrics();

$connection = $this->resourceConnection->getConnection();

$productSearchResult = $connection->fetchAll($this->getSelect($connection));

if (count($productSearchResult) === 0) {
return true;
}

foreach ($productSearchResult as $result) {
$count = $result['PRODUCT_COUNT'] ?? 0;
$productType = $result['PRODUCT_TYPE'] ?? '';

$labels = ['product_type' => $productType];

$this->updateMetricService->update(self::METRIC_CODE, (string)$count, $labels);
}

return true;
}


protected function resetMetrics(): void
{
$searchCriteriaMetrics = $this->searchCriteriaBuilder->addFilter('code', self::METRIC_CODE)->create();
$metricsSearchResult = $this->metricRepository->getList($searchCriteriaMetrics);
$metrics = $metricsSearchResult->getItems();
/** @var MetricInterface $metric */
foreach ($metrics as $metric) {
$metric->setValue("0");
$this->metricRepository->save($metric);
}
}

private function getSelect(AdapterInterface $connection): Select
{
$select = $connection->select();

$select->from(['p' => $connection->getTableName('catalog_product_entity')])
->reset(Select::COLUMNS)->columns(
[
'PRODUCT_COUNT' => 'COUNT(*)',
'PRODUCT_TYPE' => 'p.type_id'
]
)->group(['p.type_id']);

return $select;
}
}
1 change: 1 addition & 0 deletions src/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

<!-- Product Aggregator -->
<item name="ProductCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Product\ProductCountAggregator</item>
<item name="ProductByTypeCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Product\ProductByTypeCountAggregator</item>

<!-- Shipping Aggregator -->
<item name="ActiveShippingMethodsCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Shipping\ActiveShippingMethodsCountAggregator</item>
Expand Down

0 comments on commit 02093df

Please sign in to comment.