What is the difference between ClassMapAutoLoader and onBootstrap?
Class Map Autoloader
A web application consists of many PHP classes, and each class typically resides in a separate file. This introduces the need of including the files.
As your application grows in size, it may be difficult to include
each needed file. Zend Framework 2 itself consists of hundreds of files,
and it can be very difficult to load the entire library and all its
dependencies this way. Moreover, when executing the resulting code, PHP interpreter will
take CPU time to process each included file, even if you don't create an
instance of its class.
To fix this problem, in PHP 5.1, the class autoloading feature has been introduced.
The PHP function spl_autoload_register() allows you to register
an autoloader function. For complex web sites, you even can create
several autoloader functions, which are chained in a stack.
During script execution, if PHP interpreter encounters a class name
which has not been defined yet, it calls all the registered autoloader functions
in turn, until either the autoloader function includes the class or "not found" error is
raised. This allows for "lazy" loading, when PHP interpreter processes the class
definition only at the moment of class invocation, when it is really needed.
To give you an idea of how an autoloader function looks like, below we provide a
simplified implementation of an autoloader function:
<?php
// Autoloader function.
function autoloadFunc($className) {
// Class map static array.
static $classMap = array(
'Zend\\Mvc\\Application' => '/path/to/zend/dir/Zend/Mvc/Application.php',
'Application\\Module' => '/path/to/app/dir/Application/Module.php',
//...
);
// Check if such a class name presents in the class map.
if(isset(static::$classMap[$className])) {
$fileName = static::$classMap[$className];
// Check if file exists and is readable.
if (is_readable($filename)) {
// Include the file.
require $filename;
}
}
}
// Register our autoloader function.
spl_autoload_register("autoloadFunc");
In the above example, we define the autoloadFunc() autoloader function,
which we will further refer to as the class map autoloader.
The class map autoloader uses the class map for mapping between class name and
absolute path to PHP file containing that class. The class map is just a usual PHP
array containing keys and values. To determine the file path by class name, the
class map autoloader just needs to fetch the value from the class map array.
It is obvious, that the class map autoloader works very fast. However, the disadvantage
of it is that you have to maintain the class map and update it each time you add a new
class to your program.
onBootstrap
On every HTTP request, the Zend\Mvc\Application
object is created. The application's "life" consists of several stages.
Zend Framework 2 uses the concept of event. One class can trigger an event,
and other classes may listen to events. Technically, triggering an event means just calling another class' "callback" method. The event management is implemented inside of
the Zend\Mvc\EventManager component.
Each application life stage is initiated by the application by triggering an event. Other
classes (either belonging to Zend Framework or specific to your application) may listen
to events and react accordingly.
Below, the four main events (life stages) are presented:
Bootstrap. When this event is triggered by the application, a module has a chance to
register itself as a listener of further application events in its onBootstrap()
callback method.
Route. When this event is triggered, the request's URL is analyzed using a router class (typically, with
Zend\Mvc\Router\Http\TreeRouteStack class. If an exact match between the URL and a route
is found, the request is passed to the site-specific controller class assigned to the route.
Dispatch. The controller class "dispatches" the request using the corresponding action method
and produces the data that can be displayed on the web page.
Render. On this event, the data produced by the controller's action method are passed for rendering to
Zend\View\Renderer\PhpRenderer class. The renderer class uses a
view template file for producing an HTML page.
For a beginner to better understand the above mentioned concepts, I would recommend the Zend Framework 2.0 by Example: Beginner’s Guide book or the Using Zend Framework 2 e-book. You may choose the book on your own.
Related
Background - a library should execute some user defined methods inside an isloate.
Passing an object to an isolate is impossible by design.
I tried to create a dart class by refelction (mirros) and its name. Some static methods are annotated and the code can pickup the right method inside the isolate. This works only if all code resides in one file. By sperating the code like alibrary the isolate is impossible to find the user class. Any idea?
I am Java developer - the java thread model is so easy. Ok, there some pitfalls - but the Dart isolate model is so restricted.
In my Java 8 Play 2.6 application I have this particular line in a MessageConsumer class that reads a "Rule" record in the DB and sends the JSON message (node) to a specific processor based on the type configured on the rule column. ProcessType is an enum of Sub Classes that all extend from a base (Super class) process.
Play.current().injector().instanceOf(ProcessType.getClass(matchingRule.getProcessType())).processMessage(node, matchingRule);
I'm having trouble figuring out how to refactor this and don't want to add the allowGlobalApplication = true config parameter if I can avoid it.
The most straightforward approach is to inject the Injector into the component that contains this call (the MessageConsumer). This can be done the same way as any other Play component.
You can also inject the Application instance, which would return the same thing as Play.current(). This could be useful if you need more information from the Application object, but if not, injecting the Injector directly would be preferable, as it would create less coupling between the MessageConsumer and other components.
This assumes that the MessageConsumer is created by DI itself. If not, please add more details to the question, including the context code.
So I am writing an ASP.NET Core MVC application where users should be able to upload an Excel file, when a file gets uploaded I need to read the uploaded file an create a Model of the data inside the file.
I am currently creating this model in my Controller method but this made my method quite long.
My current solution is creating a class inside my Controller which deals with creating a model from an Excel file but I feel like this is the wrong way to do it.
So my question is: What is the right place to put the code that reads my excel file and puts it inside a model?
You should create a new .NET Standard library and create there the class that builds the model.
The recommended way is to use the class as an implementation and an interface (IExcelModelBuilder) that exposes all the public methods of that class (ExcelModelBuilder). This way you can inject this service into your controller constructor and, as a bonus, you can easily unit test it too.
You can read more about Dependency Injection in .NET Core.
You can register the service in your startup file:
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
{...}
services.AddTransient<IExcelModelBuilder, ExcelModelBuilder>();
}
Step 1:Create a new .NET Standard library (Services)
Step 2:Add the reference into the mvc application of that library.
Step 3:Step two create a class that will be dealing with all the stuff like that if you have a limited number of tasks to perform ,
but if you want to separate it and wants a generic solution then Create an Interface (IUpload) and then implement all its methods in a class (Upload).also register the service in your startup file:
I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}
The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.
Is it possible to override the class file location of a framework class via classmap and autoloader? If yes, then how?
Example: I want to override Zend\Form\Fieldset, so that everywhere in the framework where Zend\Form\Fieldset is referenced, I want it to use my own class file instead of the original.
Motivation: When updating the framework, I want to keep my modifications safe from getting overwritten.
Known alternative: Modify the code in the framework.
Disadvantage: Modification gets lost when updating the framework.
writing the same class (FQCN) at another location is generally a bad idea. This causes two classes which are equally named to live in two separate locations. It's a much better idea to create your own Fielset in your own namespace. Say, Application\Form\Fieldset.
You can extend the ZF2 fieldset by your own. Then reference this new fieldset class and its all much more maintainable.
The downside of this method is you don't automatically use the new fieldset class. You have to reference the Application\Form namespace in every form you use. On the other hand, this makes it much more clear to other users of you code what exactly happens: there are no unexpected consequences using ZF2 code.
The only remark I have to make here is, for what do you need another fieldset? If you think you need that for view helpers, that's not true. You can modify the view helper to render fieldsets without modifying the Fieldset form class itself.