Codeigniter 4: creating modules - php

I'm trying to create modules in Codeigniter 4 to work with HMVC. I tried following this user guide https://codeigniter4.github.io/userguide/general/modules.html, but cannot get it working.
I created a 'modules' folder, alongside the app, public, etc. folders.
Added to app/config/autoload.php
'Modules' => ROOTPATH.'modules'
Inside the modules folder, I created a 'Proef' folder, containing a Controllers folder and 'Proef.php' file.
The file contains the following;
namespace App\Modules\Proef\Controllers;
class Proef extends \CodeIgniter\Controller
{
public function index() {
echo 'hello!';
}
}
In the app/config.routes.php file I added
$routes->group('proef', ['namespace' => 'Modules\Proef\Controllers'], function($routes)
{
$routes->get('/', 'Proef::index');
});
Yet, the following error persists:
Controller or its method is not found: \Modules\Proef\Controllers\Proef::index
What am I missing?

If you put your modules folder "alongside" and not under your app folder, then your namespace is wrong.
So you would have something like
app/
Modules/ ==> can be modules or Modules but must be set in autoload with the same case
Proef/
Controllers/
Proef.php
NOTE: modules can be Modules or modules but the corresponding entry in the autoload must match.
For modules
'Modules' => ROOTPATH . 'modules'
For Modules
'Modules' => ROOTPATH . 'Modules'
It appears (from my limited testing) that the other folder names must
be 1st letter Upper case. This is under Apache on Linux.
let's use Modules for the folder name so in Autoload.php we would have...
$psr4 = [
'App' => APPPATH, // To ensure filters, etc still found,
APP_NAMESPACE => APPPATH, // For custom namespace
'Config' => APPPATH . 'Config',
'Modules' => ROOTPATH . 'Modules'
];
So your Proef Controller - Proef.php ... Note the namespace being used.
<?php
namespace Modules\Proef\Controllers;
use App\Controllers\BaseController;
class Proef extends BaseController {
public function index() {
echo 'Hello - I am the <strong>'. __CLASS__ . '</strong> Class';
}
}
To make this accessible via the URL you can set the routes (Routes.php) to... (simple version)
$routes->get('/proef', '\Modules\Proef\Controllers\Proef::index');
To make it callable within other Controllers... ( I have borrowed Home.php for this)
<?php namespace App\Controllers;
use \Modules\Proef\Controllers\Proef;
class Home extends BaseController
{
public function index()
{
$mProef = new Proef();
$mProef->index();
return view('welcome_message');
}
//--------------------------------------------------------------------
}
In your URL -
/proef will result in the just the message
/home will result in the class message and the welcome page.
So hopefully this will help you figure this out. its a lot of fun :)
Aside:
You can put your Modules Folder anywhere. I put mine under app/ for ole times sake, which removes the need to add the entry in Autoload.php as they fall under app/ which is already defined.
The namespace and use statement need to be changed appropriately as well.

Edit
namespace to Modules\Proef\Controllers in Proef class

Related

Craft CMS: action input module controller results in 404

I'm making a custom contact form in Craft CMS with a module. The goal is to view all submitted forms in the dashboard and have the possibility to mail after submissions. Submitting the form results in a HTTP 404 – Not Found error.
I made the module, controller and action needed for this. I configured the module in app.php of the config folder and added it to psr-4 in composer.json to autoload it. I know namespacing and routing is a common issue, so I tried a lot of possible combinations.
This is what the folder structure looks like:
modules/
├─ submissions/
├─ Module.php
├─ Controllers/
├─ defaultController.php
The action input of the form looks like this:
{{ actionInput('submissions/default/send-submission') }}
The module looks like this:
<?php
namespace submissions;
use Craft;
class Module extends \yii\base\Module
{
public function init()
{
// Define a custom alias named after the namespace
Craft::setAlias('#submissions', __DIR__);
// Set the controllerNamespace based on whether this is a console or web request
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
$this->controllerNamespace = 'modules\\submissions\\console\\controllers';
} else {
$this->controllerNamespace = 'modules\\submissions\\controllers';
}
parent::init();
}
}
The controller looks like this:
<?php
namespace modules\submissions\controllers;
use Craft;
class defaultController extends Controller
{
protected $allowAnonymous = [
'action' => self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE,
];
public function actionSendSubmission()
{
echo "test";
}
}
Using an actionUrl also results in the same error:
link

Yii2: run console command from controller in vendor directory

I am doing some refactoring of our large work app. This involves separating out some tools I've build, like a schema/seed migration tool for the command line, in to their own repositories to be used by multiple applications.
If it's in console/controllers, it gets picked up. If I move them to their own repository and require it via Composer, how do I get Yii to know when I say php yii db/up, i mean go to the new\vendor\namespace\DbController#actionup ?
If you create an extension (and load it through composer of course), you can locate Module.php inside, which will hold path to console controllers (that you can call with your terminal).
I will write my example for common\modules\commander namespace, for vendor extension your namespace will differ, but it work for all of them the same way.
So I have the following file structure for my extension
<app>
common
modules
commander
controllers
• TestController.php
• Module.php
My Module class looks as follow:
namespace common\modules\commander;
use yii\base\Module as BaseModule;
class Module extends BaseModule
{
public $controllerNamespace = 'common\modules\commander\controllers';
public function init()
{
parent::init();
}
}
And TestController.php is inherited from yii\console\Controller:
namespace common\modules\commander\controllers;
use yii\console\Controller;
class TestController extends Controller
{
public function actionIndex()
{
echo 123;
}
}
And the main part to make everything work is to register out Module.php in console/config/main.php settings
'modules' => [
'commander' => [
'class' => \common\modules\commander\Module::className(),
],
...
],
Here it is, now you can use your command like:
yii commander/test/index
And it'll print you 123, showing that everything works and Console Controllers are located in different folders!

Class auto loader Yii2

I created a new directory at root 'components'. Then I put a file 'ClassName.php' into this folder. Declare a namespace namespace components; and the class named ClassName Now I try to use it like
$c = new app\components\ClassName()
But there's an error. It says that Class 'components\ClassName' not found.
Where am I missing? I suppose that I should add folder components in include_path or something like that. Please help to understand.
I found the solution.
Just add
Yii::setAlias('components', dirname(dirname(\__DIR__)) . '/components');
In className.php:
namespace components;
Then usage:
$c = new components\ClassName();
This is how you can create custom components in Yii2 (basic application)
Create a folder named "components" in the root of your application.
Then create a class for your component with proper namespace and extend Component class:
namespace app\components;
use yii\base\Component;
class MyComponent extends Component {
public function testMethod() {
return 'test...';
}
}
Add component inside the config/web.php file:
'components' => [
// ...
'mycomponent' => [
'class' => 'app\components\MyComponent'
]
]
Now you can access your component like this:
Yii::$app->mycomponent->testMethod();
In ClassName.php:
namespace app\components;
Added
When you create new ClassName instance, don't forget the leading backward slash for namespace (AKA fully qualified namespace), if your current namespace is not global, because in that case namespace will be treated as relative (Like UNIX paths), use:
$c = new \app\components\ClassName(); //If your current namespace is app\controllers or app\models etc.
$c = new app\components\ClassName(); //If your current namespace is global namespace
You can read more about namespaces basics in PHP documentation
It should be late but I guest my solution may help some one later. I had the same issue and the resolved it the way bellow:
If you want to autoload (import) a customer class in your app, you to do:
create your class where ever you want e.g in my case, i created common/core/Utilities.php
then you have to create an alias (alias is a short cut name you give to your folder path). In my case in create an alias for my folder core (note i should also create an alias for my component folder) e.g
Yii::setAlias('core', dirname(DIR).'/core');
this snippet i put it in my common/config/boostrap.php file. because yii2 load this file at running time.
Now you are ready to use your customize class where ever you want. Just do
$utilities = new \core\Utilities();
Hopefully this may !!!!!!!

Extending controller in Zend Framework 2

Here is my app structure:
/application
/config
/library
/Foo
/Controler.php
/module
/User
/config
/src
/Bar
/Controler
/BarController.php
/public
/vendor
/init_autoloader.php
The Controler.php file...
namespace Foo_Controller;
use Zend\Mvc\Controller\AbstractRestfulController;
class Foo_Controller extends AbstractRestfulController {
protected $foo;
public function getFoo()
{
return "foooo";
}
function __construct()
{
parent::__construct();
$foo = $this->getFoo();
}
}
The BarController.php...
namespace Bar\Controler;
use Zend\Mvc\Controller\AbstractRestfulController;
use Foo_Controller\Foo_Controller;
use Zend\View\Model\JsonModel;
class BarController extends Foo_Controller {
.
..
....
}
Added the path /library folder in the init_autoloader.php
$loader = include 'vendor/autoload.php';
$zf2Path = 'vendor/zendframework/zendframework/library';
$loader->add('Zend', $zf2Path);
$loader->add('Julia', 'library'); // added the library folder
if (!class_exists('Zend\Loader\AutoloaderFactory')) {
throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.');
}
I get an error 500 with the following:PHP Fatal error: Class 'Foo_Controller\Foo_Controller' not found in /application/module/Bar/src/Bar/Controller/BarController.php on line #
I really don't know what to do now. I have been searching the internet for some time now for the correct way to extend a controller class in Zend Frazmework 2, but i can't seem to grasp it!
What am i doing wrong in the app?
Thank you
I would suggest you set this out slightly differently. Would really make more sense to create your own custom module which you can load into any project with directory structure like:
/zf2-MyCustomModule
/src
/MyCustomModule
/Controller
/Abstract
/MyAbstractController.php
namespace for MyAbstractController.php would be - MyCustomModule\Controller\Abstract
If it is specific to the project then why not just add
/Abstract
/MyAbstractController.php
to the User Module Controller dir.
but seems like what you have done is pretty much right you would just need to update namespace in Foo_Controller.php to:
namespace Julia\Foo\Controller;
not
namespace Foo_Controller;
Though I have never used the method you are using so am not 100% sure.
I would add a new local config to /config/autoload/
like /config/autoload/namespaces.global.php
Zend\Loader\AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
'Julia' => __DIR__ . '/Library',
),
)
));
then your namespace should still be Julia\Foo\Controller;

Putting models in library directory in Zend Framework

I want to put models outside module directory in Zend Framework. To be precise, in /library folder
library/
models/
actors/
ActorsMapper.php
Actor.php
books/
BooksMapper.php
Book.php
INSTEAD OF
application/
modules/
models/
actors/
ActorsMapper.php
Actor.php
books/
BooksMapper.php
Book.php
This is done so that I don't have to create separate model for each of the module I create.
What configurations will I have to change?
If you need more details, please ask.
Thank you :)
First answer works, but I will give you another answer in case if you want to register autoload in bootstrap.
1) put 'models' folder into library with all Table.php files.
Every model/class should have:
class Model_Table extends Zend_Db_Table_Abstract{ ... }
2) In bootstrap.php put:
protected function _initAutoLoad() {
// Add autoloader empty namespace
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(
array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'model' => array(
'path' => '../library/models/',
'namespace' => 'Model_'
),
),
)
);
return $resourceLoader;
}
That's it. Now you can use your models in controllers like this:
$model = new Model_Table();
If you want to use same models for all modules you can put it in application folder applications/models
and that works fine just like when you have web without modules.
But If you want to have models in library, You can put 'models' folder in your library path and autoload it.
Create folder 'Models' into library with all Table.php files.
In configs/application.ini Put:
autoloaderNamespaces.models = "Models_"
Then you can use namespace 'Models_' in your web application
In controller:
$model = new Models_Table();
in any case, I recommend that you keep the folder models in the path application/models
zend autoloader loading class which name beginning with prefix, that is registred on it.
If you have library in your include path, you can simple register "Models" like default namespace on autoloader and name your class for example Models_Actors_Actor.

Categories