Namespaces in PHP preventing using of Yii static functions - php

I just implemented namespaces in my small application as outlined here: http://www.yiiframework.com/doc/guide/1.1/en/basics.namespace
I'm running into an issue where my controller will no longer access Yii::app()->getRequest(); saying it can't find include(C:\Users\bkuhl\htdocs\instaLabel\application\protected\components\Yii.php): failed to open stream: No such file or directory.
I realize that's because I declared the namespace as application/components. But I'm not sure how to work around this one...
<?php
namespace application\components;
/**
* Controller is the customized base controller class.
* All controller classes for this application should extend from this base class.
*/
class Controller extends \CController {
/* #var $request CHttpRequest */
protected $request = null;
/**
* #var string the default layout for the controller view. Defaults to '//layouts/column1',
* meaning using a single column layout. See 'protected/views/layouts/column1.php'.
*/
public $layout='//layouts/column1';
/**
* #var array context menu items. This property will be assigned to {#link CMenu::items}.
*/
public $menu=array();
/**
* #var array the breadcrumbs of the current page. The value of this property will
* be assigned to {#link CBreadcrumbs::links}. Please refer to {#link CBreadcrumbs::links}
* for more details on how to specify this property.
*/
public $breadcrumbs=array();
public function __construct ($id, $module = null) {
parent::__construct($id, $module);
$this->request = Yii::app()->getRequest();
}

You need to fully qualify the relative class name Yii.
The most convenient way to do this is by importing the class: just add use Yii; below your namespace declaration.

Have you tried:
$this->request = \Yii::app()->getRequest();
\ will use the global namespace:
Prefixing a name with \ will specify that the name is required from the global space even in the context of the namespace.

Related

PHP - How can I test this class?

I'm just getting started with PHPUnit and I'm struggling on how to test certain features. For example, I've got the following class with loads the DotEnv library, and I'd like to test the following features...
Test the variables are loaded
Test it doesn't if the config is already cached
Test it throws an exception if a required variable is missing
But I'm struggling with the best way to do this $app->configurationIsCached() is managed elsewhere so blocks then rest of the class from executing.
<?php declare(strict_types=1);
namespace Foundation\Bootstrap;
use Dotenv\Dotenv;
use Foundation\Core;
class LoadEnvironmentVariables
{
/**
* Any required variables.
*
* #var array
*/
protected $required = [
'APP_URL',
'DB_NAME',
'DB_USER',
'DB_PASS',
'DB_HOST'
];
/**
* Creates a new instance.
*
* #param Core $app The application instance.
*/
public function __construct(Core $app)
{
// If the configuration is cached, then we don't need DotEnv.
if ($app->configurationIsCached()) {
return;
}
// Load the DotEnv instance
$this->load($app->get('paths.base'));
}
/**
* Loads the .env file at the given path
*
* #param string $filePath The path to the .env file
* #return void
*/
public function load(string $filePath)
{
$dotEnv = Dotenv::create($filePath);
$dotEnv->safeLoad();
$dotEnv->required($this->required);
}
}
Regarding your code getting tied up on the $app->configurationIsCached():
Use something like Mockery to create a mock of your Core class you're passing in as $app to your class. You can then mock configurationIsCached(), having it return whatever is needed to route your class through to the early return or the call to your load() method.

PHPDoc return type with extended Factory pattern

I want to use an abstract base class with common functionality for factories to extend, which works, but I don't know how to accurately specify the return type and have it detected by PHPStorm.
Here's an example. Is there a way I can document in PHPDoc that AppleFactory::make() returns AppleInterface and OrangeFactory::make() returns OrangeInterface?
<?php
namespace App\Factories;
abstract class AbstractFactory {
/** #var array $drivers */
protected $drivers;
/**
* instantiate the driver based on the given driver identifier
* #param string $driver Driver identifier.
* #return ???
* #throws UnknownDriverException If driver string is not in list of available drivers.
*/
public function make($driver) {
$class = $this->className($driver);
if (is_null($class))
throw new UnknownDriverException($driver);
return new $class;
}
/**
* get the full class name for the driver
* #param string $driver String mapping of class.
* #return string
*/
public function className($driver) {
return isset($this->drivers[$driver]) ? $this->drivers[$driver] : null;
}
}
class AppleFactory extends AbstractFactory {
protected $drivers = [
// both implement AppleInterface
'fuji' => \App\Apples\Fuji::class,
'gala' => \App\Apples\Gala::class
];
}
class OrangeFactory extends AbstractFactory {
protected $drivers = [
// both implement OrangeInterface
'navel' => \App\Oranges\Navel::class,
'blood' => \App\Oranges\Blood::class
];
}
Is there a way I can document in PHPDoc that AppleFactory::make() returns AppleInterface and OrangeFactory::make() returns OrangeInterface?
Based on your requirements above - a standard #method should do the job -- needs to be placed in PHPDoc comment for that class (AppleFactory and OrangeFactory accordingly). Something like this:
#method AppleInterface make($driver)
At the same time, since you do pass parameter to a factory method .. and returned instance has strong relation to that -- have a look at Advanced Metadata support in PhpStorm (IDE specific functionality). This is what Laravel IDE helper (for example) uses to provide better IDE integration with this framework.
More on this: https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata

Laravel class Auth

Hi can I ask about this in laravel framework
namespace Illuminate\Support\Facades;
/**
* #see \Illuminate\Auth\AuthManager
* #see \Illuminate\Contracts\Auth\Factory
* #see \Illuminate\Contracts\Auth\Guard
* #see \Illuminate\Contracts\Auth\StatefulGuard
*/
class Auth extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'auth';
}
}
what does the return 'auth' exactly returning to the caller ? is it text 'auth' or an object ? and what is the reason why they only have one method in that class ? I apologize i am just learning oop.
Thank you in advance.
In this case as you see method getFacadeAccessor it's returning auth string.
Facades are just "shortcuts" to use other classes but in fact you shouldn't use them everywhere if you don't need to.
In Laravel you can bind objects/classes into Application. So you can write for example:
$app->bind('something', function() {
return new SomeObject();
});
Let's assume there is method doSomething in SomeObject class.
Now you can use this method using:
$app['something']->doSomething();
But you can also create facade:
class GreatClass extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'something';
}
}
and now anywhere in your application you could use:
GreatClass::doSomething();
Answering your question this getFacadeAccessor is returning only the name the name of object that is used when bound to Application. To know how it's used you can look into the source of:
/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
The method you should look first is getFacadeRoot - because this method is returning the requested object.

Strict standards notices View/Layout class

I am geting a headache with php "Strict Standards" notices in a class:
Parent class:
class View {
/**
*
* #param string $viewFolder
* #param string $viewBasename
* #return boolean
*/
public static function exists($viewFolder, $viewBasename){
$exists = false;
if(\is_string($viewFolder) && \is_string($viewBasename)){
$exists = \is_file(\APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml");
}
return $exists;
}
/**
*
* #param string $viewFolder
* #param string $viewBasename
* #param array $viewVariables
*/
public static function load($viewFolder, $viewBasename,array $viewVariables = []){
extract($viewVariables);
require \APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml";
}
}
Child class:
class Layout extends View{
/**
*
* #param string $viewBasename
*/
public static function exists($viewBasename) {
return parent::exists('_layout', $viewBasename);
}
/**
*
* #param string $viewBasename
* #param array $viewVariables
*/
public static function load($viewBasename, array $viewVariables = array()) {
parent::load('_layout', $viewBasename, $viewVariables);
}
}
I've read this topic and now its clear that the reason are those missing parameters in the child class methods.
Declaration of Methods should be Compatible with Parent Methods in PHP
Is there a way of getting rid of these notices without disabling error reporting, or maybe a better approach of doing this?
Thanks in advance.
The better approach is to write your classes in a clean and sensible way. In terms of OOP practice, your child classes that need to extend the parent's methods should redefine them in the same format (hence your warning from PHP).
In your example, your general workflow for the exists() method implementation appears to be the following:
Parent class has an exists method with a folder and a filename
Child class is cutting corners, because it knows its folder already, and only accepts a filename
Child class passes a predefined variable to the parent method
If you look at this objectively, your goal is that the view should be able to call the exists() method on a Layout class and only pass the one parameter, so then you ask "how can I remove the requirement to pass the folder?" Here are a couple of options:
1: Pass the folder name in as the second argument, and making it optional in the Layout (child) class's implementation:
# Class: Layout
/**
* #param string $viewBasename
* #param string $viewFolder
*/
public static function exists($viewBasename, $viewFolder = '_layout') {
return parent::exists($viewBasename, $viewFolder);
}
# Class: View
public static function exists($viewBasename, $viewFolder) {
// essentially you swap around the order of the params
}
2: Don't pass in the folder at all, but use a class property in the child and take advantage of late static bindings:
# Class: Layout
/**
* Define the folder for your layouts
* #var string
*/
const VIEW_FOLDER = '_layout';
The exists() implementation stays the same as in your example currently.
# Class: View
public static function exists($viewBasename) {
// Get your folder from a child instead of an argument
$viewFolder = static::VIEW_FOLDER;
$exists = false;
if(\is_string($viewFolder) && \is_string($viewBasename)){
$exists = \is_file(\APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml");
}
return $exists;
}
A note here, you could also use a function in place of the constant, either abstract in the View class or not, e.g.:
# Class: View
abstract class View {
/**
* This method should be defined in children to provide the layout name.
* Using an abstract method would ensure that it is defined by children,
* however if View is going to be used on its own then do not use this approach.
* #return string The view's folder name
*/
abstract protected static function getViewFolder();
public static function exists($viewBasename) {
// Get view folder from the children (same as the constant example)
$viewFolder = static::getViewFolder();
// ...
}
}
# Class: Layout
class Layout extends View {
protected static function getViewFolder() {
return '_layout';
}
public static function exists($viewBasename) {
return parent::exists($viewBasename);
}
}
To be honest, the constant option is a little shorter and they both essentially do the same thing, other than if you use a function instead of a constant you would be able to define manipulation logic if required.
If I were you, I'd use a class constant for the view folder and take it out as an argument. You'd then implement the static::VIEW_FOLDER in place of the argument passed into load and exists.

Searching for Schema:table static method definition in Laravel Framework

I'm trying to understand PHP Laravel Framework. Whend dealing with databases, we use Schema::table to create a table in the database. Searching in my application I find the only definition is
<?php namespace Illuminate\Support\Facades;
/**
* #see \Illuminate\Database\Schema\Builder
*/
class Schema extends Facade {
/**
* Get a schema builder instance for a connection.
*
* #param string $name
* #return \Illuminate\Database\Schema\Builder
*/
public static function connection($name)
{
return static::$app['db']->connection($name)->getSchemaBuilder();
}
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return static::$app['db']->connection()->getSchemaBuilder();
}
}
but there is not a table static method neither in Schema class or in Facade class.
What piece I'm missing?
Schema here is only facade. Method table() and other methods from Schema can be found in file: \vendor\laravel\framework\src\Illuminate\Database\Schema\Builder.php .
Other methods can be found in \vendor\laravel\framework\src\Illuminate\Database\Schema\Blueprint.php
You should always look at Facade Class Reference to know what class you are really using.

Categories