How to use default constructor in codeIgniter4? - codeigniter-4

I want to use controller to load directly some models by using default constructor, but CodeIgniter4 was removed __construct method from CodeIgniter4 framework and I got error message Cannot call constructor. please see code below:
public function __construct(){
parent::__construct();
//Do magic task here
}
Instead of CI3 is working by using above code, Can anyone suggest me in CI4?
Thank You for your tips or comments!
Best Regards!

CI4 default controller namespaced CodeIgniter\Controller doesn't have a class constructor. So if you're extending directly from it, parent::__construct() can't be called.
If you really need a constructor for every one of your controller you should modify App\Controllers\BaseController and making your others controllers extending it with the code you provided.
Also if your goal is to execute some code before or after your controller is called you should check out Filters in CI4. They are perfectly designed for this need : https://codeigniter4.github.io/userguide/incoming/filters.html

You can use constructor in CI4 to load models
Add the code in your Controller class and it should work.
protected $userModel;
public function __construct()
{
$this->userModel = new UserModel();//Create a instance of the model
helper('form', 'url');
}

Related

Dynamic determination for database

I have some entity mapping to a collection in a mongoDB. However, I have a separate database I want the same code to run against (eg. Constants.db_B). How can I make this parameter dynamic so I can run this without changing the constant and recompiling? If I could pass this as a parameter that would be fine too.
#MongoEntity(collection = "sample", database = Constants.db_A)
public class SomeEntity extends PanacheMongoEntity {
}
I tried using ConfigProperty on the Constants class, but it only injects it on a bean instance and not the class itself.
Is this possible?
It's not possible right now. This has been issued in the quarkus project.
https://github.com/quarkusio/quarkus/issues/14789
It's not the same casuistry than yours but there's a solution made from the Author of that issue, may be helpful for you
https://gitlab.com/ch3rub1/quarkus-mongo-mutitenant

FakeItEasy in C# on a servicereference

I have a servicereference with a method I need to use in a test.
The servicereference class is defined as:
public class MyServiceReference : Clientbase<IMyServiceReference>, IMyServiceReference
{
public MyServiceReference()
{
}
..... methods is then defined
}
From my testmethod I have tried both
private MyServiceReference myServiceReferenceFake = A.Fake<MyServiceReference>();
// And
private MyServiceReference myServiceReference = new MyServiceReference();
For both of these is crashes in the constructor with the message:
System.InvalidOperationException: Could not find default endpoint element that references contract.
All I need is to have a callto definition from a method in that class.
How can this be solved?
I've no experience with Clientbase, which I assume to be a System.ServiceModel.ClientBase<TChannel>,but I can make some general comments.
Since you tried first to fake a MyServiceReference, I'll assume that you're not testing that class, and you want to use it as a collaborator for the system under test. In that case, your best bet is to try faking IMyServiceReference. interfaces are very easy to fake, since they don't bring along any behaviour or baggage like faking a class does.
If you feel you really need to fake a MyServiceReference, then we have to contend with the fact that FakeItEasy will eventually call MyServiceReference(), which will call ClientBase<IMyServiceReference>(), whose documentation says
Initializes a new instance of the ClientBase<TChannel> class using the default target endpoint from the application configuration file.
Based on the error you reported, I assume that the application configuration file is not found or does not include the configuration required to create a MyServiceReference. The fact that you get the same error when you just try to instantiate a MyServiceReference directly strengthens my belief.
So I think your paths forward are either to try faking IMyServiceReference or to provide the configuration that ClientBase<IMyServiceReference> needs.

How to use a librarie in views in Codeigniter4

i trie to use a own library in a view, but it failed with "undefined property: CodeIgniter\View\View::$mylib"
This is the Base Controller
protected $mylib;
/**
* Constructor.
*/
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
//--------------------------------------------------------------------
// Preload any models, libraries, etc, here.
//--------------------------------------------------------------------
// E.g.:
// $this->session = \Config\Services::session();
//Include our librarie with http-request
$this->mylib = new mylib(service('request'));
}
In the Controller i use it in this way, here i can work with my libray without any trouble. The testfunction will return a simple text.
namespace App\Controllers;
//Important to add our librarie (session, rbac, login etc.)
use App\Libraries\mylib;
...
die("Test: $this->mylib->testfunction());
If i try the same in my view file i recieve the error.
die("Test: $this->mylib->testfunction());
What i do wrong?
Update
In the meantime i find a way to work with my library in the views
at top of my view-file i add this
use App\Libraries\mylib;
$this->mylib = new mylib(service('request'));
It works, but is there a way to make the whole thing easier so that I don't have to write these lines in every view-file but maybe only once in e.g. Base-Controller?
What i do wrong?
You're assuming that because you created that Library in the Controller that it is automatically accessible in a View, which is incorrect, regardless if it's a class property of the Controller or not.
Anything that is not already in the View needs to be passed in when you "use" it (i.e. the view() function's second parameter). So you can either create the Library in the Controller and pass the entire object into the View, or continue creating it directly in the View as you're doing now.
The first option tends to be a little cleaner.

Can CDI #Producer method take custom parameters?

I think i understood how CDI works and in order to dive deep in it, i would like to try using it with something real world example. I am stuck with one thing where i need your help to make me understand. I would really appreciate your help in this regard.
I have my own workflow framework developed using Java reflection API and XML configurations where based on specific type of "source" and "eventName" i load appropriate Module class and invoke "process" method on that. Everything is working fine in our project.
I got excited with CDI feature and wanted to give it try with workflow framework where i am planning inject Module class instead of loading them using Reflection etc...
Just to give you an idea, I will try to keep things simple here.
"Message.java" is a kind of Transfer Object which carries "Source" and "eventName", so that we can load module appropriately.
public class Message{
private String source;
private String eventName;
}
Module configurations are as below
<modules>
<module>
<source>A</source>
<eventName>validate</eventName>
<moduleClass>ValidatorModule</moduleClass>
</module>
<module>
<source>B</source>
<eventName>generate</eventName>
<moduleClass>GeneratorModule</moduleClass>
</module>
</modules>
ModuleLoader.java
public class ModuleLoader {
public void loadAndProcess(Message message){
String source=message.getSource();
String eventName=message.getEventName();
//Load Module based on above values.
}
}
Question
Now , if i want to implement same via CDI to inject me a Module (in ModuleLoader class), I can write Factory class with #Produce method , which can do that. BUT my question is,
a) how can pass Message Object to #Produce method to do lookup based on eventName and source ?
Can you please provide me suggestions ?
Thanks in advance.
This one is a little tricky because CDI doesn't work the same way as your custom solution (if I understand it correctly). CDI must have all the list of dependencies and resolutions for those dependencies at boot time, where your solution sounds like it finds everything at runtime where things may change. That being said there are a couple of things you could try.
You could try injecting an InjectionPoint as a parameter to a producer method and returning the correct object, or creating the correct type.
There's also creating your own extension of doing this and creating dependencies and wiring them all up in the extension (take a look at ProcessInjectionTarget, ProcessAnnotatedType, and 'AfterBeanDiscovery` events. These two quickstarts may also help get some ideas going.
I think you may be going down the wrong path regarding a producer. Instead it more than likely would be much better to use an observer especially based on what you've described.
I'm making the assumption that the "Message" transfer object is used abstractly like a system wide event where basically you fire the event and you would like some handler defined in your XML framework you've created to determine the correct manager for the event, instantiate it (if need be), and then call the class passing it the event.
#ApplicationScoped
public class MyMessageObserver {
public void handleMessageEvent(#Observes Message message) {
//Load Module based on above values and process the event
}
}
Now let's assume you want to utilize your original interface (I'll guess it looks like):
public interface IMessageHandler {
public void handleMessage(final Message message);
}
#ApplicationScoped
public class EventMessageHandler implements IMessageHandler {
#Inject
private Event<Message> messageEvent;
public void handleMessage(Message message) {
messageEvent.fire(message);
}
}
Then in any legacy class you want to use it:
#Inject
IMessageHandler handler;
This will allow you to do everything you've described.
May be you need somthing like that:
You need the qualifier. Annotation like #Module, which will take two paramters source and eventName; They should be non qualifier values. See docs.
Second you need a producer:
#Produces
#Module
public Module makeAmodule(InjectionPoint ip) {
// load the module, take source and eventName from ip
}
Inject at proper place like that:
#Inject
#Module(source="A", eventName="validate")
Module modulA;
There is only one issue with that solution, those modules must be dependent scope, otherwise system will inject same module regardles of source and eventName.
If you want to use scopes, then you need make source and eventName qualified parameters and:
make an extension for CDI, register programmatically producers
or make producer method for each and every possible combinations of source and eventName (I do not think it is nice)

Kohana helper attribute

I have a question that keeps bothering me. Currently, I have started using Kohana 3.2 Framework. I've written a helper to handle some functionality - I have a number of methods, which are (as it should be) declared STATIC. But, all of these methods are somehow working with the database, so I need to load a model. Currently, every method has a non-static variable like this:
$comment = new Model_Comments;
$comment->addComment("abc");
OK, it seems to be working, but then I wanted to get rid of this redundancy by using class attribute to hold the instance of the model (with is class as well).
Something like this:
private static $comment; // Declaring attribute
self::$comment = new Model_Comment; // This is done within helper __constuct method
self::$comment->addComment("abc"); // And call it within the method.
But, I got failed with: Call to a member function addComment() on a non-object
Question is: is it possible to do it ? Maybe there are some other approaches ?
Sorry for a long story and, thanks in advice! :P
A static method cannot call a non-static method without operating on an instance of the class. So, what you're proposing won't work. There may be a way do accomplish something similar, but what about trying the following:
You could implement the singleton or factory pattern for your "helper" class. Then, you could create the model (as an attribute) as you instantiate/return the instance. With an actual instance of your "helper" class, you won't have to worry about the static scope issues.
In other words, you can create a helper-like class as a "normal" class in your application that, upon creation, always has the necessary model available.
I'd be happy to help further if this approach makes sense.
David

Resources