I'd like to create several instances of a class in CodeIgniter. I have created my class as a library, but cannot figure out the syntax to use to create more than one instance.
From the CodeIgniter users guide:
CI Users Guide: Loader Class
Assigning a Library to a different object name
If the third (optional) parameter is
blank, the library will usually be
assigned to an object with the same
name as the library. For example, if
the library is named Session, it will
be assigned to a variable named
$this->session.
If you prefer to set your own class
names you can pass its value to the
third parameter:
$this->load->library('session', '',
'my_session');
Session class is now accessed.
using:
$this->my_session
I think that's what you're looking for.
I know this thread is long passed, but it was one of the questions I came across while looking for my answer. So here's my solution...
It's PHP. Create your class as a library, load it using the standard CI Loader Class, but use it like you would in a regular PHP script.
Build your class:
class My_class {
var $number;
public function __construct($given_number){
$number = $given_number;
}
public function set_new_num($given_number){
$number = $given_number;
}
}
Load it:
// This will load the code so PHP can create an instance of the class
$this->load->library('My_class');
Then instantiate and use the object where needed:
$num = new My_class(24);
echo $num->number;
// OUTPUT: 24
$num->set_new_num(12);
echo $num->number;
// OUTPUT: 12
The only time I use $this->my_class is to make calls to static functions that I code.
Sorry for reviving this topic but I think I might have something reasonable to add.
You can do this to add multiple instances of a class. I don't know if it violates Codeigniter standard usage anyhow but seems more Codeigniterish than loading a library (which creates $this->library_name which isn't used) and then making 2 MORE instances with the "new" keyword.
$this->load->library( 'my_library', '', 'instance1' );
$this->load->library( 'my_library', '', 'instance2' );
$this->instance1->my_class_variable = 1;
$this->instance2->my_class_variable = 2;
echo $this->instance1->my_class_variable; // outputs 1
echo $this->instance2->my_class_variable; // outputs 2
I use this in my code to generate different menus. I have a "menu" class and different instances for each menu, with different menu items in each.
Related
Edit: So far it looks like the answer to my question is, "You can't do that in Swift." I currently have a solution whereby the subclass names are listed in an array and I loop around and instantiate them to trigger the process I'm describing below. If this is the best that can be done, I'll switch it to a plist so that least it's externally defined. Another option would be to scan a directory and load all files found, then I would just need to make sure the compiler output for certain classes is put into that directory...
I'm looking for a way to do something that I've done in C++ a few times. Essentially, I want to build a series of concrete classes that implement a particular protocol, and I want to those classes to automatically register themselves such that I can obtain a list of all such classes. It's a classic Prototype pattern (see GoF book) with a twist.
Here's my approach in C++; perhaps you can give me some ideas for how to do this in Swift 4? (This code is grossly simplified, but it should demonstrate the technique.)
class Base {
private:
static set<Base*> allClasses;
Base(Base &); // never defined
protected:
Base() {
allClasses.put(this);
}
public:
static set<Base*> getAllClasses();
virtual Base* clone() = 0;
};
As you can see, every time a subclass is instantiated, a pointer to the object will be added to the static Base::allClasses by the base class constructor.
This means every class inherited from Base can follow a simple pattern and it will be registered in Base::allClasses. My application can then retrieve the list of registered objects and manipulate them as required (clone new ones, call getter/setter methods, etc).
class Derived: public Base {
private:
static Derived global; // force default constructor call
Derived() {
// initialize the properties...
}
Derived(Derived &d) {
// whatever is needed for cloning...
}
public:
virtual Derived* clone() {
return new Derived(this);
}
};
My main application can retrieve the list of objects and use it to create new objects of classes that it knows nothing about. The base class could have a getName() method that the application uses to populate a menu; now the menu automatically updates when new subclasses are created with no code changes anywhere else in the application. This is a very powerful pattern in terms of producing extensible, loosely coupled code...
I want to do something similar in Swift. However, it looks like Swift is similar to Java, in that it has some kind of runtime loader and the subclasses in this scheme (such as Derived) are not loaded because they're never referenced. And if they're not loaded, then the global variable never triggers the constructor call and the object isn't registered with the base class. Breakpoints in the subclass constructor shows that it's not being invoked.
Is there a way to do the above? My goal is to be able to add a new subclass and have the application automatically pick up the fact that the class exists without me having to edit a plist file or doing anything other than writing the code and building the app.
Thanks for reading this far — I'm sure this is a bit of a tricky question to comprehend (I've had difficulty in the past explaining it!).
I'm answering my own question; maybe it'll help someone else.
My goal is to auto initialize subclasses such that they can register with a central authority and allow the application to retrieve a list of all such classes. As I put in my edited question, above, there doesn't appear to be a way to do this in Swift. I have confirmed this now.
I've tried a bunch of different techniques and nothing seems to work. My goal was to be able to add a .swift file with a class in it and rebuild, and have everything automagically know about the new class. I will be doing this a little differently, though.
I now plan to put all subclasses that need to be initialized this way into a particular directory in my application bundle, then my AppDelegate (or similar class) will be responsible for invoking a method that scans the directory using the filenames as the class names, and instantiating each one, thus building the list of "registered" subclasses.
When I have this working, I'll come back and post the code here (or in a GitHub project and link to it).
Same boat. So far the solution I've found is to list classes manually, but not as an array of strings (which is error-prone). An a array of classes such as this does the job:
class AClass {
class var subclasses: [AClass.Type] {
return [BClass.self, CClass.self, DClass.self]
}
}
As a bonus, this approach allows me to handle trees of classes, simply by overriding subclasses in each subclass.
Good day,
I have several partials that have code. In the code tab, I noticed that the code tab had similar looking code. Here are examples
Partial 1
function onStart()
{
$x = MyModel1::where('myColumn', 'myValue')->first();
// lots of stuff using $x functions
$this['viewData'] = $x->getViewData();
}
Partial 2
function onStart()
{
$x = MyModel2::where('myColumn', 'myValue')->first();
// lots of stuff using $x functions
$this['viewData'] = $x->getViewData();
}
MyModel1 and MyModel2 both implement the same interface, so they have the same functions.
My question is, where do I put the code that is similar? I can put it in a plugin but that doesn't feel correct. I can create a base class and have the partials call the parent method but won't that mean modifying the code in the vendor folder?
if you really need to manage your code you can create component and add that code there as they easily attached to other pages (down point is that you need to create a plugin)
you can write your code inside onRun method.
https://octobercms.com/docs/plugin/components#page-cycle
and instead directly assigning variables to this you need to assign them like
$this->page['var'] = 'value';
and now it will work same as you are doing.
I would like you to share your experience on the matter of using some common object by different components of a library (or an application). I'd like to understand, which practice is better, which way is more "ecological".
Let's imagine that we have some complex library that consists of a bunch of classes: Library, Library::Foo, Library::Foo::Bar and many other ones. An application that uses the library initializes a Library-classed object, at some stage this object initializes some quantity of Library::Foo-classed objects, they initialize Library::Foo::Bar-classed objects and so on.
And now let's imagine that there is the Library::Logger class that is being used by all components. It's being initialized only once by the constructor of the Library class and all other sub-classes need it for their logging purposed.
The question is: how to let them all have the reference to this object?
I see the following ways to acheive it:
Passing it to the constructor
When a Library-based object initializes a Library::Foo-classed object, it passes the reference to the logger to the newly-created object as a parameter:
$self->_set_logger(Library::Logger->new());
my $logger = $self->_get_logger;
my $foo = Library::Foo->new(logger => $logger);
So the Library::Foo-classed object could get the logger and even pass it to a Library::Foo::Bar-classed object when it's needed:
my $logger = $self->_get_logger;
my $bar = Library::Foo::Bar(logger => $logger);
Accessing it as a method
When a Library-based object initializes the Library::Foo-based object, it passes the reference to itself to the newly-created object:
$self->_set_logger(Library::Logger->new());
my $foo = Library::Foo->new(papa => $self);
So the Library::Foo-based object could access the logger this way:
$my logger = $self->_get_papa->_get_logger;
my $bar = Library::Foo::Bar(papa => $self);
It breaks encapsulation, but it also lets the Library::Foo-based object to get other data from its "papa".
Using a global variable
Also we can store the reference to the logger in some global variable, so any other object could access it this way:
$logger = $Library::_LOGGER;
Well, it really sucks, I know... :)
...
So, what do you think, which way seems to be better? What alternative way would you propose? How do you solve this problem for yourself? Would you pass the data to the "child" manually or would you let it to get the data from the "parent"?
Many thanks in advance!
There is no answer to your problem. It realy depends on your exact use-case. If (just guessing) you only want to have exactly one Logger in your Library, I think using the software pattern of a "singleton" might exactly fit. E.g.
package Library::Logger;
use strict;
my $logger;
sub new {
unless ($logger) {
.... initializing $logger ...
}
return $logger;
}
and in each of your sublclasses you can access it by
Library::Logger->new()->...
HTH
Georg
I'm using native session library to replace the built in session library in CI. I need to extend the class but when I drop in MY_Session.php, CI reverts back to the old /system/libraries/Session.php.
How to I extend a class that's replaced a core CI class like Session.php?
Simply by naming your class files identically to a native library will
cause CodeIgniter to use it instead of the native one. To use this
feature you must name the file and the class declaration exactly the
same as the native library. For example, to replace the native Email
library you'll create a file named application/libraries/Email.php
-user guide
then call it
class MY_Email extends CI_Email {
public function __construct()
{
parent::__construct();
}
}
Loading Your Sub-class:
$this->load->library('email');
EDIT
Try this:
Just load your new library (the one doing the extending):
Then, let's say we have Session.php and Mysession.php
<?php
load_class('session', false);
class Mysession extends Session {
//your code
}
You don't need the MY_ name tag still, I think you want to reserve that for it's original intended purpose to avoid confusion.
.. else just use an include() or require() :P
Hi I have a situation where I need to look up the number of recently viewed products on catalog/product/view.phtml. In the recently viewed 'product_viewed.phtml' file it calls
$_products = $this->getRecentlyViewedProducts()
to get the recently viewed. How would I access this method from within the catalog/product/view.phtml file?
I don't know where this method is. I've tried searching for it but it doesn't seem to exist. When I write click it in Netbeans and click go to declaration it takes me to
class Mage_Reports_Block_Product_Viewed extends Mage_Reports_Block_Product_Abstract
Actually on the class itself. This class only has _toHtml(), getCount(), and getPageSize() methods.
I just need to know whether there are any recently viewed products.
Any help most appreciated!
Billy
If you look into 'Mage_Reports_Block_Product_Viewed', you will notice:
$this->setRecentlyViewedProducts($this->getItemsCollection());
That 'getItemsCollection' method is defined in the abstract class... And you will notice this abstract class will create a model based on $_indexName defined in the (subclassed) block.
If you just want the collection, you can probably get away with:
$_products = Mage::getModel('reports/product_index_viewed')->getCollection();
And then adding whatever you want to the collection:
$_products
->addAttributeToSelect('*')
->setAddedAtOrder();
// optionally add other methods similar to Mage_Reports_Block_Product_Abstract::getItemsCollection
Another approach that might be more suited would be to create the original block:
$productViewedBlock = $this->getLayout()->createBlock('reports/product_viewed');
On which you can simply call whatever you want:
$_collection = $productViewedBlock->getItemsCollection();
$_count = $productViewedBlock->getCount();
The getRecentlyViewedProducts function is a magical getter that gets the data that was set with setRecentlyViewedProducts in app/code/core/Mage/Reports/Block/Product/Viewed.php (which builds it using app/code/core/Mage/Reports/Block/Product/Abstract.php's function _getRecentProductsCollection).
This is complicated stuff that you don't want to reproduce; its better, IMO to make your own Block that extends Mage_Catalog_Block_Product_Abstract that will give you access to the same functionality, and drop your new block into the page you're working on.