CodeIgniter get all controller list with its method - codeigniter

I want to create user role and permission based on controller method. For this i needed a list of controllers with its method.
i want it to dynamically if i add a method into any class than it will list in this listing
For that i tried this into my method But the problem is that its only showing the current controller and its method.:
<?php
$controller = $this->router->fetch_class();
$method = $this->router->fetch_method();
?>
Please help.
Thanks in advance

Use this library to get all Codeigniter class with yours methods. On application/config/autoload.php, you need load Controllerlist.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/***
* File: (Codeigniterapp)/libraries/Controllerlist.php
*
* A simple library to list all your controllers with their methods.
* This library will return an array with controllers and methods
*
* The library will scan the "controller" directory and (in case of) one (1) subdirectory level deep
* for controllers
*
* Usage in one of your controllers:
*
* $this->load->library('controllerlist');
* print_r($this->controllerlist->getControllers());
*
* #author Peter Prins
*/
class ControllerList {
/**
* Codeigniter reference
*/
private $CI;
private $EXT;
/**
* Array that will hold the controller names and methods
*/
private $aControllers;
// Construct
function __construct() {
// Get Codeigniter instance
$this->CI = get_instance();
$this->CI->EXT = ".php";
// Get all controllers
$this->setControllers();
}
/**
* Return all controllers and their methods
* #return array
*/
public function getControllers() {
return $this->aControllers;
}
/**
* Set the array holding the controller name and methods
*/
public function setControllerMethods($p_sControllerName, $p_aControllerMethods) {
$this->aControllers[$p_sControllerName] = $p_aControllerMethods;
}
/**
* Search and set controller and methods.
*/
private function setControllers() {
// Loop through the controller directory
foreach(glob(APPPATH . 'controllers/*') as $controller) {
// if the value in the loop is a directory loop through that directory
if(is_dir($controller)) {
// Get name of directory
$dirname = basename($controller, $this->CI->EXT);
// Loop through the subdirectory
foreach(glob(APPPATH . 'controllers/'.$dirname.'/*') as $subdircontroller) {
// Get the name of the subdir
$subdircontrollername = basename($subdircontroller, $this->CI->EXT);
// Load the controller file in memory if it's not load already
if(!class_exists($subdircontrollername)) {
$this->CI->load->file($subdircontroller);
}
// Add the controllername to the array with its methods
$aMethods = get_class_methods($subdircontrollername);
$aUserMethods = array();
foreach($aMethods as $method) {
if($method != '__construct' && $method != 'get_instance' && $method != $subdircontrollername) {
$aUserMethods[] = $method;
}
}
$this->setControllerMethods($subdircontrollername, $aUserMethods);
}
}
else if(pathinfo($controller, PATHINFO_EXTENSION) == "php"){
// value is no directory get controller name
$controllername = basename($controller, $this->CI->EXT);
// Load the class in memory (if it's not loaded already)
if(!class_exists($controllername)) {
$this->CI->load->file($controller);
}
// Add controller and methods to the array
$aMethods = get_class_methods($controllername);
$aUserMethods = array();
if(is_array($aMethods)){
foreach($aMethods as $method) {
if($method != '__construct' && $method != 'get_instance' && $method != $controllername) {
$aUserMethods[] = $method;
}
}
}
$this->setControllerMethods($controllername, $aUserMethods);
}
}
}
}
// EOF

Related

Cannot declare class Spatie\MediaLibrary\UrlGenerator\GcsUrlGenerator because the name is already in use

I'm having a problem with Spatie Media Library. I created my class to use a different filesystem (specifically a Google bucket). Everything works smooth and I can integrate the filesystem correctly, save and view through the custom url. I created my class and gave what "Spatie" describes in its documentation as a namespace namespace Spatie\MediaLibrary\UrlGenerator;
. However, when I run the "artisan config: cache" command I get the error mentioned above.
Here my Custom Class Code extending BaseUrlGenerator:
namespace Spatie\MediaLibrary\UrlGenerator;
use DateTimeInterface;
use Illuminate\Contracts\Config\Repository as Config;
use Illuminate\Filesystem\FilesystemManager;
class GcsUrlGenerator extends BaseUrlGenerator
{
/** #var \Illuminate\Filesystem\FilesystemManager */
protected $filesystemManager;
public function __construct(Config $config, FilesystemManager $filesystemManager)
{
$this->filesystemManager = $filesystemManager;
parent::__construct($config);
}
/**
* Get the url for a media item.
*
* #return string
*/
public function getUrl(): string
{
$url = $this->getPathRelativeToRoot();
if ($root = config('filesystems.disks.'.$this->media->disk.'.root')) {
$url = $root.'/'.$url;
}
$url = $this->rawUrlEncodeFilename($url);
$url = $this->versionUrl($url);
return config('medialibrary.gcs.domain').'/'.$url;
}
/**
* Get the temporary url for a media item.
*
* #param \DateTimeInterface $expiration
* #param array $options
*
* #return string
*/
public function getTemporaryUrl(DateTimeInterface $expiration, array $options = []): string
{
return $this
->filesystemManager
->disk($this->media->disk)
->temporaryUrl($this->getPath(), $expiration, $options);
}
/**
* Get the url for the profile of a media item.
*
* #return string
*/
public function getPath(): string
{
return $this->getPathRelativeToRoot();
}
/**
* Get the url to the directory containing responsive images.
*
* #return string
*/
public function getResponsiveImagesDirectoryUrl(): string
{
$url = $this->pathGenerator->getPathForResponsiveImages($this->media);
if ($root = config('filesystems.disks.'.$this->media->disk.'.root')) {
$url = $root.'/'.$url;
}
return config('medialibrary.gcs.domain').'/'.$url;
}
}
Here what I included in the published vendor of medialibrary
'custom_url_generator_class' => \Spatie\MediaLibrary\UrlGenerator\GcsUrlGenerator::class,
What I'm missing here?
Thanks for helping me
According to the documentation you should implement the Spatie\MediaLibrary\UrlGenerator interface, not the namespace. Alternatively you can extend Spatie\MediaLibrary\UrlGenerator\BaseUrlGenerator which implements that interface itself. So the namespace of your custom class should still adhere to default naming, meaning it should have namespacing according to the folder structure and classname so it gets autoloaded properly.

Laravel, Reusable API Resource method

So I've created an API Resource and in the toArray() method, I've filtered which attributes get returned via query strings. I want to be able to do this for most of my API Resources so it makes sense to move this into a reusable method. What would be the best way of doing this?
I was thinking about extending the base Resource but I'm not sure how I would go about doing that. Or should it be moved into a service class or repository?
My method is below;
public function toArray($request)
{
if($request->fields) {
$fields = [];
$selectedFields = explode(',', $request->fields);
foreach($selectedFields as $field) {
if(isset($this->{$field})) {
$fields[$field] = $this->{$field};
}
}
return $fields;
} else {
return parent::toArray($request);
}
}
Ideally, I would like to do something like...
public function toArray($request)
{
if($request->fields) {
return parent::filterFields($request); // Not sure whether it should be parent::, $this or something else?
} else {
return parent::toArray($request); // Not sure whether it should be parent::, $this or something else?
}
// or event just
return parent::filterFields($request); // Not sure whether it should be parent::, $this or something else?
}
Full Classes:
ProjectResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class ProjectResource extends Resource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
dd(parent::filterFields());
// or
dd($this->filterFields());
if($request->fields) {
$fields = [];
$selectedFields = explode(',', $request->fields);
foreach($selectedFields as $field) {
if(isset($this->{$field})) {
$fields[$field] = $this->{$field};
}
}
return $fields;
} else {
return parent::toArray($request);
}
}
}
Test.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class Test extends Resource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function filterFields($request)
{
return 'test';
}
}
Thank you!
If you're extending the class, you can use either parent:: or $this->. The difference being parent will always refer to the parent class, $this will only refer to the parent if the method does not exist on the current class. Therefore, using $this allows extension of methods and properties.
Example:
<?php
class A {
public function test() {
echo 'A';
}
}
class B extends A {
public function test() {
echo 'B';
}
public function callParent(){
parent::test();
}
public function callThis() {
$this->test();
}
}
$b = new B();
$b->callParent(); // Echoes A
$b->callThis(); // Echos B
In your updated class representation, you have both classes extending Resource but ProjectResource will have no idea about the methods in Test. You would need ProjectResource to extend Test, which will also inherit methods from Resource since Test extends Resource (multiple inheritence).
Beyond that, how you implement is going to be opinion based and you have lots of options. You can extend an abstract class, you can use a dedicated filtering class, or you can use a trait.
You can extend the resource
<?php
namespace App\Http\Resources;
use App\Http\Resources\Product as ProductResource;
class ProductQuantity extends ProductResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
$parent = parent::toArray($request);
return array_merge($parent, [
'depotsQuantity' => $this->warehouses->sum('pivot.quantity'),
]);
}
}

Symfony 3 - Auto generate BOOLEAN getters and setters - isActive vs getActive

Auto-generate BOOLEAN getters and setters - different output
Symfony3.2.0: php bin/console vs PhpStorm 2016.3
There seems to be a difference in generated code if I use the command line doctrine:generate:entities or use the PhpStorm function Generate - Getters and Setters on a BOOLEAN value within an Entity class.
Example: I have set this private variable, below are 3 examples to generate Getters/Setters, which all give a slightly different output.
/**
* #var boolean
* #ORM\Column(name="active", type="boolean")
*/
private $active;
# Generated 'getter' from command line = getActive()
# Generated 'getter' from PhpStorm = isActive()
Console command: php bin/console doctrine:generate:entities MyBundle:MyEntity (note: getActive, return boolean)
/**
* Set active
*
* #param boolean $active
*
* #return MyEntity
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
/**
* Get active
*
* #return boolean
*/
public function getActive()
{
return $this->active;
}
Within PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' enabled) (note: isActive, return bool)
/**
* #return bool
*/
public function isActive()
{
return $this->active;
}
/**
* #param bool $active
* #return MyEntity
*/
public function setActive($active)
{
$this->active = $active;
return $this;
}
and another one: PhpStorm - Code > Generate (Alt+Insert) > Getters and Setters (with checkbox 'Fluent setters' disabled) (note: isActive, return bool, and setActive does not return $this)
/**
* #return bool
*/
public function isActive()
{
return $this->active;
}
/**
* #param bool $active
*/
public function setActive($active)
{
$this->active = $active;
}
My Questions:
Can the commandline tool doctrine:generate:entities be configured somehow to generate getters for boolean values automatically as is... in stead of 'get...' ? (so that it always generates boolean getter methods as: isActive(), isEnabled(), etc)
I saw some examples/tutorials where the method setActive() did not return $this, so no chaining could be used. Is it best practice to return $this? What would be the preferred way? (Is there a disadvantage when you DO return $this, performance maybe?)
Does the minor difference of the return type within the comment section has any effect on the app (database migrations with the command line or something)? Or are the types bool and boolean handled the same way everywhere in Symfony?
(3. Example)
#return bool (Generated by command line)
vs
#return boolean (Generated by PhpStorm)
I've played with the code a bit and unfortunately there is no way to generate it differently with the existent setup. All classes are hardcoded and there is no way to override it with command or Symfony settings.
So I've extended generator classes a bit and created extended command that accepts generator as a parameter. I've also created sample generator that created 'is...' methods for setting booleans.
Unfortunately there are some copy-paste from existent classes because it is not possible to extend it.
Answering 2nd question I think that it is more personal preference using fluent interface. I'm old school developer and I'm not used to fluent interface in PHP. I do not see any major performance impact with it.
For the 3rd question. The difference between bool and boolean is that bool is a scalar type declaration while the boolean is a variable type. See the 'Warning' in the documentation. It explains a lot.
<?php
// src/AppBundle/Command/GenerateDoctrineEntityExtendedCommand.php
namespace AppBundle\Command;
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineEntityCommand;
use Sensio\Bundle\GeneratorBundle\Generator\Generator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class GenerateDoctrineEntityExtendedCommand extends GenerateDoctrineEntityCommand
{
/** #var Generator */
private $generator;
protected function configure()
{
parent::configure();
$this->setName('doctrine:generate:entity:extended');
$this->setDescription($this->getDescription() . " Allows specifying generator class.");
$this->addOption('generator', null, InputOption::VALUE_REQUIRED, "The generator class to create entity.", 'Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator');
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output);
if ($class = $input->getOption('generator')) {
if (!class_exists($class)) {
throw new \Exception('Class ' . $class . 'does not exist.');
}
$this->generator = new $class($this->getContainer()->get('filesystem'), $this->getContainer()->get('doctrine'));
}
}
protected function createGenerator()
{
return $this->generator;
}
}
DoctrineEntityGenerator replacement:
<?php
// src/AppBundle/Generator/IsDoctrineEntityGenerator.php
namespace AppBundle\Generator;
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator;
class IsDoctrineEntityGenerator extends DoctrineEntityGenerator
{
protected function getEntityGenerator()
{
// This is the place where customized entity generator is instantiated instead of default
$entityGenerator = new IsEntityGenerator();
$entityGenerator->setGenerateAnnotations(false);
$entityGenerator->setGenerateStubMethods(true);
$entityGenerator->setRegenerateEntityIfExists(false);
$entityGenerator->setUpdateEntityIfExists(true);
$entityGenerator->setNumSpaces(4);
$entityGenerator->setAnnotationPrefix('ORM\\');
return $entityGenerator;
}
}
EntityGenerator replacement:
<?php
// src/AppBundle/Generator/IsEntityGenerator.php
namespace AppBundle\Generator;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\DBAL\Types\Type;
class IsEntityGenerator extends EntityGenerator
{
protected function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
{
//
// This is the only line I've added compared to the original method
//
$methodPrefix = ($type == 'get' && $typeHint == 'boolean') ? 'is' : $type;
$methodName = $methodPrefix . Inflector::classify($fieldName);
$variableName = Inflector::camelize($fieldName);
if (in_array($type, array("add", "remove"))) {
$methodName = Inflector::singularize($methodName);
$variableName = Inflector::singularize($variableName);
}
if ($this->hasMethod($methodName, $metadata)) {
return '';
}
$this->staticReflection[$metadata->name]['methods'][] = strtolower($methodName);
$var = sprintf('%sMethodTemplate', $type);
$template = static::$$var;
$methodTypeHint = null;
$types = Type::getTypesMap();
$variableType = $typeHint ? $this->getType($typeHint) : null;
if ($typeHint && !isset($types[$typeHint])) {
$variableType = '\\' . ltrim($variableType, '\\');
$methodTypeHint = '\\' . $typeHint . ' ';
}
$replacements = array(
'<description>' => ucfirst($type) . ' ' . $variableName,
'<methodTypeHint>' => $methodTypeHint,
'<variableType>' => $variableType,
'<variableName>' => $variableName,
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null) ? (' = ' . $defaultValue) : '',
'<entity>' => $this->getClassName($metadata)
);
$method = str_replace(
array_keys($replacements),
array_values($replacements),
$template
);
return $this->prefixCodeWithSpaces($method);
}
}
So that's I'm afraid the only option for what you want so far.
Stepashka correctly answered.
But I think there is a better, simplified and more conventional way to help you to use PhpStorm auto generate Getters and Setters methods with Symfony.
You can customize PhpStorm Getters and Setters generation methods!
You just have to go to :
Preferences/Editor/File and Code Templates/Code
Then for Getter, to modify isActive to getActive you have to change "PHP Getter Method" to :
/*
* #return ${TYPE_HINT}
*/
public ${STATIC} function get${NAME}()#if(${RETURN_TYPE}): ${RETURN_TYPE}#else#end
{
#if (${STATIC} == "static")
return self::$${FIELD_NAME};
#else
return $this->${FIELD_NAME};
#end
}
for Setter, to add "return $this" you have to change "PHP Setter Method" to:
/*
* #param ${TYPE_HINT} $${PARAM_NAME}
* #return ${CLASS_NAME}
*/
public ${STATIC} function set${NAME}(#if (${SCALAR_TYPE_HINT})(${SCALAR_TYPE_HINT} #else#end$${PARAM_NAME})
{
#if (${STATIC} == "static")
self::$${FIELD_NAME} = $${PARAM_NAME};
#else
$this->${FIELD_NAME} = $${PARAM_NAME};
#end
return $this;
}
Finally, don't forget to Apply changes.

Show the first error only

I am using code igniter form_validation class to perform a number of validations, since codeigniter validates all the fields and then shows a list of all the errors, I need to restrict this to show only the first error that occurred.
Eg.
If I have 2 (email, message) fields with the required validation in place, and if I were to leave both fields blank. I need codeigniter to show only the error The Email Field is required.
To my knowledge CI doesn't come with this out of the box, but it's easy enough to implement:
Firstly, (if you don't have this file already) create the file MY_Form_validation.php in application/libraries/ with the following:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
public function __construct($rules = array())
{
parent::__construct($rules);
}
}
Then add the following method to that class:
/**
* First Error
*
* Returns the first error messages as a string, wrapped in the error delimiters
*
* #access public
* #param string
* #param string
* #return str
*/
public function first_error($prefix = '', $suffix = '')
{
// No errrors, validation passes!
if (count($this->_error_array) === 0)
{
return '';
}
if ($prefix == '')
{
$prefix = $this->_error_prefix;
}
if ($suffix == '')
{
$suffix = $this->_error_suffix;
}
// Generate the error string
$str = '';
foreach ($this->_error_array as $val)
{
if ($val != '')
{
return $prefix.$val.$suffix."\n";
}
}
return $str;
}
This way you'll be able to access this with $this->form_validation->first_error()
Alternatively, you can create a helper function similar to validation_errors() by (if the file doesn't exist) creating a file called MY_form_helper.php in application/helpers/
and then adding the following code:
/**
* First Validation Error String
*
* Returns the first error associated with a form submission. This is a helper
* function for the form validation class.
*
* #access public
* #param string
* #param string
* #return string
*/
if ( ! function_exists('first_validation_error'))
{
function first_validation_error($prefix = '', $suffix = '')
{
if (FALSE === ($OBJ =& _get_validation_object()))
{
return '';
}
return $OBJ->first_error($prefix, $suffix);
}
}
Hope this helps!

Joomla 2.5 variable global in components scope

Im developing custom Joomla 2.5 backend component. I would like to know best practice of making variable global in my components scope. Should I put declarations in components main controller?
class MyController extends JController
{
/**
*
* #var object External database object
*/
public $dbExternal;
function __construct($config = array())
{
$this->dbExternal = $this->_getDbInstance();
JTable::setDbo($this->dbExternal);
parent::__construct($config);
}
/**
* Display task
*
* #return void
*/
function display($cachable = false, $urlparams = false)
{
// set default view if not set
JRequest::setVar('view', JRequest::getCmd('view', 'My'));
// call parent behavior
parent::display($cachable);
// Set the submenu
MyHelper::addSubmenu('messages');
}
/**
* Getting instance of the database
*
* #return instance $dbExternal Return db instance on success
*/
private function _getDbInstance()
{
$params = $this->_getDbParams();
$dbExternal = JDatabase::getInstance($params);
if ($dbExternal->getErrorNum() > 0)
{
JError::raiseWarning(500, 'JDatabase::getInstance: '.
$dbExternal->getErrorMsg());
$this->isError = true;
}
return $dbExternal;
}
/**
* Getting external db parameters
*
* #return array $dbParamsArr Return db params on success
*/
private function _getDbParams()
{
$dbParamsArr = array();
$params = JComponentHelper::getParams('com_my');
$dbParamsArr['host'] = $params->get('db_host');
$dbParamsArr['user'] = $params->get('db_user');
$dbParamsArr['password'] = $params->get('db_password');
$dbParamsArr['database'] = $params->get('db_database');
$dbParamsArr['driver'] = $params->get('db_driver');
return $dbParamsArr;
}
}
So I would like to reach $dbExternal in any other components controller or model. Any ideas?
To access the $dbExternal variable from another component, you'll need to instantiate a MyController object first. The $dbExternal variable does not exist anywhere until you have an instance of MyController.
$myController = new MyController();
$dbExternal = $myController->$dbExternal;

Resources