1. Go to this page and download the library: Download wedrix/watchtower library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
wedrix / watchtower example snippets
#index.php
use App\Doctrine\EntityManager;
use GraphQL\Error\DebugFlag;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use function Wedrix\Watchtower\Executor;
ass the entity manager and other config options using DI or
* configuration objects.
**/
$executor = Executor(
entityManager: $entityManager, // Either as a Singleton or from some DI container
schemaFile: __DIR__ . '/resources/graphql/schema.graphql',
pluginsDirectory: __DIR__ . '/resources/graphql/plugins',
scalarTypeDefinitionsDirectory: __DIR__. '/resources/graphql/scalar_type_definitions',
optimize: true, // Should be false in dev environment
cacheDirectory: __DIR__ . '/var/cache'
);
$response->getBody()
->write(
is_string(
$responseBody = json_encode(
/**
* Call executeQuery() on the request to
* generate the GraphQL response.
**/
$executor->executeQuery(
source: ($input = (array) $request->getParsedBody())['query'] ?? '',
rootValue: [],
contextValue: [
'request' => $request,
'response' => $response,
'args' => $args
],
variableValues: $input['variables'] ?? null,
operationName: $input['operationName'] ?? null,
validationRules: null
)
->toArray(
debug: DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE
)
)
)
? $responseBody
: throw new \Exception("Unable to encode GraphQL result")
);
return $response->withHeader('Content-Type', 'application/json; charset=utf-8');
});
$app->run();
/**
* Serializes an internal value to ue
): string // You can replace 'mixed' with a more specific type
{
}
/**
* Parses an externally provided value (query variable) to use as an input
*/
function parseValue(
string $value
): mixed // You can replace 'mixed' with a more specific type
{
}
/**
* Parses an externally provided literal value (hardcoded in GraphQL query) to use as an input.
*
* @param array<string,mixed>|null $variables
*/
function parseLiteral(
\GraphQL\Language\AST\Node $value,
?array $variables = null
): mixed // You can replace 'mixed' with a more specific type
{
}
#resources/graphql/scalar_type_definitions/date_time_type_definition.php
declare(strict_types=1);
namespace Wedrix\Watchtower\DateTimeTypeDefinition;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Utils\Utils;
function serialize(
\DateTime $value
): string
{
return $value->format(\DateTime::ATOM);
}
function parseValue(
string $value
): \DateTime
{
try {
return new \DateTime($value);
}
catch (\Exception $e) {
throw new Error(
message: "Cannot represent the following value as DateTime: " . Utils::printSafeJson($value),
previous: $e
);
}
}
/**
* @param array<string,mixed>|null $variables
*/
function parseLiteral(
Node $value,
?array $variables = null
): \DateTime
{
if (!$value instanceof StringValueNode) {
throw new Error(
message: "Query error: Can only parse strings got: $value->kind",
nodes: $value
);
}
try {
return parseValue($value->value);
}
catch (\Exception $e) {
throw new Error(
message: "Not a valid DateTime Type",
nodes: $value,
previous: $e
);
}
}
# resources/graphql/plugins/filters/apply_listings_ids_filter.php
declare(strict_types=1);
namespace Wedrix\Watchtower\FilterPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_listings_ids_filter(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$ids = $node->args()['queryParams']['filters']['ids'];
$idsValueAlias = $queryBuilder->reconciledAlias('idsValue');
$queryBuilder->andWhere("{$entityAlias}.id IN (:$idsValueAlias)")
->setParameter($idsValueAlias, $ids);
}
#resources/graphql/plugins/selectors/apply_product_selling_price_selector.php
declare(strict_types=1);
namespace Wedrix\Watchtower\SelectorPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_product_selling_price_selector(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$queryBuilder->addSelect("
$entityAlias.markedPrice - $entityAlias.discount AS sellingPrice
");
}
function function_name(
\Wedrix\Watchtower\Resolver\QueryBuilder $queryBuilder,
\Wedrix\Watchtower\Resolver\Node $node
): void;
#resources/graphql/plugins/resolvers/resolve_currency_exchange_rate_field.php
declare(strict_types=1);
namespace Wedrix\Watchtower\ResolverPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function resolve_currency_exchange_rate_field(
Node $node
): mixed
{
$exchangeRateResolver = $node->context()['exchangeRateResolver']; // Assuming the service was added to $contextValue when Executor::executeQuery() was called
return $exchangeRateResolver->getExchangeRate(
currencyCode: $node->root()['isoCode']
);
}
function function_name(
\Wedrix\Watchtower\Resolver\Node $node
): mixed;
# resources/graphql/plugins/search_resolvers/resolve_books_search.php
declare(strict_types=1);
namespace Wedrix\Watchtower\SearchResolverPlugin;
use Wedrix\Watchtower\Resolver\Node;
function resolve_books_search(
Node $node
): mixed
{
$search = (string) ($node->args()['queryParams']['search'] ?? '');
return [
[
'id' => 1,
'title' => "Search result for $search",
],
];
}
function function_name(
\Wedrix\Watchtower\Resolver\Node $node
): mixed;
$console->addSearchResolverPlugin('Book');
function resolve_user(
Node \$node
): mixed
{
return [
'__typename' => 'Customer', // This indicates the concrete type, i.e., Customer
'name' => 'Sylvester',
'age' => '20 yrs',
'total_spent' => '40000' // This probably could only be applicable to the Customer type
];
}
declare(strict_types=1);
namespace Wedrix\Watchtower\FilterPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_listings_ids_filter(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$ids = $node->args()['queryParams']['filters']['ids'];
$idsValueAlias = $queryBuilder->reconciledAlias('idsValue');
$queryBuilder->andWhere("{$entityAlias}.id IN (:$idsValueAlias)")
->setParameter($idsValueAlias, $ids);
}
function function_name(
\Wedrix\Watchtower\Resolver\QueryBuilder $queryBuilder,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\ConstraintPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_listing_constraint(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$whitelistedListings = ['listing1','listing2','listing3'];
$idsValueAlias = $queryBuilder->reconciledAlias('idsValue');
$queryBuilder->andWhere("{$entityAlias}.id IN (:$idsValueAlias)")
->setParameter($idsValueAlias, $whitelistedListings);
}
function function_name(
\Wedrix\Watchtower\Resolver\QueryBuilder $queryBuilder,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\ConstraintPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_constraint(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$queryBuilder->join("{$entityAlias}.app", 'app')
->andWhere("app.id = :appId")
->setParameter('appId', Config::appId());
}
function function_name(
\Wedrix\Watchtower\Resolver\QueryBuilder $queryBuilder,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\OrderingPlugin;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\QueryBuilder;
function apply_listings_newest_ordering(
QueryBuilder $queryBuilder,
Node $node
): void
{
$entityAlias = $queryBuilder->rootEntityAlias();
$dateCreatedAlias = $queryBuilder->reconciledAlias('dateCreated');
$queryBuilder->addSelect("$entityAlias.dateCreated AS HIDDEN $dateCreatedAlias")
->addOrderBy($dateCreatedAlias, 'DESC');
}
function function_name(
\Wedrix\Watchtower\Resolver\QueryBuilder $queryBuilder,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\MutationPlugin;
use App\Server\Session;
use Wedrix\Watchtower\Resolver\Node;
function call_log_in_user_mutation(
Node $node
): mixed
{
$request = $node->context()['request'] ?? throw new \Exception("Invalid context value! Unset request.");
$response = $node->context()['response'] ?? throw new \Exception("Invalid context value! Unset response.");
$session = new Session(
request: $request,
response: $response
);
$session->login(
email: $node->args()['email'],
password: $node->args()['password']
);
return $session->toArray();
}
function function_name(
\Wedrix\Watchtower\Resolver\Node $node
): mixed;
function function_name(
\Wedrix\Watchtower\Resolver\Node $node
): mixed;
declare(strict_types=1);
namespace Wedrix\Watchtower\AuthorizorPlugin;
use App\Server\Session;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\Result;
use function Wedrix\Watchtower\any_in_array;
function authorize_customer_result(
Result $result,
Node $node
): void
{
$user = new Session(
request: $node->context()['request'] ?? throw new \Exception("Invalid context value! Unset request."),
response: $node->context()['response'] ?? throw new \Exception("Invalid context value! Unset response.")
)
->user();
if (
any_in_array(
needles: \array_keys($node->concreteFieldsSelection()),
haystack: $user->hiddenFields()
)
) {
throw new \Exception("Unauthorized! Hidden field requested.");
}
}
function function_name(
\Wedrix\Watchtower\Resolver\Result $result,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\AuthorizorPlugin;
use App\Server\Session;
use Wedrix\Watchtower\Resolver\Node;
use Wedrix\Watchtower\Resolver\Result;
use function Wedrix\Watchtower\any_in_array;
function authorize_result(
Result $result,
Node $node
): void
{
$user = new Session(
request: $node->context()['request'] ?? throw new \Exception("Invalid context value! Unset request."),
response: $node->context()['response'] ?? throw new \Exception("Invalid context value! Unset response.")
)
->user();
if (
any_in_array(
needles: \array_keys($node->concreteFieldsSelection()),
haystack: $user->hiddenFields()
)
) {
throw new \Exception("Unauthorized! Hidden field requested.");
}
}
function function_name(
\Wedrix\Watchtower\Resolver\Result $result,
\Wedrix\Watchtower\Resolver\Node $node
): void;
declare(strict_types=1);
namespace Wedrix\Watchtower\MutationPlugin;
use Wedrix\Watchtower\Resolver\Node;
use function Wedrix\Watchtower\Resolver\NodeBuffer;
use function Wedrix\Watchtower\Resolver\ResultBuffer;
use function Wedrix\Watchtower\Resolver\BatchKey;
function call_send_notification_mutation(
Node $node
): mixed
{
$batchKey = BatchKey(node: $node);
// 1. Check if the batch result is already cached
if (ResultBuffer()->has($batchKey)) {
$batchResult = ResultBuffer()->get($batchKey);
// Filter to only those relevant for this node
return $batchResult[$node->args()['user_id']];
}
// 2. Collect all matching nodes with the same batch key
$matchingNodes = [];
foreach (NodeBuffer() as $bufferedNode) {
if (BatchKey(node: $bufferedNode)->value() === $batchKey->value()) {
$matchingNodes[] = $bufferedNode;
}
}
// 3. Perform the batch mutation for all matching nodes
$notificationService = $node->context()['notificationService'];
$userIds = \array_map(
static fn (Node $n) => $n->args()['user_id'],
$matchingNodes
);
$batchResult = $notificationService->sendMultiple($userIds, "Hello World!!!");
// 4. Cache the result for subsequent identical mutations
ResultBuffer()->add(
batchKey: $batchKey,
batchResult: $batchResult
);
// Filter to only those relevant for this node
return $batchResult[$node->args()['user_id']];
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.