Using Namespaces with spl_autoload_register - namespaces

use PHPMailer\PHPMailer\PHPMailer;
require_once "PHPMailer/PHPMailer.php";
$mail = new PHPMailer(true);
This works great.
But when I try to autoload the classes using spl_autoload_register i get a
Warning: require_once(PHPMailer/PHPMailer\PHPMailer\PHPMailer.php): failed to open stream: No such file or directory
use PHPMailer\PHPMailer\PHPMailer;
spl_autoload_register(function($class){
require_once 'PHPMailer/' . $class . '.php';
});
$mail = new PHPMailer(true);`
I'm a bit confused since the autoloader now requires the full path to the PHPMailer class in the PHPMailer/PHPMailer namespace.

After doing some extended research it seems there are 2 ways to make this work.
when we use the "use" statement we tell spl_autoload_register() where the PHPMailer() class is located. In this example it is located in the PHPMailer/PHPMailer namespace.
In order for this to properly work we need to match the namespace to the folder structure. This means that the PHPMailer.php file must be located in the PHPMailer/PHPMailer folder.
We instantiate like this: $mail = new PHPMailer();
if we don't use the "use" statement we can tell the spl_autoload_register() where the class is when we instantiate the class.
$mail = new PHPMailer/PHPMailer/PHPMailer();

Related

Namespace in php application

I am trying to manage my code in a sample code to learn. I have a sample application whose dir structure is as follow
-Sample
--bootstrap
--app
--class1.php
--class2.php
--class3.php
--config
--public
--resource
--readme
Everything works fine for me, able to autoload the classes and consume all the feature.
Now, I added namespace to my class definition.
namespace Sample\classes;
and my application won't work. In app needs I am trying to add
$obj = new Sample/classes/class1() //no class found
use Sample/classes as Sample
but still class not found error
Any help to consume namespace in this setup will be appreciated.
You need use backslash instead of slash
$obj = new Sample\classes\class1()

Google Contacts API with Yii2

I am trying to use the Google contacts api from within Yii2.
Google provides a composer interface, so I added
"google/apiclient": "1.0.*#beta"
to my composer.json and did "composer update"
Now - how do I actually use this from within my Yii2 controller?
I have a working, standalone test script that works. In that, it does
require_once 'GoogleClientApi/autoload.php';
$client = new Google_Client();
However, this does not seem to work from Yii.
I've tried adding the require to my index.php file, as follows (copying autoload.php from a previous installation since autoload doesn't seem to come with the composer version - why would this be omitted?)
require(__DIR__ . '/../vendor/google/apiclient/autoload.php');
but this results in the following error when called in my controller:
Call to undefined function app\controllers\Google_Client()
I've read the post on http://www.yiiframework.com/doc-2.0/guide-tutorial-yii-integration.html but this doesn't make much sense to me.
Any help appreciated. Thanks
Your code is almost correct:
require_once 'GoogleClientApi/autoload.php';
$client = new \Google_Client();
The "\" is needed to indicate the class exists in the global namespace, as you are - in that piece of code - under the app\controllers namespace.

Perl use module, keep getting Undefined subroutine &main error

I have a perl module DB.pm, inside is somthing like:
package GUI::DB;
use strict;
use DBI;
use vars qw(#ISA #EXPORT);
use Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(fun);
sub fun {
my $dsn = "DBI:mysql:database=test";
return $dsn;
}
Then I wrote test.pl:
#!/usr/bin/perl
use strict;
use warnings;
use lib '~/Downloads/GUI'; #Here is the path of the DB.pm module.
use DB;
my $aa = fun();
I have been trying to fix it for hours, I tried to use comment perl -l /path/to/file aa.pl and it gave me no error but the script didn't run at all, I am purely new to Perl, really stuck.
Please help me.
EDIT: So the module's name is DB.pm and folder's name is GUI now, and I an using use DB in my script, still doesn't work, where should I save the DB.pm file?
use HA; does a couple of things. First, it finds a file HA.pm in the perl library paths (#INC). Second, it calls HA::->import() to allow the HA module to do whatever initialization/exporting it wants; this relies on the module's package matching its filename. If it doesn't, this initialization is quietly skipped (method calls to an import method don't generate an error even if the method does not exist).
So explicitly call import on the package you want, or make the package name match the filename.
Perl doesn't understand ~, see How do I find a user's home directory in Perl?
You also need to give use lib the directory which GUI/DB.pm is in and use GUI::DB:
use lib $ENV{HOME}."/Downloads";
use GUI::DB;

Why aren't namespace autoload classes loading in phpunit tests?

To compliment an existing smorgasbord of arrangements between phpunit,autoload and namespace is this:
I have created a simple test project that runs PhpUnit tests and uses namespace autoloading. I register the autoloading in the bootstrap file like so:
set_include_path(get_include_path() . PATH_SEPARATOR . "/path/to/classes/folder");
spl_autoload_register();
and inside a unit test I load and test my class like so:
$obj = new \some\space\someClass(); // which is in the classes/some/space folder
$this->assertTrue($obj->foo()=='bar');
And I get an error
Fatal error: Class '\some\space\someClass' not found in testSomeClass.php...
While this is not phpunit specific you need to change:
spl_autoload_register();
to
spl_autoload_register('spl_autoload');
Any other component that registers an autoloader unregisters the default __autoload().
If your code has an existing __autoload function then this function must be explicitly registered on the __autoload stack. This is because spl_autoload_register() will effectively replace the engine cache for the __autoload function by either spl_autoload() or spl_autoload_call().
So this is how spl-autoload works together with anything else that uses autoloading.
Make sure your path to classes folder is made relative to script which is run for tests execution. If the script is in subfolder of your projects (for example tests/) then your path should be ../path/to/classes/folder
That's what I have in my tests/bootstrap.php
set_include_path(dirname(__FILE__).'/../classes'.PATH_SEPARATOR.get_include_path());
spl_autoload_extensions('.php');
spl_autoload_register('spl_autoload');

grails base.dir system property

I have a simple grails file upload app.
I am using transferTo to save the file to the file system.
To get the base path in my controller I am using
def basePath = System.properties['base.dir'] // HERE IS HOW I GET IT
println "Getting new file"
println "copying file to "+basePath+"/files"
def f = request.getFile('file')
def okcontents = ['application/zip','application/x-zip-compressed']
if (! okcontents.contains(f.getContentType())) {
flash.message = "File must be of a valid zip archive"
render(view:'create', model:[zone:create])
return;
}
if(!f.empty) {
f.transferTo( new File(basePath+"/files/"+zoneInstance.title+".zip") )
}
else
{
flash.message = 'file cannot be empty'
redirect(action:'upload')
}
println "Done getting new file"
For some reason this is always null when deployed to my WAS 6.1 server.
Why does it work when running dev but not in prod on the WAS server? Should I be accessing this information in a different way?
Thanks j,
I found the best dynamic solution possible. As a rule I never like to code absolute paths into any piece of software. Property file or no.
So here is how it is done:
def basePath = grailsAttributes.getApplicationContext().getResource("/files/").getFile().toString()
grailsAttributes is available in any controller.
getResource(some relative dir) will look for anything inside of the web-app folder.
So for example in my dev system it will toString out to "C:\WORKSPACEFOLDER\PROJECTFOLDER\web-app\ with the relative dir concated to the end
like so in my example above
C:\WORKSPACEFOLDER\PROJECTFOLDER\web-app\files
I tried it in WAS 6.1 and it worked in the container no problems.
You have to toString it or it will try to return the object.
mugafuga
There's a definitive way...
grailsApplication.parentContext.getResource("dir/or/file").file.toString()
Out of controllers (ex. bootstrap)? Just inject..
def grailsApplication
Best regards!
Grails, when it's run in dev mode, provides a whole host of environment properties to its Gant scripts and the app in turn, including basedir.
Take a look at the grails.bat or grails.sh script and you will find these lines:
Unix: -Dbase.dir="." \
Windows: set JAVA_OPTS=%JAVA_OPTS% -Dbase.dir="."
When these scripts start your environment in dev mode you get these thrown in for free.
When you take the WAR and deploy you no longer use these scripts and therefore you need to solve the problem another way; you can either
Specify the property yourself to the startup script for the app server, eg: -Dbase.dir=./some/dir .. however
... it usually makes more sense to use the Grails Config object which allows for per-environment properties
Another option:
def basePath = BuildSettingsHolder.settings.baseDir