how to import multiple namespaces properly - php

I am very new to PHP namespaces and I have a question:
If we import multiple namespaces with the 'use' command, shouldn't we run into issues?
I have been reading through this post http://www.sitepoint.com/php-namespaces-import-alias-resolution/, and in the section about Namespace Importing, it says that you still need to have a qualified prefix next to a function (ie: Lib2), but when looking at some Symfony 2 example files, I don't see that happening.
How is namespacing solving (in the example file below) solving name conflicts?
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Acme\DemoBundle\Form\ContactType;
// these import the "#Route" and "#Template" annotations
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller
{
/**
* #Route("/", name="_demo")
* #Template()
*/
public function indexAction()
{
return array();
}
/**
* #Route("/hello/{name}", name="_demo_hello")
* #Template()
*/
public function helloAction($name)
{
return array('name' => $name);
}
/**
* #Route("/contact", name="_demo_contact")
* #Template()
*/
public function contactAction(Request $request)
{
$form = $this->createForm(new ContactType());
$form->handleRequest($request);
if ($form->isValid()) {
$mailer = $this->get('mailer');
// .. setup a message and send it
// http://symfony.com/doc/current/cookbook/email.html
$request->getSession()->getFlashBag()->set('notice', 'Message sent!');
return new RedirectResponse($this->generateUrl('_demo'));
}
return array('form' => $form->createView());
}
}

I think the misunderstanding comes from the post's filenames. keep in mind:
DefaultController.php with namespace Acme/AcmeBundle/Controller/ will be included with use Acme/AcmeBundle/Controller/DefaultController
DefaultController2.php with namespace Acme/AcmeBundle/Controller2/ will be included with use Acme/AcmeBundle/Controller2/DefaultController2
To have a conflict you'd need to include two files named DefaultController.php
DefaultController.php with namespace Acme/AcmeBundle/Controller
DefaultController.php with namespace Acme/AcmeBundle/Controller2
And would then need an alias as pointed out by Kevin
DefaultController.php with namespace Acme/AcmeBundle/Controller
=> use Acme/AcmeBundle/Controller/DefaultController
DefaultController.php with namespace Acme/AcmeBundle/Controller2
=> use Acme/AcmeBundle/Controller2/DefaultController as DefaultController2

Maybe the best way to explain this is to work backwards from the namespace resolution.
Say you have a line like the following:
$newFoo = new Foo();
PHP will look through the current symbol table for the class Foo. That symbol table includes the current namespace and any imported (use) namespaces (as well as built-in PHP symbols).
For example, say class Foo is declared in Foo.php:
<?php //Baz/Foo.php
namespace Baz\Foo;
class Foo{}
If you were working in Bar.php, you could reference the following:
<?php //Baz/Bar.php
namespace Baz\Bar;
use Baz\Foo;
//The following lines are equivalent
$newFoo = new Foo\Foo(); //Local namespace
$newFoo = new \Baz\Foo\Foo(); //Fully qualified namespace
You could also reference the Foo class directly in your use, rather than referencing the Foo namespace.
<?php //Baz/Bar.php
namespace Baz\Bar;
use Baz\Foo\Foo;
//The following lines are equivalent
$newFoo = new Foo(); //Local namespace
//$newFoo = new Foo\Foo(); //This will fail, as the symbol Foo is a class, not a namespace
$newFoo = new \Baz\Foo\Foo(); //Fully qualified namespace still works.
If you wanted to reference both the Namespace and the Class Foo directly, you'd need to resolve the conflict with an Alias.
<?php //Baz/Bar.php
namespace Baz\Bar;
use Baz\Foo;
use Baz\Foo\Foo as FooClass;
//The following lines are equivalent
$newFoo = new FooClass(); //Notice the new aliased symbol.
$newFoo = new Foo\Foo(); //This works now.
$newFoo = new \Baz\Foo\Foo(); //Fully qualified namespace still works.
//$newFoo = new \Baz\Foo\FooClass(); //This will fail, aliases don't work for fully qualified names.
Also, say, in addition to your Baz/Foo.php file, you have a Bar/Foo.php file as such:
<?php //Bar/Foo.php
namespace Bar\Foo;
class Foo{}
If you wanted to reference both namespaces locally, you'll need aliases to resolve the name conflict:
<?php //Baz/Bar.php
namespace Baz\Bar;
use Baz\Foo as Foo1;
use Baz\Foo\Foo as Foo1Class;
use Bar\Foo as Foo2;
use Bar\Foo\Foo as Foo2Class;
//The following lines are equivalent, referencing Baz\Foo\Foo
$newBazFoo = new Foo1Class(); //Object alias.
$newBazFoo = new Foo1\Foo(); //Namespace alias.
$newBazFoo = new \Baz\Foo\Foo(); //Fully qualified namespaces don't need any aliases.
//The following lines are equivalent, referencing Bar\Foo\Foo
$newBarFoo = new Foo2Class(); //Object alias.
$newBarFoo = new Foo2\Foo(); //Namespace alias.
$newBarFoo = new \Bar\Foo\Foo(); //Fully qualified namespaces don't need any aliases.
In addition to importing the Namespace with the use statement, you will also need to include the file containing that namespace. This can be done manually with require_once(), but is normally handled automatically by an autoloader.
See Symfony Class Loader for more details.
Hope that helps.

Related

PHP Cannot redeclare class - Require error - Silex Framework

I'm working on a project, but I have a very annoying problem. I use a PHP file rb.php that contains several important classes for the project (File rb.php of the RedBean ORM, all in one).
The problem is that I can use the file correctly with a require in a special location, but not in another location.
This is my arborescence:
When I go to index.php, everything goes well, i can do require('rb.php');
<?php
require_once 'vendor/autoload.php';
require('rb.php');
R::setup('mysql:host=localhost;
dbname=silex','root','');
require('Model_Bandmember.php');
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$srcDir = __DIR__;
$app = new Application();
$app['debug'] = true;
$app->register(new DDesrosiers\SilexAnnotations\AnnotationServiceProvider(), array(
"annot.controllerDir" => $srcDir."\controllers"
));
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => $srcDir.'\views',
));
$bandmember = R::dispense('bandmember');
$bandmember->name = 'Fatz Waller';
$id = R::store($bandmember);
$bandmember = R::load('bandmember',$id);
R::trash($bandmember);
echo $lifeCycle;die();
$app->run();
I have the good value of $lifeCycle. But I would like to use this file in a controller for functions add (), updates () etc .. So I try this :
<?php
namespace App\Controllers;
use DDesrosiers\SilexAnnotations\Annotations as SLX;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
require(__DIR__.'/../rb.php');
/**
* #SLX\Controller(prefix="article")
*/
class ArticleController
{
/**
* #SLX\Route(
* #SLX\Request(method="GET", uri="/"),
* #SLX\Bind(routeName="articleIndex")
* )
*/
public function index(Application $app)
{
$articles = R::findAll('article');
return $app['twig']->render('Article/index.twig', array(
'articles' => $articles,
));
}
...
...
But i have this error :
Cannot redeclare class RedBeanPHP\RedException in C:\wamp64\www\SilexTest\rb.php on line 6737
Very well, I think that the file must already be present! But if i comment it i have this error :
Class 'App\Controllers\R' not found
This is normal because this class is in the rb.php file that I just commented on.
If I do a require, I have a class redeclare , but if I do not put it, it lacks a class.
Any help will be appreciated.
Since the rb is already included so no need to include it anywhere. To use it from the global scope , you've to use \R:
$articles = \R::findAll('article');
Because, it seems like that, the R is available in the global scope. In this case, you can use use R; at the top of your class, for example:
namespace App\Controllers;
use DDesrosiers\SilexAnnotations\Annotations as SLX;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use R; // <-- Notice this
/**
* #SLX\Controller(prefix="article")
*/
class ArticleController
{
// Use: R::findAll('article') in any method in this class
}
You should read about namespace in PHP.

Can't use a namespace in a Controller

I have this Controller :
namespace FacilitaTripBundle\Controller;
use FacilitaTripBundle\Api\models\GuideDestination\GuideDestinationModel;
use FacilitaTripBundle\Api\models\Destination\DestinationModel;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
/**
* #Route("/api/v1", name="api")
*/
class ApiController extends Controller
{
/**
* #Route("/destinations/get_all_minimal/", name="destination_get_minimal")
*/
public function getMinimalAction()
{
$model = new DestinationModel();
$data = $model->getAllMinimal();
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
/**
* #Route("/guideDestination/getLastAddDestination/", name="destination_last_add_destination")
*/
public function getLastAddDestinationAction()
{
$guide_destination_model = new GuideDestinationModel();
$data = $guide_destination_model->getLastAddDestination();
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
I got this error :
Attempted to load class "GuideDestinationModel" from namespace "FacilitaTripBundle\Api\models\GuideDestination".
Did you forget a "use" statement for another namespace
I define the class GuideDestinationModel in this file :
namespace FacilitaTripBundle\Api\models\GuideDestination;
class GuideDestinationModel {
}
How you got an idea why I got this error ?
What is the physical path to file containing GuideDestinationModel class?
According to PSR-0, which Symfony is using, you are supposed to put class definitions in path which corresponds to your namespace like in following example.
\Symfony\Core\Request =>
/path/to/project/lib/vendor/Symfony/Core/Request.php
I notice you have lowercase models in your FacilitaTripBundle\Api\models\GuideDestination namespace. Is your directory models also lowercase? If not this might be the issue here if you are using system which is case sensitive when it comes to path resolving (i.e. Linux)

Loading custom class in CakePHP3

I am trying to load a custom class in my CakePHP3 project, although I can't seem to find out what I am missing.
I have a folder src/Library with Config.php in it:
<?php
namespace App\Library;
/**
* Class containing CONST values for important settings
*
* #version 1.0
* #author berry
*/
class Config
{
const UPLOAD_DIRECTORY = './upload/';
}
I put use App\Library\Config; in my PicturesController, which Visual Studio even recognizes as a valid class (I can access the const through intellisense)
Here is my controller:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
use App\Library\Config;
/**
* Pictures Controller
*
* #property \App\Model\Table\PicturesTable $Pictures
*/
class PicturesController extends AppController
{
public function upload()
{
if($this->request->is('post'))
{
$oConfig = new Config();
$oUploadDir = new Folder($oConfig::UPLOAD_DIRECTORY);
debug($oUploadDir);
$aFile = $this->request->data('submittedfile');
}
}
So despite my IDE even registering the class (and telling me I'm using it correctly) I get Class 'App\Library\Config' not found thrown in the browser.
I changed the name from Library to Berry (My first name).
Apparently you can't call it Library. Probably used somewhere else in Cake.

Unable to use helper in controller of laravel app

I'm building an application, now i'm created a helper
class Students{
public static function return_student_names()
{
$_only_student_first_name = array('a','b','c');
return $_only_student_first_name;
}
}
now i'm unable to do something like this in controller
namespace App\Http\Controllers;
class WelcomeController extends Controller
{
public function index()
{
return view('student/homepage');
}
public function StudentData($first_name = null)
{
/* ********** unable to perform this action *********/
$students = Student::return_student_names();
/* ********** unable to perform this action *********/
}
}
this is my helper service provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
foreach(glob(app_path().'/Helpers/*.php') as $filename){
require_once($filename);
}
}
}
i event added it as an alias in config/app.php file
'Student' => App\Helpers\Students::class,
Try putting use App\Helpers\Student; at the top of your controller beneath the namespace delcaration:
namespace App\Http\Controllers;
use App\Helpers\Student;
class WelcomeController extends Controller
{
// ...
Look more into PHP namespaces and how they are used, I believe you may have a deficient understanding about them. Their only purpose is to make so you can name and use two classes with the same name (e.g. App\Helpers\Student vs maybe App\Models\Student). If you needed to use both of those classes inside of the same source file, you can alias one of them like this:
use App\Helpers\Student;
use App\Models\Student as StudentModel;
// Will create an instance of App\Helpers\Student
$student = new Student();
// Will create an instance of App\Models\Student
$student2 = new StudentModel();
You do not need to have a service provider for this, just the normal language features. What you would need a service provider for is if you wanted to defer the construction of your Student object to the IoC:
public function register()
{
$app->bind('App\Helpers\Student', function() {
return new \App\Helpers\Student;
});
}
// ...
$student = app()->make('App\Helpers\Student');
You should never have to include or require a class file in laravel because that is one of the functions that composer provides.
You do not need a service provider to make it works. Just lets the Students class as you did:
class Students{
public static function return_student_names()
{
$_only_student_first_name = array('a','b','c');
return $_only_student_first_name;
}
}
all its methods should be static
You added the Facade correctly:
'Student' => App\Helpers\Students::class,
Finally, looks like your problem is caused by forgetting a backslash at facade name. Uses \Students instead of Students:
public function StudentData($first_name = null)
{
$students = \Student::return_student_names();
}
When using a facade, it is not necessary makes nay include, the facades were made to avoid complex includes in everywhere.

PHP Possible to use namespaces (or anything else) to include two classes of same name

I have a class named 'Users' in /v1/users.php and another class named 'users' in /v2/users.php (v1 is a legacy API to our database). I'm trying to write migration code using both APIs.
Is there a way I can use both of these classes in a migration class? I unfortunately can't declare the namespaces in the users.php files themselves, but am wondering if there's some way I can encapsulate the include itself in a namespace? For example, in migrations.php:
<?php
namespace v1 {
require_once("v1/users.php");
}
namespace v2 {
require_once("v2/users.php");
}
class migration
{
public function migrateUser($v1UserId)
{
$v1Users = new v1\Users;
$v2Users = new v2\users;
$v2Users->addUser($v1Users->getUser($v1UserId));
}
}
?>
Along with Rocket Hazmat's comment, I'm pretty sure you need a global/blank namespace for the other code as well. Once you use the bracketed namespace { } syntax in a file, all code must be in a namespace:
namespace {
class migration
{
public function migrateUser($v1UserId)
{
$v1Users = new \v1\Users;
$v2Users = new \v2\users;
$v2Users->addUser($v1Users->getUser($v1UserId));
}
}
}

Categories