Is it possible to auto bootstrap all registered modules? - phalcon

I have structure for multimodule app, but can't understand how I can register some routes from Module.php and fire event from one module and listen for it in another. Is it possible?

Some php frameworks register all modules before routing. For example, Zend Framework will loop through every registered module and load its bootstrap information. It will then parse the route and execute the targeted controller. The benefit is that you can do hierarchical mvc calls between modules. The drawback is you have a lot of overhead if you aren't planning on doing anything with all of those modules you bootstrapped.
To streamline the bootstrap process and load more quickly, Phalcon's framework determines the route before loading any files in the registered modules. It does not load the module.php file in each module, but instead only loads the module.php file that sits in the path of the route that will be executed. The benefit here is speed. The drawback is in trying to do hierarchical mvc across modules. At this point, phalcon has only bootstrapped the routed module, so is agnostic of any other modules.
Essentially, this means that you can only do hmvc requests within the current module. Likewise, the dispatcher in phalcon can only redirect to controllers and actions within the same module. If you need to go to another module, you can do a 301 redirect using the response->redirect action. Of course, this will generate an entirely new http request, so will not fit the hmvc paradigm.
One way to expand this functionality is to register a set of common namespaces that sit outside the modules. You can load these namespaces during the initial boot sequence started from the index.php file:
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(
array(
'Common\Controllers' => COMMON_PATH . '/controllers/' ,
'Common\Forms' => COMMON_PATH . '/forms/' ,
'Common\Models' => COMMON_PATH . '/models/' ,
'Common\Models\ViewHelpers' => COMMON_PATH . '/models/ViewHelpers/' ,
'Common\Plugins' => COMMON_PATH . '/plugins/' ,
)
);
// each module will register its own namespace separately
$loader->register();
return $loader;
In each module's Module.php bootstrap file, you will add the additional namespaces for your given module:
/**
* Register a specific autoloader for the module
*/
public function registerAutoloaders(){
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(
array(
$this->_module_name . '\Controllers' => __DIR__ . '/controllers/' ,
$this->_module_name . '\Models' => __DIR__ . '/models/' ,
$this->_module_name . '\Forms' => __DIR__ . '/forms/' ,
)
);
$loader->register();
}
Now you have namespace access to call classes in the common namespace as well as namespace access to classes in the current module's namespace:
$common_model = new \Common\Models\MyModel();
$module_model = new \CurrentModuleName\Models\MyModel();

Related

Only Map existing Blazor Pages(Razor Components) in the pipeline?

The usual pattern for Blazor (server) apps, is that at the end pf program.cs there is app.MapFallbackToPage("/_Host");
That will result in ALL request paths, that match no earlier endpoint, executing the Blazor App. Sure the Blazor App has a <NotFound> Renderfragment, but that will still result in establishing the SignalR and so on. What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
NavigationManager.NavigateTo cannot be used directly inside the BuildRenderTree markup of the <NotFound> ... I could maybe put a component inside there that redirects OnInitialized ... but that would still first require the SignalR.
How can I completely avoid Blazor/SignalR for URLs that don't exist in the Blazor App ?
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
app.MapFallbackToPage("~/Admin/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomeRoute/More/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomePage/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("/NotValidRoute");
Edit:
#Reason:
I wanted to have a single fallback page (razor page or static) for all routes/urls that don't match any target in the app. But sadly as it seems, that conflicts with blazor'S client side routing. since the server-side routing does not know, which routes should be handled by blazor, it also cannot know, which routes would not map to anything (razor pages and blazor combined). Other please correct me here.
There's server-side routing and client-side routing. On the server side, the middleware pipeline runs first, handling static files and server defined routes, including the fallback route. Fallback routes are routes that don't match static file requests and have the lowest priority, so they are not preferred over other matching routes.
Server-side routing has no idea what routes are going to match on the client-side. That data model is separate. What's happening is, when no server route matches, the host page is rendered, which bootstraps the client. Now you've transitioned to client-side routing and cannot re-enter (without a change to refresh the browser)
What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
That requires knowing what routes exists on the client.
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
Possible using the <NotFound> component to run some JavaScript and redirect the browser to a fixed route on the server.
Edit:
Another would be to build that found all routable razor components and map them all as fallback routes to "_Host".
Something like this (untested):
// This should match wherever components are declared.
var types = typeof(Program).Assembly.GetTypes();
foreach (var type in types)
{
if (typeof(ComponentBase).IsAssignableFrom(type) && type.GetCustomAttribute<RouteAttribute>() is { } routeAttribute)
{
var route = routeAttribute.Template;
endpointRouteBuilder.MapFallbackToPage(route, "/_Host");
}
}
It partly depends on how your app is hosted. In IIS, you can add applications to any website, which are basically websites of any type you want with a "/path" added.
Currently, my company's main app is "ABCsite.com," and my Blazor app is "ABCsite.com/Blazor"

Get site URL in ConfigureServices method of Startup.cs

I need to register SPA files based on URLs...I have registered AddHttpContextAccessor but not sure how i can check the url there?
services.AddSpaStaticFiles(configuration =>
{
if (GetUrl(_httpContextAccessor).EndsWith("support") || GetUrl(_httpContextAccessor).EndsWith("support/"))
configuration.RootPath = "ClientApp/build";
else
configuration.RootPath = "support-app/build";
});
Why are you trying to change the root path based on the request url?
Is the reason for this requirement that you are you serving multiple SPA's? If that is the case, you might want to check out this thread that describes how to configure the pipeline to serve multiple apps at different paths:
How to handle multiple SPA application in ASP.NET Core
If you only have one SPA, then you might need to describe in more detail what you are trying to achieve.

Add route in Blazor server side app for .json or .js file to be handled by controller

This seems like it should be simple but cannot quite work out how.
I want to be able to make a file in the root of the application to by dynamically served.
i.e.
https://localhost:5000/test.json
to be handled by a controller. Its easy if you just have a path without a . but if its a json or js file it seems to get handled differently by the server.
ok really simple - just needed to do this in startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/test.js", context => context.Response.WriteAsync("Hello world"));
});

How to access a controller from a different module?

I have a Phalcon Multimodule App with the following structure:
appServer
apps
api
backend
web
config
public
The backend module is my common logic module. (I think that) I need a Controller in the API to call a Controller inside backend. How can I do that? or is there a better way to access the logic within the backend module from the api module?
I have already tried adding the \AppServer\Backend\Controllers namespace to the loader inside \AppServer\Api\Module->registerAutoloaders(), but when I tried to use it inside \AppServer\Api\Controllers\IndexController->index(), it gives me an error saying it couldn't find the class.
I've read that I should get the processed module from the router, but I don't know how to do that either.
Thanks in advance for your help :)
Use this structure:
appServer
apps
api
backend
web
common
models
controllers
views
config
public
Here is an example application that uses a similar application structure: https://github.com/phalcon/album-o-rama

What to choose for Yii based website: subdomains pointing to modules or separate yii-applications

I'm making a website on yii which has several separate parts, each on it's own subdomain like themes.example.com, events.example.com etc with main page example.com where these parts are listed. I will also need to authenticate users across subdomains. So i'm thinking what would be better: making each part as a yii module or making a separate yii application for each of these parts?
I think in your case it would be better to use modules. At least to have a single webroot directory. Using separate yii application would be appropriate for console part of your project.
See this link for more information: The directory structure of the Yii project site
Well,
The features you are trying to accomplish from Yii its called "Parameterizing Hostnames". You need to create a module based structure in Yii.
At first you need to create a virtual host from apache and redirect that to your Yii project. On you Yii framework you need to change the URL manager from config.
'components' => array(
...
'urlManager' => array(
'rules' => array(
'http://admin.example.com' => 'admin/site/index',
'http://admin.example.com/login' => 'admin/site/login',
),
),
...
),
To know more about Parameterizing Hostnames