Laravel 5 trouble autoloading class - Class Not Found Error - laravel-5.1

I am attempting to autoload my classes. I create a folder app/Classes with a file Foo.php and a file Bar.php.
In composer.json I have the folder referenced
"autoload": {
"classmap": [
"database",
"app/Classes/"
],
"psr-4": {
"App\\": "app/"
},
"files": ["app/Library/myFunctions.php"]
},
Follow this by
composer dump-autoload
Verified the vandor/autoload/autoload_classmap.php has both
'Bar' => $baseDir . '/app/Classes/Bar.php',
'Foo' => $baseDir . '/app/Classes/Foo.php',
I put a simple function in each class like:
<?php
class Bar {
public function __construct(){
echo 'Bar';
}
}
?>
Then I attempt to reference it
new Bar;
and receive the error
FatalErrorException in LoginController.php line 24:
Class 'App\Http\Controllers\Login\Bar' not found
NOW..... to solve the error I put
new \Bar;
and we are good.
Is there some reason I need the '\' in my code. This fix is nowhere for me to find in docs, I just noticed it on laracasts and added it in frustration, and it works.

It's a namespacing issue. It looks like setting "app/Classes/" as a classmap sets classes in there as being in the root namespace. So Foo and Bar are both in the root. Your controller seems to be in this namespace:App\Http\Controllers\Login. Unless otherwise specific class names are taken as relative to the current namespace, so just using Foo makes it look up the class App\Http\Controllers\Login\Foo., where as putting a slash in front stops it being relative and goes straight to the root (think folders or URLs).
If you want it be tidier, you can put use Foo; at the top, below the namespace line if there is one, but before anything else.

Related

Where should I setup DI container in Yii2?

I have an interface. And a class. The classimplements the interface and extends BaseObject. It's something like business logic service. I a'm going to inject it in a controlller via constructor. My target is use dependency from the interface.
I'm looking on the documentation and I don't understand, where should I write this code. Is it a parth of main config? Or it's some kind of new one config? Is it a separete file? If yse, how Yii2 will understand that it's DI configuration?
You can set up DI container in your app config. For example in web.php config:
$config = [
// ...
'container' => [
'definitions' => [
\my\namespace\MyInterface::class => \my\namespace\MyClass::class,
// ... other definitions
],
],
// ... other configs
];
Another good place to set up DI might be in bootstrap method of component. For example in Module class.
class MyModule extends \yii\base\Module implements \yii\base\BootstrapInterface
{
public function bootstrap($app)
{
Yii::$container->set(
\my\namespace\MyInterface::class,
\my\namespace\MyClass::class
);
}
}
In this case you have to add the module to app's bootstrap property.

Class not found for custom plugin block when trying to do dependency injection

I'm attempting to create a custom plugin block in Drupal. When attempting to actually access the services that I've registered I continue to get the following exception:
NOTICE: PHP message: Error: Class 'Drupal\MyNamespace\MyRegisteredService' not found in /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php on line 259 #0 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php(173): Drupal\Component\DependencyInjection\Container->createService(Array, 'foo....')
I have registered the services correctly, and have set up dependency injection correctly (I believe) it's just accessing the services that is not working.
My file structure currently looks like:
- web
- modules
- custom
- foo
- foo.services.yml
- src
- MyService.php
- Plugin
- Block
- FooBlock.php
foo.services.yml looks like:
services:
foo.my_service:
class: Drupal\MyNamespace\MyRegisteredService
autowire: true
FooBlock.php looks like (simply for dependency injection):
namespace Drupal\foo\Plugin\Block;
use Drupal\MyNamespace\MyRegisteredService
use Drupal\Console\Bootstrap\Drupal;
use Drupal\Core\Block\BlockBase;
use GuzzleHttp\Client;
use Http\Client\Exception;
use phpDocumentor\Reflection\Types\Array_;
use stdClass;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FooBlock extends BlockBase implements ContainerFactoryPluginInterface {
private $my_service;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('foo.my_service'),
);
}
function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
Drupal\MyNamespace\MyRegisteredService $my_registered_service,
) {
$this->my_registered_service = $my_registered_service;
}
MyService.php looks like:
<?php
namespace Drupal\MyNamespace;
class MyService
{
static function say_hello()
{
return 'hello world';
}
}
I'm not sure if the way that I'm trying to set this up is incorrect or if I haven't set up dependency injection correctly. Some things that I have tried with no success is changing the namespace and removing Drupal\ from it but this changed little.
I've also tried following several guides (such as this) on how set up services, with little luck.
Any help would be appreciated.
I am not sure about the actual name of your service or namespace path, but I can see a few inconsistencies in your placeholder references:
Please change all references of Drupal\MyNamespace\MyRegisteredService to Drupal\foo\MyRegisteredService where foo is the name of your module. This should be lower cased.
Secondly Drupal\MyNamespace\MyRegisteredService references a class name MyRegisteredService whereas the example class name you give is MyService. These should be equal, so either go with one or the other.

Adding Value Options to Select Element

I'm trying to set multiple values for a select object with Zend Framework 2's form class but it's only passing one value. Here is my code:
public function addphotosAction()
{
$identity = $this->identity();
$files = array();
$album_name = array();
foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
$album_name = basename($dir);
$files[$album_name] = glob($dir . '/*.{jpg,png,gif,JPG,PNG,GIF}', GLOB_BRACE);
}
$form = new AddPhotosForm();
$form->get('copy-from-album')->setValueOptions(array($album_name));
return new ViewModel(array('form' => $form, 'files' => $files));
}
I know it has to do with $album_name but am at a loss about how to use it to grab all the directories (if I try to write to $album_name via []), I get an warning of
`Warning: Illegal offset type in C:\xampp\htdocs\module\Members\src\Members\Controller\ProfileController.php on line 197`
which is the $files[$album_name] = glob($dir . '/*.{jpg,png,gif,JPG,PNG,GIF}', GLOB_BRACE); line.
As I said, I am at a loss about how to edit this to grab all the directories.
Any help would be appreciated.
Thanks!
here is a screenshot of what I am trying to describe: http://imgur.com/OGifNG9
(there is more than one directory that exists but only one is being listed in the select menu).
I really recommend to do it with a factory. With a factory you 'll write this code once and can use it everywhere else in your code. For object orientated reasons, in which everything should be an object, I recommend using PHP 's own DirectoryIterator class instead of glob. The code in the controller should be kept as small as possible. Please have a look at the following example code.
The Form Factory with the Directory Iterator
The form factory intializes the form class with everything you need for the form instance for you, so this code won 't show up in the controller. You can re-use it for an inherited edit form for example.
<?php
namespace Application\Form\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Form\AddPhotosForm;
class AddPhotosFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $oServiceLocator)
{
$oParentLocator = $oServiceLocator->getServiceLocator();
// please adjust the dir path - this is only an example
$aDirectories = [];
$oIterator = new \DirectoryIterator(__DIR__);
// iterate and get all dirs existing in the path
foreach ($oIterator as $oFileinfo) {
if ($oFileinfo->isDir() && !$oFileinfo->isDot()) {
$aDirectories[$oFileinfo->key()] = $oFileinfo->getFilename();
}
}
// set option attribute for select element with key => value array of found dirs
$oForm = new AddPhotosForm();
$oForm->get('mySelectElement')
->setAttributes('options', $aDirectories);
return $oForm;
}
}
That 's all for the factory itself. The only thing you have to do is writing it down in your module.config.php file.
...
'form_elements' => [
'factories' => [
AddPhotosForm::class => AddPhotosFormFactory::class,
],
],
...
Using ::class not just cleans things up, it will lead to using fewer strings and this makes things easy to remember in an IDE with autocompletion for class names.
The Controller
With the factory we cleaned up the controller. In a controller code should be as small as possible. Using factories is the solution for many problems, which may happen in a later process of coding. So keep it always clean and simple.
...
public function indexAction()
{
$oForm = $this->getServiceManager()
->get('FormElementManager')
->get(AddPhotosForm::class);
return [
'form' => $oForm,
}
}
That 's all for the controller so far. Your select element was populated in the factory and your controller is easy to understand and as small as it should be.

Why does the ZF2 autoloader build the path wrongly?

I have an application with some modules. One of them is CourseSearch. Now I want to add a further one, the SportsPartnerSearch. Since these two modules are very similar to each other, I simply "cloned" / copied the CourseSearch and replaced all "Course" with "SportsPartner" (in all variations: $course to $sportsPartner, course-...phtml to sports-partner-...phtml etc.), in order to edit the logic in the second step. Now I'm getting following errors:
Warning:
require_once(/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php):
failed to open stream: No such file or directory in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Fatal error: require_once(): Failed opening required
'/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php'
(include_path='.:/usr/share/php:/usr/share/pear') in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Why is the path to the file being built in such strange way: /path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php? Where did I do a mistake?
Some additional information.
The class, that cannot be found because the wron path is CourseSearch\View\Helper\CourseSearchForm in the CourseSearch module. It can be found, when I deactivate the new module SportsPartnerSearch, that contains the class SportsPartnerSearch\View\Helper\SportsPartnerSearchForm.
The CourseSearchForm view helper is instanciated in the CourseSearchForm\Module
class Module {
public function getViewHelperConfig() {
return array(
'factories' => array(
'courseSearchForm' => function($serviceManager) {
$helper = new View\Helper\CourseSearchForm(array('render' => true, 'redirect' => false));
// ERROR. This code is not executed anymore.
$helper->setViewTemplate('course-search/course-search/course-search-form');
$courseSearchForm = $serviceManager->getServiceLocator()->get('CourseSearch\Form\CourseSearchForm');
$helper->setCourseSearchForm($courseSearchForm);
return $helper;
}
)
);
}
}
And called in the layout file:
echo $this->courseSearchForm();
The SportsPartnerSearch\View\Helper\SportsPartnerSearchForm is instanciated in the same way in the SportsPartnerSearch\Module#getViewHelperConfig() and is not called yet.
Have you generated a classmap? Check the autoload_classmap.php file in both the CourseSearch and the SportsPartnerSearch modules. I guess you still have an old classmap lying around. I think the problem is hidden inside the classmap because of the error in the ClassMapAutoloader from Zend, and not the standard autoloader.
You can generate a new classmap with the classmap generator provided in ZF2 (assuming you load it via Composer) with:
cd module/SportsPartnerSearch
../../vendor/bin/classmap_generator.php
This will generate a new classmap file inside the SportsPartnerSearch module.

How to create a custom yaml config file in Symfony

What I want to do is quite simple: store data in a custom config file that I want to read later on.
I created my file something.yml that I put in the global config directory.
It looks like that:
prod:
test: ok
dev:
test: ko
all:
foo: bar
john: doe
Then I copied the config_handlers.yml and also put it in the config directory and added the following at the top of the file:
config/something.yml:
class: sfDefineEnvironmentConfigHandler
param:
prefix: something_
But if I'm calling sfConfig::get("something_foo"); I keep getting NULL.
What did I do wrong?
I just want to read values, so no need to create a custome config handler, right?
I've read the doc here: http://www.symfony-project.org/book/1_2/19-Mastering-Symfony-s-Configuration-Files even though I'm running 1.4 (I don't think that changed since then).
Edit: Of course I can use sfYaml::load() but I'd like to do things in a better way.
Do not modify the index.php this is dirty!
Juste add this line to your app/frontend/config/frontendConfiguration.class.php
require_once($this->getConfigCache()->checkConfig('config/something.yml'));
(adapt with your own app name)
It's really easy, but also a little bit hacky:
Create the file /config/config_handlers.yml and add this:
config/something.yml:
class: sfDefineEnvironmentConfigHandler
param:
prefix: something_
Then add these two lines to /web/index.php after ... getApplicationConfiguration() (and also add them to frontend_dev.php and wherever you want this config file to be available):
$configCache = new sfConfigCache($configuration);
include($configCache->checkConfig('config/something.yml'));
So your /web/index.php might look like this afterwards:
<?php
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
$configCache = new sfConfigCache($configuration);
$configCache->checkConfig('config/something.yml');
sfContext::createInstance($configuration)->dispatch();
Btw: This is also in the documentation you cited, although the checkConfig() call is in a different place. Look for this: "When you need the code based on the map.yml file and generated by the myMapConfigHandler handler in your application, call the following line:"
Have fun ;-)
If you're doing this for a plugin you need to load the configuration file in the initialize() method. You can still use config_handlers.yml in your plugin's config directory or let the plugin load the handler too.
class myPluginConfiguration extends sfPluginConfiguration
{
public function setup() // loads handler if needed
{
if ($this->configuration instanceof sfApplicationConfiguration)
{
$configCache = $this->configuration->getConfigCache();
$configCache->registerConfigHandler('config/features.yml', 'sfDefineEnvironmentConfigHandler',
array('prefix' => 'feature_'));
$configCache->checkConfig('config/features.yml');
}
}
public function initialize() // loads the actual config file
{
if ($this->configuration instanceof sfApplicationConfiguration)
{
$configCache = $this->configuration->getConfigCache();
include($configCache->checkConfig('config/features.yml'));
}
}
}
The plugin's config initialize() method is called automatically by sfProjectConfiguration class and all appConfiguration classes (trough inheritance).
if your cached config-file is empty, you have probably forgotten to set the environment in your yml-file.
like:
all:
test: value1
test2: value2
dev:
test2: value3
Works in all application files:
$configCache = sfApplicationConfiguration::getActive()->getConfigCache();
$configCache->registerConfigHandler('config/something.yml', 'sfDefineEnvironmentConfigHandler', Array('prefix' => 'something_'));
include $configCache->checkConfig('config/something.yml');
Then you can use:
sfConfig::get("something_foo");
Have you cleared your cache files?
php symfony cc
In prodution environment all config files, classes, etc... are being cached.

Resources