feat(mcp) : add business tools — search, history, comments, custom fields, documents, model types
- search_inventory: global search across all 6 entity types - get_entity_history + get_activity_log: audit trail access - 4 comment tools: list, create, resolve, unresolved count - 3 custom field tools: list values, upsert, delete - 2 document tools: list, delete (upload via REST only) - 6 model type tools: list, get, create, update, delete, sync - 69 MCP tests pass total Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
114
src/Mcp/Tool/CustomField/UpsertCustomFieldValuesTool.php
Normal file
114
src/Mcp/Tool/CustomField/UpsertCustomFieldValuesTool.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Mcp\Tool\CustomField;
|
||||
|
||||
use App\Entity\Composant;
|
||||
use App\Entity\CustomField;
|
||||
use App\Entity\CustomFieldValue;
|
||||
use App\Entity\Machine;
|
||||
use App\Entity\Piece;
|
||||
use App\Entity\Product;
|
||||
use App\Mcp\Tool\McpToolHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Mcp\Capability\Attribute\McpTool;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
#[McpTool(
|
||||
name: 'upsert_custom_field_values',
|
||||
description: 'Create or update custom field values for a given entity. Each entry in the fields array needs customFieldId and value. If a value already exists for that custom field + entity, it is updated; otherwise a new one is created. Requires ROLE_GESTIONNAIRE.',
|
||||
)]
|
||||
class UpsertCustomFieldValuesTool
|
||||
{
|
||||
use McpToolHelper;
|
||||
|
||||
private const ALLOWED_TYPES = ['machine', 'composant', 'piece', 'product'];
|
||||
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
public function __invoke(string $entityType, string $entityId, array $fields): array
|
||||
{
|
||||
$this->requireRole($this->security, 'ROLE_GESTIONNAIRE');
|
||||
|
||||
$entityType = strtolower($entityType);
|
||||
|
||||
if (!in_array($entityType, self::ALLOWED_TYPES, true)) {
|
||||
$this->mcpError('validation', "entityType must be one of: machine, composant, piece, product. Got '{$entityType}'.");
|
||||
}
|
||||
|
||||
$entityClass = match ($entityType) {
|
||||
'machine' => Machine::class,
|
||||
'composant' => Composant::class,
|
||||
'piece' => Piece::class,
|
||||
'product' => Product::class,
|
||||
};
|
||||
|
||||
$entity = $this->em->getRepository($entityClass)->find($entityId);
|
||||
|
||||
if (null === $entity) {
|
||||
$this->mcpError('not_found', ucfirst($entityType)." not found: {$entityId}");
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
foreach ($fields as $fieldEntry) {
|
||||
$customFieldId = $fieldEntry['customFieldId'] ?? null;
|
||||
$value = $fieldEntry['value'] ?? '';
|
||||
|
||||
if (null === $customFieldId) {
|
||||
$this->mcpError('validation', 'Each field entry must have a customFieldId.');
|
||||
}
|
||||
|
||||
$customField = $this->em->getRepository(CustomField::class)->find($customFieldId);
|
||||
|
||||
if (null === $customField) {
|
||||
$this->mcpError('not_found', "CustomField not found: {$customFieldId}");
|
||||
}
|
||||
|
||||
$existing = $this->em->getRepository(CustomFieldValue::class)->findOneBy([
|
||||
'customField' => $customField,
|
||||
$entityType => $entity,
|
||||
]);
|
||||
|
||||
if (null !== $existing) {
|
||||
$existing->setValue((string) $value);
|
||||
$results[] = [
|
||||
'id' => $existing->getId(),
|
||||
'customFieldId' => $customField->getId(),
|
||||
'value' => (string) $value,
|
||||
'action' => 'updated',
|
||||
];
|
||||
} else {
|
||||
$cfv = new CustomFieldValue();
|
||||
$cfv->setCustomField($customField);
|
||||
$cfv->setValue((string) $value);
|
||||
|
||||
$setter = 'set'.ucfirst($entityType);
|
||||
$cfv->{$setter}($entity);
|
||||
|
||||
$this->em->persist($cfv);
|
||||
$this->em->flush();
|
||||
|
||||
$results[] = [
|
||||
'id' => $cfv->getId(),
|
||||
'customFieldId' => $customField->getId(),
|
||||
'value' => (string) $value,
|
||||
'action' => 'created',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return $this->jsonResponse([
|
||||
'entityType' => $entityType,
|
||||
'entityId' => $entityId,
|
||||
'results' => $results,
|
||||
'total' => count($results),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user