I am trying to create an ACL component as a service, for a multi-module PhalconPHP application. When I call the ACL component from the Controller Base, I am getting an error that I can't re-declare the ACL class.
Any ideas how to fix it, and understand the logic of why it is re-initialized again?
Fatal error: Cannot declare class X\Acl\Acl because the name is already in use in C:\xampp\htdocs\x\app\common\Acl\Acl.php on line 12
Update:
If I changed everything to "Pacl" then it works. I assume there might be a mixup with the PhalconPHP namespace. I am either not using the namespaces properly, or there's a bug in PhalconPHP 2.1 Beta 2.
/app/common/Acl/Acl.php
namespace X\Acl;
use Phalcon\Mvc\User\Component;
use Phalcon\Acl;
use Phalcon\Acl\Role as AclRole;
use Phalcon\Acl\Resource as AclResource;
/*
* ACL component
*/
class Acl extends Component {
private function initialize() {
}
public function isAllowed() {
die('called');
}
}
/app/front/controllers/ControllerBase.php
namespace X\Front\Controllers;
use Phalcon\Session as Session;
use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;
class ControllerBase extends Controller {
public function beforeExecuteRoute(Dispatcher $dispatcher) {
//$this->acl = $this->getDI()->get("acl");
var_dump($this->acl->isAllowed()); //same behavior in both case
}
}
/app/front/Module.php
namespace X\Front;
use Phalcon\DiInterface;
use Phalcon\Mvc\Dispatcher;
use X\Acl\Acl as Acl;
class Module {
public function registerAutoloaders() {
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
'X\Front\Controllers' => __DIR__ . '/controllers/',
'X\Front' => __DIR__,
'X' => __DIR__ . '/../common/'
));
$loader->register();
}
public function registerServices(DiInterface $di) {
$di['acl'] = function() {
return new Acl();
};
}
}
This is not Phalcon issue. Look closely at your code:
namespace X\Acl;
use Phalcon\Acl;
class Acl extends ... {
}
What Acl interpreter should use? X\Acl\Acl or Phalcon\Acl?
The same error you get for example for the following code
namespace My\Awesome\Ns;
use Some\Name; # Name 1
class Name # Name 2
{
}
Related
I'm working on a Laravel (5.4) package, and I'm trying to do unit testing. I have this class :
<?php
namespace Sample;
class Foo
{
public function getConfig()
{
$config = \Config::get('test');
return $config;
}
}
I have this test :
<?php
use PHPUnit\Framework\TestCase;
use Sample\Foo;
class FooTest extends TestCase
{
public function testGetConfig()
{
$foo = new Foo;
$config = $foo->getConfig();
}
}
When I execute phpunit I have this error :
Error: Class 'Config' not found
How can I unit test this class ?
Thank you.
Instead of extends PHPUnit\Framework\TestCase, you should extends Tests\TestCase:
<?php
namespace Tests\Unit;
// use PHPUnit\Framework\TestCase;
use Tests\TestCase;
use Sample\Foo;
class FooTest extends TestCase
{
public function testGetConfig()
{
$foo = new Foo;
$config = $foo->getConfig();
}
}
Moreover, Config or other Laravel facades may not work in #dataProvider method, please see Laravel framework classes not available in PHPUnit data provider for more info.
It is good practice to mock the dependencies in your code. In this case you are depending on an outside class (Config). Usually I test it like this:
// make sure the mock config facade receives the request and returns something
Config::shouldReceive('get')->with('test')->once()->andReturn('bla');
// check if the value is returned by your getConfig().
$this->assertEquals('bla', $config);
Obviously, you need to import the Config facade in your test.
BUT: I would inject the Config class in the constructor in my real code, instead of using the facade. But that's me... :-)
Something like this
class Foo
{
/** container for injection */
private $config;
public function __construct(Config config) {
$this->config = $config;
}
public function getConfig()
{
$config = $this->config->get('test');
return $config;
}
}
And then test it by injecting a mock Config into the constructor.
Try by including like this
use Illuminate\Support\Facades\Config;
I'm trying to set up PSR-4 within a new Laravel 4 application, but I'm getting some troubles achieving what I want when it comes to build controllers.
Here's what I have now :
namespace MyApp\Controllers\Domain;
class DomainController extends \BaseController {
public $layout = 'layouts.default';
public function home() {
$this->layout->content = \View::make('domain.home');
}
}
I'm not so fond of using \View, \Config, \Whatever to use Laravel's classes. So I was wondering if I could put a use Illuminate\View; to be able to use View::make without putting a \.
Unfortunately, while doing this, I'm getting the following error : Class 'Illuminate\View' not found.
Could somebody help with this please ?
The problem in your case is that View is not located in Illuminate namespace but in Illuminate\View namespace, so correct import would be not:
use Illuminate\View;
but
use Illuminate\View\View;
You can look at http://laravel.com/api/4.2/ to find out which namespace is correct for class you want to use
Assuming BaseController.php has a namespace of MyApp\Controllers\Domain
namespace MyApp\Controllers\Domain;
use View;
class DomainController extends BaseController {
public $layout = 'layouts.default';
public function home() {
$this->layout->content = View::make('domain.home');
}
}
If BaseController.php has other namespace, i.e MyApp\Controllers
namespace MyApp\Controllers\Domain;
use MyApp\Controllers\BaseController;
use View;
class DomainController extends BaseController {
public $layout = 'layouts.default';
public function home() {
$this->layout->content = View::make('domain.home');
}
}
If, for instance, you controller needs to use another base class from Laravel, lets say Config.
namespace MyApp\Controllers\Domain;
use MyApp\Controllers\BaseController;
use View;
use Config;
class DomainController extends BaseController {
public $layout = 'layouts.default';
public function home() {
$this->layout->content = View::make('domain.home')->withName(Config::get('site.name'));
}
}
The use of View::make() takes advantage of the Laravel facades. To properly reference the facade, instead of directly referencing the class that gets resolved out of the iOC container, I would use the following:
use Illuminate\Support\Facades\View;
This will reference the View facade that is being used when calling View::make()
I am trying to get my Facade class to work, however it seems Laravel is calling the method on my Facade class instead of calling it on my root class. So I get method undifined error. When I create the the feed class directly from the binding ( App::make('feed')->addArticle();) it works. So I think there is soemthing wrogn with my Facade. Any ideas? Thank in advance.
Controller
class RssController extends BaseController
{
public function getArticles() {
Feed::addArticle();
}
}
ServiceProvider
use Illuminate\Support\ServiceProvider;
class FeedServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('feed', function()
{
return new Feed;
});
}
}
Facade class
use Illuminate\Support\Facades\Facade;
class FeedFacade extends Facade {
protected static function getFacadeAccessor()
{
return 'feed';
}
}
Root Class
class Feed {
//vars
public function __construct()
{
}
public function make() {
return new Feed();
}
public function addArticle() {
return '#addArticle';
}
The problem seems to be you want both your Laravel Facade (Feed::), and the implementation class of your service provider (class Feed) to have the same name. Facades work because in app/config/app.php there's an alias section
'aliases' => array(
'App' => 'Illuminate\Support\Facades\App',
'Artisan' => 'Illuminate\Support\Facades\Artisan',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Blade' => 'Illuminate\Support\Facades\Blade',
This aliasing means whenever you use, say, the App facade
`App::someMethod`
Laravel actually invokes the getFacadeAccessor on Illuminate\Support\Facades\App. There's no global class App in the system. If there were it would cause a similar problem with the facade.
Get an alias for Feed=>Illuminate\Support\Facades\Facade\FeedFacade into your system, and get your implementation class Feed out of the global namespace (moving the file to an appropriate place)
<?php
namespace My\Namespace;
class Feed
{
}
...
return new \My\Namespace\Feed;
and you should be all set.
Also, at the risk of confusing you, you don't need to drop your own classes in the Illuminate\Etc\... namespace, and you should probably put them in your own unless you're trying to get the core Laravel team to accept your classes as the official feed service.
I have a base controller as follows
<?php
use Phalcon\Mvc\Controller;
class ControllerBase extends Controller {
public function initialize() {
}
// wrapper function for debug purposes.
public function pr($data = null) {
echo '<pre>';
print_r($data);
echo '</pre>';
}
}
and a users controller as follows
<?php
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model as Paginator;
use Phalcon\Mvc\View;
class UsersController extends ControllerBase {
public function initialize() {
// initialize parent, here ControllerBase.
parent::initialize();
}
public function loginAction() {
// disable the main layout.
$this->view->disableLevel(View::LEVEL_MAIN_LAYOUT);
// disable the controller layout.
$this->view->disableLevel(View::LEVEL_LAYOUT);
}
.
.
.
.
other functions...
}
i was wondering if i could call all the required phalcon classes in base controller and extend then to all the child classes so that i dont need to call them individually on each controller.
in otherwords, can i add the below code
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model as Paginator;
use Phalcon\Mvc\View;
only in the base controller and acces them in other controllers. I tried putting them base controller but it gave error : Class not found.
Is this the right way or is there something wrong in my approach...please help.
If I understand your question correctly the answer is NO.
Namespaces are language feature and works this way. The use Phalcon\Mvc\Model\Criteria only declares that you'll use Criteria class from Phalcon\Mvc\Model\ namespace. So in your code you can write new Criteria() to create object instead of using its' full name new \Phalcon\Mvc\Model\Criteria().
You must declare each class in every file which instantiates object of that class so autoloader will know in which file given class exists.
I'm building a small REST API with Laravel 4. I'm using an HMVC scheme in the application. The issue is, when I try to call a controller for the API, PHP says that the class is not instantiable.
Target [App\Modules\ChunkletAPI\v1\ServerController] is not instantiable.
Here's the class itself, in v1/controllers:
<?php namespace App\Modules\ChunkletAPI\v1;
class ServerController extends ChunkletAPI {}
Which inherits from
<?php namespace App\Modules\ChunkletAPI\v1;
use Controller;
abstract class ChunkletAPI extends Controller {
protected $name;
protected function __construct() {
$this->name = '\Model\ ' . str_replace('Controller', '', get_class($this));
}
public function index() {
$n = $this->name;
return $n::all();
}
}
The routing is done by:
<?php namespace App\Modules\ChunkletAPI;
use \Illuminate\Support\Facades\Route;
Route::group(array('prefix' => 'api/v1'), function()
{
Route::resource('server', 'App\Modules\ChunkletAPI\v1\ServerController');
});
I cannot figure out what is occurring - I've tried playing around, making the parent class non-abstract, etc - and Google is no help. Any ideas?
Found out why. ChunkletAPI->__construct() had to be set as public, not protected. Otherwise, it looked to Laravel like a static class.