Download the PHP package wedrix/watchtower without Composer

On this page you can find all versions of the php package wedrix/watchtower. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package watchtower

Watchtower

Watchtower helps you serve GraphQL APIs from Doctrine ORM entities without writing the same resolver boilerplate over and over. You provide a GraphQL SDL schema, point Watchtower at your Doctrine EntityManager, and add small plugin files only where your API needs custom behavior.

It is built on graphql-php and works well in Symfony, Slim, or any PHP application that already uses Doctrine ORM.

What You Get

Requirements

Doctrine ORM 3 requires PHP 8.1 or newer.

Nested collection pagination with limit requires a database with SQL window function support, such as PostgreSQL, MySQL 8+, MariaDB 10.2+, SQLite 3.25+, SQL Server 2005+, Oracle, or DB2.

Installation

For Symfony applications, the companion bundle has framework-specific installation notes: github.com/Wedrix/watchtower-symfony-bundle

A Symfony demo application is available here: github.com/Wedrix/watchtower-symfony-demo-application

Project Layout

Watchtower only needs a few writable paths in your application:

The exact paths are up to your application. Use the same paths when creating the Console and Executor.

Basic Setup

Watchtower exposes two entry points:

Create a Console Helper

Wrap the Console object in whatever CLI system your project already uses.

Generate the starter SDL from Doctrine mappings:

Use the generated SDL as a starting point. generateSchema() creates entity query types and built-in scalar definitions for DateTime, Limit, Page, and Cursor when they do not already exist. Add mutations, subscriptions, enum/interface/union definitions, and custom computed fields to the SDL yourself.

After editing an existing SDL file, run schema:update if your application uses the schema cache. It clears stale schema cache files; it does not merge Doctrine mapping changes into your SDL.

Add a GraphQL Endpoint

In an HTTP endpoint, create an Executor and call executeQuery().

Pass framework services, request objects, users, tenants, or other application state through contextValue; plugins can read it from $node->context().

Schema Usage

Watchtower uses GraphQL SDL as the public contract for your API.

Top-level query fields can find entities by unique identifiers. Relation fields resolve automatically when the GraphQL field maps to a Doctrine association.

For compound keys, pass all fields that make a unique key. For example, if your SDL exposes a field like this:

query it with both key parts:

Through Associations

Direct Doctrine associations do not need extra SDL directives. If a field represents a relation through an explicit association entity, add @watchtowerAssociation.

The through value is the association field on the returned type.

Abstract Types

Enums, interfaces, and unions are normal SDL. Resolver, mutation, or search plugins that return interface or union results must include __typename.

Pagination

Collection fields are paginated through queryParams.

Use offset pagination with limit and optional page:

Use cursor pagination with after or before, usually with limit and a deterministic ordering:

Use the last returned row's _cursor as after for the next page, or the first returned row's _cursor as before for the previous page. If you maintain SDL manually, declare _cursor: Cursor on entity types where clients can request cursors:

Treat _cursor as an opaque string in clients. Pass the returned value back as after or before; clients do not need to decode or edit it.

Ordering plugins used with cursor pagination must call $queryBuilder->registerCursorOrdering() for every ordered value that belongs in the cursor. If a query uses multiple orderings, register cursor fields in the same order as the effective ORDER BY clauses. Include a stable unique tie-breaker, usually id, at the end.

If you need to create cursor values directly in tests or custom tooling, encode a JSON object with every registered cursor key:

Cursor pagination rules:

Plugins

Plugins are plain PHP files loaded from the configured pluginsDirectory. Use console helpers to generate the files, then fill in the application logic.

The console writes each plugin into the correct directory with the expected function name. Fill in the generated function body.

For addResultAuthorizorPlugin(), pass false for a single-object result authorizor and true for a collection result authorizor.

Use case Directory Function shape
Computed database field selectors/ apply_book_summary_selector(QueryBuilder $queryBuilder, Node $node): void
Computed service-backed field resolvers/ resolve_book_external_rating_field(Node $node): mixed
Search-backed collection search_resolvers/ resolve_books_search(Node $node): mixed
Pre-resolution authorization node_authorizors/ authorize_book_node(Node $node): void
Global pre-resolution authorization node_authorizors/ authorize_node(Node $node): void
Always-on private selection projections/ project_book(QueryBuilder $queryBuilder, Node $node): void
Client-supplied filter filters/ apply_books_ids_filter(QueryBuilder $queryBuilder, Node $node): void
Always-on query constraint constraints/ apply_book_constraint(QueryBuilder $queryBuilder, Node $node): void
Global query constraint constraints/ apply_constraint(QueryBuilder $queryBuilder, Node $node): void
Client-supplied ordering orderings/ apply_books_title_asc_ordering(QueryBuilder $queryBuilder, Node $node): void
Mutation field mutations/ call_create_book_mutation(Node $node): mixed
Subscription field subscriptions/ call_book_created_subscription(Node $node): mixed
Result authorization result_authorizors/ authorize_book_result(Result $result, Node $node): void
Global result authorization result_authorizors/ authorize_result(Result $result, Node $node): void

The generated namespace must stay as-is. For example, node authorizors use Wedrix\Watchtower\NodeAuthorizorPlugin, result authorizors use Wedrix\Watchtower\ResultAuthorizorPlugin, and mutations use Wedrix\Watchtower\MutationPlugin.

Filters

Expose filters in SDL:

Then implement the filter plugin:

Clients use it like this:

Sharing Joins Between Plugins

When a constraint, filter, ordering, or selector needs an association, use joinOnce() or leftJoinOnce() when the query should have exactly one join for that path. These methods follow Doctrine's join style and return the builder. If the same join already exists with a different alias, Watchtower throws so the duplicate shape is caught early.

When a plugin needs to reference the alias, ask for the join alias first:

For deeper paths, compose the chain explicitly and use the alias returned from each step:

Choose the join method that matches the data you want:

Use selectAlias() for AS or AS HIDDEN aliases, and parameterName() for named parameters such as :tenantId.

For expensive association paths, add a query-shape test. Call $queryBuilder->assertNoDuplicateJoins() after your plugins have modified the query, or set WATCHTOWER_STRICT_QUERY_SHAPE=1 in test runs. If you want to make your own assertion, duplicateJoinPaths() returns repeated equivalent joins by path and alias.

Orderings

Expose orderings in SDL. Each ordering takes a required rank; lower ranks are applied first.

Implement the ordering plugin:

Use the optional fourth argument to pass the Doctrine/DBAL parameter type used when comparing cursor values.

Computed Fields

Use a selector when the value can be selected by the Doctrine query:

Use a resolver when the value comes from PHP code, another service, or an external API:

Resolvers and mutations can return null, int, bool, float, string, arrays, or values handled by custom scalars. Object results should be associative arrays; collection results should be lists.

Search

Add a search field to the collection query params and create a search resolver:

When queryParams.search is present and a search resolver exists for the type, return the full collection result from the search resolver. The resolver receives only the current Node; the context keys above are application-defined.

HydrationQuery(Node $node, EntityManager $entityManager, Plugins $plugins, bool $applyFilters = true) is optional. It returns a fresh Doctrine query with base selections, projections, constraints, and client filters applied. Pass false as the fourth argument to omit filters. Construct it only for the current node or another already-authorized node from the same search batch. It deliberately applies neither ordering nor pagination, which remain owned by the search provider. A resolver that skips hydration must provide any private values its result authorizors require.

Mutations

Declare mutations in SDL and implement the matching mutation plugin.

Constraints, Projections, Node Authorizors, and Result Authorizors

Use constraints to apply query restrictions before Doctrine fetches data, such as tenant scoping or soft-delete rules.

Use a node authorizor for rules that can be decided from the operation, arguments, selected fields, and context. It runs before Doctrine queries, search calls, resolvers, mutations, and subscriptions.

Use a projection to add private selects, shared joins, or parameters needed by downstream query plugins and result authorizors on every Doctrine hydration path.

Use result authorizors to validate resolved results across queries, search, mutations, and subscriptions.

For collections, Watchtower runs the root result authorizor once, the collection result authorizor once, and then the singular result authorizor for every non-null row. The singular result authorizor receives the original collection Node, so it can distinguish the collection path with isACollection(). Individual results keep the root-then-singular order.

Use constraints for mandatory database predicates, node authorizors for request-shape rules that must fail before work begins, and result authorizors for row-dependent checks.

Custom Scalars

Create a scalar definition stub:

This creates money_type_definition.php in scalar_type_definitions/. Implement serialize(), parseValue(), and parseLiteral() in the generated namespace:

Production Cache

While developing, use optimize: false so file edits are picked up without regenerating the cache.

For production:

  1. Give each application release its own cache directory. Configure Console() and Executor() with the same directory for that release.
  2. Generate the complete cache during deployment, before starting that release's request-serving workers. If generation fails, do not activate the release.
  3. Create the executor with optimize: true.
  4. When the schema, plugins, or scalar definitions change, generate a new release's cache instead of replacing the cache used by running workers.

Each cache file is published atomically, so readers cannot observe a partially written file. The schema, scalar definitions, and plugins are replaced separately, however; publication is not atomic across the complete set. Different releases must not share a cache directory, because their workers could read mismatched files. Workers using the same unchanged release may generate its cache concurrently.

The example below assumes __DIR__ belongs to an immutable release directory and var/cache is not shared with other releases. For an external cache location, include the release identifier in the path, such as /var/cache/my-app/release-123, and use that path for both the console and executor. Retain the old release's cache until its workers have stopped.

Security

Watchtower delegates execution to graphql-php. Use graphql-php validation rules, depth limits, complexity limits, authentication, and transport protections appropriate for your application: webonyx.github.io/graphql-php/security

Pass custom validation rules through $executor->executeQuery(..., validationRules: $rules).

Common Gotchas

Development

Run the test suite:

Run grouped workflows:

Run Doctrine compatibility lanes:

Run static and formatting checks:

Versioning

This project follows Semantic Versioning 2.0.0.

Published releases are available at github.com/Wedrix/watchtower/releases.

Contributing

For significant features or breaking changes, please start a discussion in the repository first.

For smaller fixes:

  1. Fork the project.
  2. Make your changes.
  3. Open a pull request.

Reporting Vulnerabilities

Send security reports to [email protected]. Security vulnerabilities will be addressed promptly.

License

Watchtower is open-source software distributed under the MIT license.


All versions of watchtower with dependencies

PHP Build Version
Package Version
Requires php Version ^8.0
doctrine/orm Version ^2.20 || ^3.3
webonyx/graphql-php Version ^15.30.2
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package wedrix/watchtower contains the following files

Loading the files please wait ...