I've created my code as ZF2 pushes you to do it and now I'm starting to think that it's actually against the whole point/benefit of using namespacing in the first place.
I want to change everything but I'm scared to do it my way just because ZF didn't do it this way themselves so I feel like I have to be missing one important thing.
My folder/file structure is something like this:
- Application
- Controller
IndexController.php
- Model
- Table
User.php
Building.php
- Mapper
User.php
Building.php
- Entity
User.php
Building.php
So inside my controller, the code might look something like this, as ZF2 suggests you start out:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController,
Zend\View\Model\ViewModel;
use Application\Model\Entity\User as UserEntity,
Application\Model\Mapper\User as UserMapper,
Application\Model\Table\User as UserTable;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new UserEntity;
$userMapper = new UserMapper;
$userTable = new UserTable;
Right there I've only given a few items but as your application grows, you end up with a HUGE use statement and it seems like it should be done more like the following:
namespace Application;
use Zend\Mvc\Controller\AbstractActionController,
Zend\View\Model\ViewModel;
use Model;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new Entity\User;
$userMapper = new Mapper\User;
$userTable = new Table\User;
I'm guessing it's because ZF2 are pushing Modular based projects that have lots of modules. But surely then I could just throw in that module's namespace if required? I would still need to do that with the more qualified names as currently in use.
The use statement is to import a namespace and about how & when you import, there is no coding standard.
There are two things you have to keep in mind:
Yes, the use of many classes (or namespaces) might get too complicated. Therefore I usually import a namespace, without having the classes imported explicitly. Examples are here (for module features), here (for autoloading) and here (for exceptions). As you see, it's a mixture of FQCN and namespaces.
If you are scared for "if your application grows": think about classes as they encapsulate responsibility. If your class has more than one responsibility, split it into two classes. Then you will also notice your number of imported namespaces will decrease.
By the way, there is a use PSR-2 guideline that states use statements must end with ; for every single use. So not this:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController,
Zend\View\Model\ViewModel;
use Application\Model\Entity\User as UserEntity,
Application\Model\Mapper\User as UserMapper,
Application\Model\Table\User as UserTable;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new UserEntity;
$userMapper = new UserMapper;
$userTable = new UserTable;
}
}
But this:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model\Entity\User as UserEntity;
use Application\Model\Mapper\User as UserMapper;
use Application\Model\Table\User as UserTable;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new UserEntity;
$userMapper = new UserMapper;
$userTable = new UserTable;
}
}
So you might clean things up to this:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new Model\Entity\User;
$userMapper = new Model\Mapper\User;
$userTable = new Model\Table\User;
}
}
And if you want to use your own entity and mapper, but a table from a different module, the code will get refactored into this:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model;
use OtherModule\Model\Table\User as UserTable;
class IndexController extends AbstractActionController {
public function indexAction() {
$userEntity = new Model\Entity\User;
$userMapper = new Model\Mapper\User;
$userTable = new UserTable;
}
}
Related
I have class that I have set up like this:
use MVC\Model;
use \Firebase\JWT\JWT;
class ModelsAuth extends Model {
In my ModelsAuth class, I have this member function:
public function validateToken($token) {
}
I am using this to autoload my classes:
// autoload class
function autoload($class) {
// set file class
$file = SYSTEM . str_replace('\\', '/', $class) . '.php';
if (file_exists($file))
require_once $file;
else
throw new Exception(sprintf('Class { %s } Not Found!', $class));
}
// set autoload function
spl_autoload_register('autoload');
Is it possible to call this class and function from outside the class?
I have tried:
$authorization = new \MVC\Model\ModelsAuth();
$authorization->validateToken($token);
and
$authorization = MVC\Model\ModelsAuth::validateToken($token);
Both return a class not found error.
Any thoughts on what I might be doing wrong with this approach?
You have not declared a namespace for your class, so it's not clear that it will exist as MVC\Model\ModelsAuth and it's probably just going into the root namespace as \ModelsAuth. You probably want something like this:
namespace MVC\Model;
class ModelsAuth extends \MVC\Model {
...
}
Which can also be specified as:
namespace MVC\Model;
use MVC\Model;
class ModelsAuth extends Model {
...
}
I'm not fond of either of these options however, because then you've got a base class named \MVC\Model and a namespace named \MVC\Model, which is somewhat confusing. I'd recommend putting your base class as an abstract into the \MVC\Model namespace, in a file named MVC/Model/AbstractModel.php like this:
namespace MVC\Model;
abstract class AbstractModel {
...
}
And then your model in a file name MVC/Model/MyModel.php like this:
namespace MVC\Model;
class MyModel extends AbstractModel {
...
}
This way, all your models are in the same namespace and the same directory.
Also, if you use a PSR-4 autoloader then most of these sorts of issues will go away.
I need an example of where to exactly create the file, to write to it, and how to use the functions declared in the trait. I use Laravel Framework 5.4.18
-I have not altered any folder in the framework, everything is where it corresponds-
From already thank you very much.
I have Create a Traits directory in my Http directory with a Trait called BrandsTrait.php
and use it like:
use App\Http\Traits\BrandsTrait;
class YourController extends Controller {
use BrandsTrait;
public function addProduct() {
//$brands = Brand::all();
// $brands = $this->BrandsTrait(); // this is wrong
$brands = $this->brandsAll();
}
}
Here is my BrandsTrait.php
<?php
namespace App\Http\Traits;
use App\Brand;
trait BrandsTrait {
public function brandsAll() {
// Get all the brands from the Brands Table.
$brands = Brand::all();
return $brands;
}
}
Note: Just like a normal function written in a certain namespace, you can use traits as well
Trait description:
Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.
The solution
Make a directory in your App, named Traits
Create your own trait in Traits directory ( file: Sample.php ):
<?php
namespace App\Traits;
trait Sample
{
function testMethod()
{
echo 'test method';
}
}
Then use it in your own controller:
<?php
namespace App\Http\Controllers;
use App\Traits\Sample;
class MyController {
use Sample;
}
Now the MyController class has the testMethod method inside.
You can change the behavior of trait methods by overriding them it in MyController class:
<?php
namespace App\Http\Controllers;
use App\Traits\Sample;
class MyController {
use Sample;
function testMethod()
{
echo 'new test method';
}
}
Let's look at an example trait:
namespace App\Traits;
trait SampleTrait
{
public function addTwoNumbers($a,$b)
{
$c=$a+$b;
echo $c;
dd($this)
}
}
Then in another class, just import the trait and use the function with this as if that function was in the local scope of that class:
<?php
namespace App\ExampleCode;
use App\Traits\SampleTrait;
class JustAClass
{
use SampleTrait;
public function __construct()
{
$this->addTwoNumbers(5,10);
}
}
I have multiple DAO classes (or Repository classes in Laravel jargon).
<?php
namespace App\Repository;
class CompanyRepository extends RepositoryFactory
{
public function getCompany($id)
{
$q = "SELECT COMPANY FROM `COMPANIES` WHERE ID > :id1";
$result = DB::select($q, ["id1" => $id]);
return $result;
}
}
?>
<?php
namespace App\Repository;
class ArticleRepository extends RepositoryFactory
{
public function createArticle($title, $summary)
{
….
}
}
?>
Now I would like for one class to include once all my Repositories (30-40 Repositories) with a class such as RepositoryInclude
<?php
namespace App\Repository;
use App\Repository\ArticleRepository;
use App\Repository\CompanyRepository;
use ….
class RepositoryInclude
{
}
?>
so that from my Controller I could simply:
use App\Repository\RepositoryInclude;
class MYController extends Controller
{
public function __construct(CompanyRepository $companyRepository)
{
$this->companyRepository = $companyRepository;
}
public function index()
{
$companyNameList = $this->companyRepository->getCompany();
}
}
How can I do that? apparently nesting classes with a hierarchy of "use" doesn't work as if I nest a series of "include_once".
PS: I would like to use common PHP language techniques which I can reuse in the future and no Laravel "hacks", expecially if they involve command line commands which I'm avoiding as much as possible.
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
{
}
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()