Custom Files

Custom Files enables you to add your own files to the project. A Custom File is a simply blank page with the layout of the project (optional) for you to add your own content so it will have a consistent look and feel like other generated files.

 

How to Use

To create a Custom File, simply right click the database pane or click Edit in the main menu, then select Add File, the following form will show:

File Name File name with extension.
Notes
  1. Do not include path in the file name, you can enter Path separately (see below).
  2. Do not use characters not allowed as a file name on your machine or on your server. Alphanumerical characters only is recommended.
  3. The file name cannot be same as any other table (including view, report, etc.) name.
Caption **For case 1 (see below).** The caption of the page. This is similar to table caption for a table and will be shown up in the menu and in the Breadcrumbs of the page.
Includes common files **For case 1 (see below).** Specify whether to include common files so the custom file will be consistent with other generated scripts and able to use PHPMaker classes and functions.
Path The path of the page. There are 2 cases:

##### Case 1 - Additional Page (with Layout and HTML Content) Accessible Via Route
| Property | Value | |----------------|--------------------| | **File name** | **_*.php_ or _*.html.twig_ (file name of view)** | | **Includes common files** | ✔ **ENABLED** | | **Path** | **Route path (Optional)** | For example, ![Case 1](images/customfilecase1.png)

In this case, the **Path** is the **route** for the page, e.g. "/myroute" (no quotes). If route is **unspecified**, the file name without extension will be used as the route, e.g. if your file name you entered is _Home.php_, then the route is `/Home`; if **Lowercase routes** is enabled, then the route is `/home`. Your route can include parameters, e.g. `'/myroute/{param1}/{param2}'`, see [Route Parameters](https://symfony.com/doc/current/routing.html#route-parameters) for details. You can get the parameters in your code by `Route("param1")` and `Route("param2")`. If route is **unspecified**, a catch-all parameter `/{params?}` will be added, you can get the parameter by `Route("params")`. If you pass multiple parameters in the URL, e.g. `/myroute/value1/value2/value3`, the `Route("params")` returns `value1/value2/value3` and you need to split it into separate variables yourself. If you want full control over the route attributes and the controller parameters, you can use **Controller_Action** server event (see below). The page class of the file is generated in the _"models"_ folder and the content of the file (i.e. the view) is generated in the _"views"_ folder. The file names are in Pascal case. The output folders and file names cannot be changed. Note that the file names are NOT related to the route path or the URL.

**Notes** 1. A **route** is NOT the physical output folder or file path for your file, DO NOT try to specify a route like a folder or file path (e.g. "myfolder/" or "myfolder/myfile.php"). A route must begin with a leading slash, but no trailing slash, e.g. "/myroute". 1. **Always access your custom page by its route (e.g. "/myroute"), NEVER try to access it by its physical path (e.g. "/views/myfile.php").** 1. If you only want to output a single value or JSON, you should not use this case, you'd better use **Controller_Action** server event or route/API controller. 1. If **Controller_Action** is used, the controller method includes the **route attribute**, the path specified by the **route attribute** will override the **Path** setting.

##### Case 2 - Class or Standalone File
| Property | Value | |----------------|--------------------| | **File name** | **_*.php_ or other non-PHP files** | | **Includes common files** | **✘ DISABLED** | | **Path** | **Output folder relative to project folder (Required)** | The file is a **single** file, NO other related files (e.g. page class, controller and view) and no route will be generated, e.g.
![Case 2](images/customfilecase2.png)

In this case, the **Path** is the **output folder relative to the project folder**. For example, if your project folder is *D:\websites\myproject* and you want to generate the page in *D:\websites\myproject\myfolder*, then you should enter `"myfolder"` (no quotes, no leading slash, no parent path).

**Notes** 1. **This is a very powerful feature, you can use this to add your own classes to your project, see examples below.** 1. Do NOT use leading slash for the output folder path. 1. Do NOT use parent path `".."` or the file will be generated outside the project folder.

After entering above properties, click OK button to save. The Custom File will show up in the database pane under the Custom Files node:

To edit the Custom File properties, right click the Custom File in the database pane and select Edit File.

To delete a Custom File, right click the Custom File in the database pane and select Delete File.

To enter server events or content for the file, select the Custom File in the database pane , then select the Code tab (which contains Server Events, Client Scripts and Custom Templates) in the right pane.

To enter server event, go to Server Events -> Table-Specific -> Custom File:

To enter content for the file, Scroll down the treeview or collapse the Server Events and Client Scripts node, select the Custom Templates -> Table-Specific -> Custom File -> Content node, then you can enter or paste your content in the editor:



Then just save your project, generate and run your scripts as usual.

**IMPORTANT** Although it is convenient to save your own files in the project, you should avoid saving all the contents in the project or the project will become so large that the performance of the UI will be affected. If the file content is very large or they are many custom files, you should consider making [extensions](extension.html).


Controller_Action Server Event

Custom Files support **Controller_Action** server event which gives you full control over the route attributes, the controller parameters and the response of the page. ![Controller action](images/controlleraction.png) By default a simple controller action will be generated for each custom file with **Includes common files** enabled, e.g. if the file name of the Custom File is "home.php", the controller action will be: You can customize the response by replacing it with your own code by **Controller_Action** server event, e.g.

Route Attributes

PHPMaker uses PHP attributes to define routes next to the code of the controllers associated to those routes. **Make sure you define route attribute for each controller action.** The path specified by the route attribute overrides the **Path** setting (see above) of the custom file. The parameters of the attribute ``Route`` are: (including but limited to) - ``path`` _(string)_ - The path pattern to match, see [Creating Routes as Attributes](https://symfony.com/doc/current/routing.html#creating-routes-as-attributes). - ``methods`` _(string|array)_ - By default, routes match any HTTP verb (`GET`, `POST`, etc.) Use this option to restrict the verbs each route should respond to. It is a required HTTP method or an array of restricted methods: "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH". - ``defaults`` _(array)_ - An array of default parameter values, see [Optional Parameters](https://symfony.com/doc/current/routing.html#optional-parameters). - ``requirements`` _(array)_ - An array of requirements for parameters (regexes), see [Parameters Validation](https://symfony.com/doc/current/routing.html#parameters-validation). - ``name`` _(?string)_ - Route name, it is essential for [generating URLs](https://symfony.com/doc/current/routing.html#generating-urls). Keep in mind that each route name must be unique in the application. **Note** You can omit the first parameter name (i.e. ``path:``) if you specify the route pattern as the first argument. Other arguments should be used with parameter names so you don't need to care about the parameter position. See [Routing](https://symfony.com/doc/current/routing.html) for detailed information about route attributes.

Examples

###### Example 1 - Use HTML in View

Add a Bootstrap Card in the page to show some news.

The result: ![Example 1](images/customfile4.png)
###### Example 2 - Use Global Functions in View Add multiple Bootstrap Cards in the page as a dashboard page. Use helper function to execute SQLs and display data as HTML table.
**Note** There are many other useful helper functions other than ``ExecuteHtml()``, refer to [Global Functions](functions.html) for details.
Result: ![Example 2](images/customfile5.png) ###### Example 3 - Add List Action Add your own class such as custom list action to the project: - **File Name** - Use a unique file name with file extension *.php* and **the file name MUST be same as the class name**, e.g. *MyCustomAction.php* for your class ``MyCustomAction``. - **Include Common Files** - **DISABLE IT**. It is NOT applicable to classes. - **Caption** - NOT applicable. - **Path** - Set the path as _"src"_ (no quotes). - **Content** - Enter your whole class, note that you should use the special placeholder ``{ProjectNamespace}`` as your namespace, e.g. ###### Example 4 - Add Controller Add your own controller and action(s) to the project: - **File Name** - Use a unique file name with file extension *.php* and **the file name MUST be same as the class name**. Use **PascalCase** with a `Controller` suffix, e.g. MyCustomController, to clearly indicate it's a controller. - **Include Common Files** - **DISABLE IT**. It is NOT applicable to classes. - **Caption** - NOT applicable. - **Path** - Set the path as _"controllers"_ (no quotes). - **Content** - Enter your whole class, note that you should use the special placeholder ``{ProjectNamespace}`` as your namespace.
**Note** 1. You can find template of route/API action controller in [Code Repository](customscripts.html?id=code-repository). 2. For simplicity, PHPMaker uses `{ProjectNamespace}` namespace for controllers only. If you prefer to use `{ProjectNamespace}\Controllers` as namespace for your custom controllers, you should generate to *"controllers/Controllers"*. However, be aware that deeper namespaces require **fully qualified names** or `use` statements, making references to sibling or higher-level namespaces (e.g. using global functions) more verbose and harder to manage.
###### Example 5 - Override Export Class Customize the default `ExportExcel` class for Export to Excel. First, add your own class by [Custom Files](customfile.html), you can extend the default class and generate it to the _"src"_ folder.
**Note** To override a method in a subclass, use the **same method name** and keep all **required parameters** and their types exactly as defined in the base class. Ensure the **return type** is compatible. You may add **optional parameters at the end**, as long as they have default values, to provide extra flexibility without breaking compatibility. Optionally, call the parent implementation using `parent::methodName(...)` to preserve or extend the base behavior. Refer to the base class source code to understand the expected behavior and contract.
Then you can replace the default `ExportExcel` class by yours in Global Code, e.g. Alternatively, you can use [Services_Config](customscripts.html?id=services_config) server event to replace the export service by your class, e.g. ###### Example 6 - Add Event Listener The most common way to listen to an event is to register an **event listener**. See Example 3 above about how to add a custom class to your project. You can set the path as _"src"_ (no quotes) or _"src/EventListener"_ (no quotes), see below for details. For example, if you want to listen to ``AuthenticationSuccessEvent``, your content is like this: If you can set the path as _"src"_, then you need to register it as a service and notify the security system that it is an event listener by using a special "tag". You can add your listener to the services by the **Services_Config** server event, e.g. The security system follows this logic to decide which method to call inside the event listener class: 1. If the ``kernel.event_listener`` tag defines the method attribute, calls the method. 1. If no method attribute is defined, calls the ``__invoke()`` magic method (which makes event listeners invokable). 1. If the ``__invoke()`` method is not defined either, throws an exception.
**Notes** 1. There is an optional attribute for the ``kernel.event_listener`` tag called ``priority``, which is a positive or negative integer that defaults to 0 and it controls the order in which listeners are executed (the higher the number, the earlier a listener is executed). This is useful when you need to guarantee that one listener is executed before another. The priorities of the internal Symfony listeners usually range from -256 to 256 but your own listeners can use any positive or negative integer. 1. If you generate to the _"src/EventListener"_ folder and use `#[AsEventListener]` attribute, then you don't need to register the service manually. See [Defining Event Listeners with PHP Attributes](https://symfony.com/doc/current/event_dispatcher.html#defining-event-listeners-with-php-attributes).
###### Example 7 - Add Event Subscriber Another way to listen to events is via an **event subscriber**, which is a class that defines one or more methods that listen to one or various events. The main difference with the event listeners is that subscribers always know the events to which they are listening. See Example 3 above about how to add a custom class to your project. You can set the path as _"src"_ (no quotes) or _"src/EventSubscriber"_ (no quotes), see below for details. If different event subscriber methods listen to the same event, their order is defined by the ``priority`` parameter. This value is a positive or negative integer which defaults to 0. The higher the number, the earlier the method is called. Priority is aggregated for all listeners and subscribers, so your methods could be called before or after the methods defined in other listeners and subscribers. The following example shows an event subscriber which listen to the `CheckPassportEvent` event: If you set the path as _"src"_, then you need to register it as a service and notify the security system that it is an event subscriber by using a special "tag". You can add your subscriber to the services by the **Services_Config** server event, e.g.
**Note** If you generate to the _"src/EventSubscriber"_ folder, then you don't need to register the service manually.


Learn More

You can use Custom Files to add various classes to your application, read: - [Controllers](https://symfony.com/doc/current/controller.html) - [Creating an Event Listener](https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-listener) - [Defining Event Listeners with PHP Attributes](https://symfony.com/doc/current/event_dispatcher.html#defining-event-listeners-with-php-attributes) - [Creating an Event Subscriber](https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber) - [Doctrine Entity Listeners](https://symfony.com/doc/current/doctrine/events.html#doctrine-entity-listeners) (listen to a single Doctrine event on a single entity class) - [Doctrine Lifecycle Listeners](https://symfony.com/doc/current/doctrine/events.html#doctrine-lifecycle-listeners) (listen to a single Doctrine event on all the application entities) - [Using a Factory to Create Services](https://symfony.com/doc/current/service_container/factories.html) - [How to Import Configuration Files/Resources](https://symfony.com/doc/current/service_container/import.html) - [Data customization and validation](https://symfony.com/bundles/LexikJWTAuthenticationBundle/current/2-data-customization.html) (for JWT)
**Notes** If you generate your **services** to _"src"_ folder, remember to register your service, e.g. by [Services_Config](customscripts.html?id=services_config) server event. However, PHPMaker supports some special folders to simplify configuration: 1. If you output your **event listeners** to _"src/EventListeners"_ folder, they will be loaded automatically. If you `#[AsEventListener]`, `#[AsEntityListener]` or `#[AsDoctrineListener]` attribute, you don't need to register them as services manually. However, make sure your class uses `{ProjectNamespace}\EventListeners` as namespace. You can find a template of event listener in [Code Repository](customscripts.html?id=code-repository). 1. If you output your **event subscribers** to _"src/EventSubscribers"_ folder, they will be loaded automatically, you don't need to register them as services manually. However, make sure your class uses `{ProjectNamespace}\EventSubscribers` as namespace, and you have subscribed the events by the `getSubscribedEvents()` method properly. You can find a template of event subscriber in [Code Repository](customscripts.html?id=code-repository). 1. If you output your **service configuration files** to _"config/extensions"_ folder, they will be imported automatically.



 ©2002-2025 e.World Technology Ltd. All rights reserved.