I'm facing a rather weird problem.
In one of my Kohana Modules Autoload seems to fail for just a single class, and also only on my staging box, but not on my development box.
Also, it loads all other classes just fine in the same piece of code.
So i have this class in which i call other classes:
class PayPal_AdaptivePayment extends PayPal {
public function DoAdaptivePayment($params)
{
$receiverList = new PayPal_Container_ReceiverList();
....some more other code
$result = new Paypal_Result_AdaptiveResult($response);
}
}
Both Classes PayPal_Container_ReceiverList() and Paypal_Result_AdaptiveResult() are located in folders on the level of the class i'm calling them in.
PayPal_Container_ReceiverList() lives in ./Container/receiverlist.php
Paypal_Result_AdaptiveResult() lives in ./Result/adaptiveversult.php
sofor some reason, it can't find the PayPal_Container_ReceiverList class unless i include it specifically at the top
but it can find the Paypal_Result_AdaptiveResult() class.
There's nothing really crazy going on in the class that isn't working:
class PayPal_Container_ReceiverList extends PayPal {
public $receiver = array();
public function __construct()
{
}
}
that's it.
The PayPal_Result_AdaptiveResult class is a bit more complex, and i don't think it'd make sense pasting it here.
Giving the fact that this works on one box but not the other might give me an indication that it could have to do with php instead of kohana, but i'm not sure.
on the box it works i have php 5.3.8
on the one where it doesn't i have php 5.3.2
Does anyone see anything obivous here which i'm just not seeing?
any help is greatly appreciated!
T.
There is a typo in one of the filenames (adaptiveversult.php). Also all the folders and files should be lowercase. Perhaps the system it's working on is Windows (which is case-insensitive). Basically this is the path where the classes should be:
PayPal_Container_ReceiverList in paypal/container/receiverlist.php
Paypal_Result_AdaptiveResult in paypal/result/adaptiveresult.php
Related
For my current project I have to parse data "dumps" (EEPROM HEX dumps from a microcontroller) (coming from a file or a SQL database) that have a different format depending on the version of the software in the controller. (The software version is also in the dump.)
Extracting the version works and I have a somewhat working version that works for 1 specific version (but I find the current version quite messy). Since there is some overlap the between the different versions.
The output of the code is a JSON array that is fed to angular that formats the data into a table so a user can start playing with the data. (the JSON is generated with json_encode, works great)
What I'm looking for is a nice (oop, if possible) solution what can extract the data from the different file versions without a lot of code copy-paste. The only solution I can think of right now would be class for the 1st version, and than do a copy-paste (and a little edit) to a new class the 2nd version (and so on).
A generic answer on how to do this is fine for me, however I'm trying to do this in PHP.
Start by making a base class and a child class for the first version (the following code may not have perfect syntax):
class DataDump {
// some kind of storage
protected $contents;
}
class FirstVersion extends DataDump {
}
Then as you are building the FirstVersion class, try to pay close attention to what you think might be common in all the versions and move that code down to the DataDump parent class.
class DataDump {
// some kind of storage
protected $contents;
public loadFile($filename) {
....code....
$this->contents = ...
}
public processHeader() {
}
}
class FirstVersion extends DataDump {
public loadFirstFile {
$this->loadFile(...);
$this->processHeader();
...some code specific to this version...
}
}
Then you can slowly build the parent class with the things that are common, and there is almost always parts of the code that are common (even if in small segments). As you build other child classes, you may find other logic that can be shared, so push it down to the parent, or perhaps there is a base method that some of the child classes override and others can just use the base method.
Sometimes, when you have a big mess to deal with, it is hard to see all the shared code upfront and how to best organize it in a sane way, and this process helps tremendously when you are stuck. Just start writing and you will begin to see the patterns among all the versions, even if just helper methods.
I've come across an unusual class loading problem in PHPUnit, initially experienced with 4.3.5 and now latest 4.4.2 as well (latest stable).
I have a bootstrap file which is loaded via a phpunit.xml automatically, which includes Composer's default autoloader and also my own autoloader. This works fine as it is. However, I discover that if I load a test class in the bootstrap, then PHPUnit isn't able to resolve the class name correctly, and it thus does not load.
I get this error:
Class 'test/unit/tests/UpdateAllTest' could not be found in '/full/project/path/webapp/test/unit/tests/UpdateAllTest.php'.
(My purpose in wanting to refer to a test class in the bootstrap is to add a database build method in each one, keeping it with the test file it pertains to. I plan to do this in the bootstrap rather than a setUp() method, as I want it to run once across all tests, not once per test method).
I've done a bit of light debugging inside PHPUnit itself (in particular PHPUnit_Runner_StandardTestSuiteLoader::load) and found the class name is incorrectly supplied as a path and not as a namespaced class name. Here is the relevant clause:
if (class_exists($suiteClassName, false)) {
$class = new ReflectionClass($suiteClassName);
if ($class->getFileName() == realpath($suiteClassFile)) {
return $class;
}
}
The value of $suiteClassName is test/unit/tests/UpdateAllTest, which is plainly not a namespaced anything - it should be Awooga\Testing\Unit\UpdateAllTest, something that is normally handled by a custom mapping in my autoloader.
I don't think I am doing anything particularly unusual with PHPUnit, and so find it unlikely that this is a bug that no-one else has thus far experienced. In these circumstances, do I maybe need to declare the class namespaces in the phpunit.xml or something unusual like that? Grasping at straws here!
Any thoughts as to what the cause of this seemingly trivial problem could be would be appreciated. In the meantime I will just move these set-up methods to a different file/class - not ideal but not the end of the world either. I'm on PHP 5.5.x and Ubuntu 12.04.
I haven't fixed this, but my build methods are now so long that it makes sense for them to appear in different classes anyway. I have a naming convention so that a test of *Test.php has a corresponding build class of *Build.php.
I use PHPUnit's bootstrap system to scan for build classes and to call a static build() within automatically.
Maybe you are also experiencing this problem.
Having the path as parameter is normal behavior at this point, check further down in PHPUnit_Runner_StandardTestSuiteLoader::load causes this confusing error message.
Lets suppose I want to auto load classes, so far thats normal. Now, lets suppose we are in "test" environment. I want to load other classes instead, this classes act just like others, but with some modifications. So, originally
class A
{
public function method()
{
return rand(1,10);
}
$a = new A(); // in the meantime autoloader finds and load class A
$a->method();
and what I want:
class Adev
{
public function method()
{
something::log ('method running');
return rand(1,10);
}
}
$a = new A(); // and then I dont need "A" class but "Adev"
$a->method();
so somewhat "renaming" method should be used, instead of refactoring the code.
use get_declared_classes and eval e.g.
$classes = get_declared_classes();
foreach ($classes as $class)
eval("\$".$class." = new ".$class."();");
Updated (and messy)
A couple of possible ways of tackling your issue - may be worth a closer look. At the bottom, there is also a personal consideration/suggestion.
The shortest of short fixes might just apply in your case: instead of having PHP's autoloader looking for the .php extension, you could set it so that, when testing your code, you are in fact looking for files ending on dev.php, so that class A, when passed as a string to the autoloarder becomes Adev.php:
if (RUNNING_ENV=== 'test')
{
spl_autoload_extensions('dev.php');
}
Not sure, but perhaps use getenv() to determine if you're running on test/dev or production environment, and based on that register different autoloaders? spl_autoload_register is a handy function for that:
function prodAutoload($class)
{
//normal loading
}
function tstAutoload($class)
{
$class .='Dev';
//add Dev to className, proceed as you normally would?
}
if (getenv('RUN_ENV') === 'prod')
{
spl_autoload_register('prodAutoload');
}
else
{
spl_autoload_register('tstAutoload');
}
Of course, there will be a bit more to it, than just these few lines. But with this approach, you don't need differently named classes: A will be loaded form either the dev or live file, based on the autoloader/extension.
That way, you can at least keep type-hinting all the way through, without any issues. Of course, maintainability will be even more of a nightmare: Edit 1 file, make sure to edit the other one, too.
That's why I must say, personally, I wouldn't go through all this trouble of writing different classes for test & live environments. At one point, you'll run into trouble with that...
Suppose you fix a bug in test, but fail to edit the production version? Or the other way 'round... I think you're better off spending a little time in setting up a decent debugger and test environment that will work with the same code, but (for example) not the actual production databases.
Useful links:
manage autoload extensions
workings of default autoloader + examples
register (multiple) custom autoloaders)
Have you considered using namespaces? The code that follows is probably not 100% correct, but the gist of it would be:
# A.php
class A {...}
# ADev.php
class ADev {...}
# script.php
use ADev as A;
$a = new A; # of class ADev
See:
http://php.net/manual/en/language.namespaces.importing.php
Have you considered a simple solution rather than a complex one?
Make Class A do what ADev does i.e. include the logging function and forget about duplicating all your classes.
Make the something:: class test a enviroment variable or a simple config variable.
So something::debug tests $DO_I_WANT_DEBUGGING_ON = TRUE, if it is then you do the logging otherwise you do not.
I am recoding my site using CodeIgniter. This is my first time using an MVC or any other type of development pattern. I am using the video tutorials off of the CI site to make a playground and get acquainted with the protocol of the system.
I've just encountered my first problem and it has to do with a parent class.
I am on the second tutorial trying to make a blog and have this:
<?php
class Test extends CI_Controller {
function Test()
{
parent::CI_Controller();
$this->load->scaffolding('entries');
}
function index()
{
$data['muck'] = 'test test test';
$data['kookoo'] = 'howdy howdy hi';
$data['hi'] = 'holla';
$data['yo'] = 'fa la la';
$data['zoom'] = '1234';
$data['array'] = array('hi','howdy','hey','sup');
$this->load->view('test_view', $data);
}
}
?>
When I loaded the page without the content inside the function Test() I noticed that the system could not find "Controller". I discovered that the tutorial is using an older version of CI and that "CI_Controller" is the proper name for the class Controller. Now with the above code I'm getting this error:
Fatal error: Call to undefined method CI_Controller::CI_Controller() in /Users/michaelsanger/Sites/CodeIgniter/application/controllers/test.php on line 7
I've scoured and am really not sure why it can't define it.
thanks in advance!
You're mixing up things from different versions, the 1.7 one focusing mainly on PHP4-style class construction (using a method with the same name as the class as constructor, instead that the dedicated magic method __construct() available in php 5)
Also, beware that scaffolding is not present in the latest versions. You didn't say which one are you using, I suppose V2. In case you're using an older version, 1) use the latest :) 2) the parent class was just Controller.
It should be like this
class Test extends CI_Controller {
function __construct()
{
parent::__construct();
//$this->load->scaffolding('entries');
}
function Test()
{
// this will call a method name test, so maps to a URL like Test/test
}
}
Note that it's not needed to extends the parent controller, unless of course you want to "autoload" a library to have it available to all methods.
CI is known for its great and easy documentation, so whenever you're using tutorial found on the net, expecially if a bit old (in internet terms), make an habit of going to the user_guide (which is also shipped along with the installation files, for local browsing) whenever you have doubts or problems.
For example, check the controllers page, you'll soon see what's wrong with your snippet (and the tutorial, as of today)
UPDATE:
In routes you're setting a route, that maps to a controller(/method).
Quoting the changelog:
Version 2.0.0
Release Date: January 28, 2011 Hg Tag: v2.0.0
General changes
PHP 4 support is removed. CodeIgniter now requires PHP 5.1.6.
Scaffolding, having been deprecated for a number of versions, has been removed.
So I don't know what you mean now with scaffolding. Looking at your route, CI expects a controller named "scaffolding_trigger", which has to be rerouted to the controller "scaffolding". If any of those are present, you get the 404 error.
Please, choose a version and stick to that, don't mix things! and don't rely on tutorials, they're not always up-to-date with the latest changes.
Hello and thanks for reading.
I'll get straight to the point: I have a website project that I've been building using CodeIgniter 1.7.3, which I have thoroughly enjoyed using, however I have been contemplating upgrading to CI 2.0+.
I tried a straight copy, just moved my folders for controllers, models and views over to a CI 2.0 framework, but I got a 500 server error when I tried to view my pages.
After doing some investigation I discovered that all of your controllers must now use "CI_Controller" as their parent class. Also I noticed that if you want to include a constructor in your controller class that it must use the syntax "function __construct()" as its name and of the parent class. It seems that CI 2.0+ no longer supports using a constructor that has the same name as the class name, e.g. "class Blogs extends CI_controller{ function Blogs(){parent::__construct();}}" is no longer supported?
I've been reading the CI Change Log, but all I see are bug fixes, and new features, nothing about compatibility issues with older versions of CI?
Does anyone else know of any other secret little pitfalls?
Thanks,
H
CI 2.x removed all compatibility with PHP4 and also updated a number of standards to be compliant with PHP 5.3 going forward. One of these is the constructor issue you have encountered. As of PHP 5.3, the function ClassName() is no longer the constructor for a class, it is simply another function. You must explicitly declare a __construct function to perform any tasks that need to be done when a new instance of the class is created. Given this, you should see it no longer makes sense to call parent::ClassName() in your child constructor as that function would no longer be the parent's constructor.
Another pitfall I recently had to work out is how the $_GET array is now handled. In the 1.x versions, you could use query strings to pass back extra information and still use URI segments to route to controllers and functions. This is especially useful for AJAX calls where you may not always know all the parameters being sent to and from the server in a particular request. In the 2.x versions, the config.php file contains a new option, $config['allow_get_array']. This must be set to TRUE if you want to use query strings otherwise the input class clears out the $_GET array as part of CI's initialization routine on each request.
Something which isn't a pitfall but you may find useful is the new options in config/autoload.php that allows you to add new application directories to your project. If you work on a number of different projects with CI and want to keep any useful libraries you write in a single location, you can now add that location to $autoload['packages']. CI expects any path in this array to contain the sub-directories "controllers", "models", "libraries" and "helpers". It won't complain if you don't have those directories but you will at least need them for anything you intend to load, i.e. libraries would live in /libraries as with the main application folder.
Have you read the official guide for upgrading from 1.7.x to 2.x ?
so in short
Update Models and Controllers to
extend CI_Model and CI_Controller
Update Parent Constructor calls
class Wow extends CI_Controller {
function __construct()
{
parent::__construct();
//your stuff
}
function index()
{
// just for example
}
}