I have a file called application.config.php in my apps root directory. I want to require it or autoload it for my tests. The config file is like so:
<?php
// database connection
$config = array(
'database' => array(
'dsn' => 'mysql:host=localhost;dbname=budgetz',
'user' => 'budgetz_user',
'password' => 't1nth3p4rk',
),
);
My app uses these to connect to the database. So, to test my models they also need to connect to the database, .. or some database. Is it just a matter of something along the lines of requiring it in the test file:
<?php
require_once 'vendor/autoload.php';
require_once 'application.config.php';
class MapperTest extends PHPUnit_Framework_TestCase {
public function testFetchOne() {
$dbAdapter = new DatabaseAdapter($config['database']);
$userMapper = new UserMapper($dbAdapter); // using UserMapper but any child of Mapper will do
$user = $userMapper->fetchOne(1);
$this->assertsEquals(1, $user->id, 'message');
}
}
I tried this but I get the error:
There was 1 error:
1) MapperTest::testFetchOne
Undefined variable: config
/var/www/new_orm/test/MapperTest.php:8
What am I doing wrong? Also, I appreciate anyone giving some advise on best practise here. Perhaps this approach to requiring a config file in every page is a little old. Thanks
Globals is an option, but not good one.
Create your class, witch extends PHPUnit_Framework_TestCase. Then use the setup to set your config.
e.g.
class myTestCase extends PHPUnit_Framework_TestCase {
private $config;
public function setUp() {
$this->config = ....
}
public function getConfig() {
return $this->configl
}
Then your testcases should extends myTestCase. You could access config with
$this->getConfig();
Anyway, accessing dev db is not a good idea, maybe it is better to mock the work with the db ?
Try
public function testFetchOne() {
global $config;
Related
I wanted to use Doctrine in my project, but I am not able to use Entity Manager.
I have created entites, repositories, config files and dbconnect but it seems that it's not done correctly.
Can you please check this code? Maybe I'm missing something really small.
My dbconnect file(it is bootstrapped in init.php):
<?php
namespace Projekt\Config;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
$paths = array("Entity");
$isDevMode = false;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'projekt',
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
$em = EntityManager::create($dbParams, $config);
My Repository example:
<?php
namespace Projekt\Repository;
use Doctrine\ORM\EntityRepository;
/**
* Message
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class Message extends EntityRepository
{
public function getMessage($id)
{
$message = $this->find($id);
return $message;
}
public function getAllMessages()
{
}
public function createMessage()
{
}
public function updateMessage()
{
}
public function deleteMessage()
{
}
}
Now when I'm trying to access a default or custom repository method I get this error:
Warning: Missing argument 1 for Doctrine\ORM\EntityRepository::__construct(),
called in F:\xampp\htdocs\mvc\app\Controllers\Messages.php
on line 15 and defined in F:\xampp\htdocs\mvc\vendor\doctrine\orm\lib\Doctrine\ORM\EntityRepository.php on line 64
line 64 in EntityRepository.php is a __construct function that declares entitymanager, but it seems to not be working properly:
public function __construct($em, Mapping\ClassMetadata $class)
{
$this->_entityName = $class->name;
$this->_em = $em;
$this->_class = $class;
}
Two things that i noticed:
Your path is relative. Im not sure but i always use complete path to the Entity folder. You can use __DIR__ to achieve that easily. Depending on your namespace it should look Like:
$paths = array(__DIR__ . "/../Repository");
Doctrine needs to know where to find your entities and repositories. Depending on your namespace i would think your Repository file exists in a folder named "Repository" and not "Entity".
Have you correctly defined an Entity Class? Your Repository class looks ok to me but it can only work if you have a valid Entity class.
You should not name your repository "Message". The Entity should be named "Message" and the repository should be named "MessageRepository".
I want to increase the functionality of my CodeIgniter project by integrating some code that is written in laravel? how do I approach,
Can I include the code via library in CodeIgniter ? If yes How?
I only want to include controllers and ORM into the CI.
Laravel code is a kind of api fetcher with function talks with other
3rd party services.
Yes you can use composer to install Laravel specific modules/projects, third-party projects in your CodeIginter. Just include autoload in your `index.php' file at top
// Composer autoload
require_once __DIR__.'/vendor/autoload.php';
I am using Eloquent as ORM in my CodeIgniter codebase.
Create a classmap to your app directory in composer.json
"autoload": {
"psr-4": { "YourApp\\": ["application/"] },
Use Eloquent
To use Eloquent, you will require to create a library to setup Eloquent for use.
/**
* Capsule setting manager for Illuminate/database
*/
use Illuminate\Database\Capsule\Manager as CapsuleManager;
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
class Capsule extends CapsuleManager {
public function __construct()
{
parent::__construct();
//Loaded by CI
if(function_exists('get_instance')) {
$ci = &get_instance();
$db = new stdClass;
$db = $ci->db;
} else {
require_once __DIR__.'/../config/database.php';
$db = (object) $db['default'];
}
$this->addConnection(array(
'driver' => $db->dbdriver,
'host' => $db->hostname,
'database' => $db->database,
'username' => $db->username,
'password' => $db->password,
'charset' => $db->char_set,
'collation' => $db->dbcollat,
'prefix' => $db->dbprefix,
));
$this->setEventDispatcher(new Dispatcher(new Container));
// Make this Capsule instance available globally via static methods... (optional)
$this->setAsGlobal();
// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$this->bootEloquent();
}
}
// END Capsule Class
Now load the auto load the library, and you have the eloquent beauty.
Similarly, you can use MonoLog for logging, Whoops for error display, Formers\Former for form building etc.
Use Whoops
You can place this code somewhere after autload and defining CI Environment in your index.php to use beautiful https://github.com/filp/whoops library
if (ENVIRONMENT == 'development') {
$whoops = new \Whoops\Run;
$whoops->pushHandler(new Whoops\Handler\PrettyPageHandler());
$whoops->register();
}
You can also extend CI_Router to use Laravel style routing in your Code Igniter app.
Blade Templating
You can extend the CI_Loader to use Blade templating in Code Igniter. Create a new file MY_Loader in your application/core directory with this code.
use Illuminate\Blade\Environment;
use Illuminate\Blade\Loader;
use Illuminate\Blade\View;
class MY_Loader extends CI_Loader {
public function __construct()
{
parent::__construct();
}
public function blade($view, array $parameters = array())
{
$CI =& get_instance();
$CI->config->load('blade', true);
return new View(
new Environment(Loader::make(
$CI->config->item('views_path', 'blade'),
$CI->config->item('cache_path', 'blade')
)),
$view, $parameters
);
}
}
You may have to create a config file blade.php in your application/config directory to store blade specific configurations.
//config/blade.php
$config['views_path'] = APPPATH . 'views/blade/';
$config['cache_path'] = APPPATH . 'cache/blade/';
Now you can do something like this in your controller
class Home extends CI_Controller {
public function index()
{
// Prepare some test data for our views
$array = explode('-', date('d-m-Y'));
list($d, $m, $y) = $array;
// Basic view with no data
echo $this->load->blade('home.index');
// Passing a single value
echo $this->load->blade('home.index')->with('day', $d);
// Multiple values with method chaining
echo $this->load->blade('home.index')
->with('day', $d)
->with('month', $m)
->with('year', $y);
// Passing an array
echo $this->load->blade('home.index', array(
'day' => $d,
'month' => $m,
'year' => $y
));
}
}
I am migrating a project from Zend framework 1.4 to 2.4, I have a class in "vendor/custom/classes/User.php"
<?php
namespace Classes;
use Zend\Db\TableGateway\TableGateway;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Db\Adapter\Adapter;
class User
{
public function getItemById($id)
{
//$config = $this->getServiceLocator()->get('config');
//This only work in controller
$configs = array();
$adapter = new Adapter($configs);
$projectTable = new TableGateway('project', $adapter);
$rowset = $projectTable->select(array('type' => 'PHP'));
echo 'Projects of type PHP: ';
foreach ($rowset as $projectRow) {
echo $projectRow['name'] . PHP_EOL;
}
}
}
?>
I need to load merged configurations in my files in "config/autoload" , global.php and local.php. $config = $this->getServiceLocator()->get('config'); Can someone guide me how can I get these configurations from a custom class. Basically I am trying to do is writing set of classes like User, Project, Customer outside of Models and use them commonly in all modules like CMS, Admin Panel, Web site. Appreciate your guidance.
An approach could be using a factory.
You create a class UserFactory implementing Zend\ServiceManager\FactoryInterface. This class will have a method createService with a $serviceLocator parameter. You use this service locator to retrieve your dependencies and pass them to your User class.
In your User class you need to use a controller that accepts as parameters the dependencies that you need to pass to it
Since there is no direct way to access those configurations. I have wrote constants with DB access information in the local and global php files in config/autoload and used it in my class.
class DBManager
{
protected $adapter ;
protected $connection ;
/**
* Constructor
*/
public function __construct()
{
$configs = array(
'hostname' => DB_SERVER_NAME,
'driver' => 'Pdo_Mysql',
'database' => DB_DATABASE_NAME,
'username' => DB_USER_NAME,
'password' => DB_PASSWORD ,
);
$this->adapter = new Adapter($configs);
}
}
I want to instantiate a class every time a page is loaded in CodeIgniter.
It looks like the /application/config/autoload.php is the place to do this. Is that correct?
I added this line to the package's autoload:
$autoload['packages'] = array('/application/third_party/Autoload.php');
Now I need this code to be executed on every page, where can I make this happen?
$bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
To auto load a package (according to CI), you should put the package path/name in following array, like
$autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
But it doesn't execute any code automatically but makes your package available to use without explicitly loading it.
To make some code execute every time, you can put that code in your base controller's constructor function. Also, you can put the code in your config.php file. If you have an extended base controller, like application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
//
}
Then you can use it's constructor function like
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
$this->bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
}
}
Rest of your controllers will use/extend MY_Controller instead of CI_Controller.
But you can also use a hook in this case (to register custom exception handlers), in application/config/hooks.php file, put following code
$hook['pre_controller'][] = array(
'class' => 'CustomExceptionHook',
'function' => 'SetExceptionHandlers',
'filename' => 'CustomExceptionHook.php',
'filepath' => 'hooks'
);
Create a class in application/hooks/CustomExceptionHook.php folder, like
class CustomExceptionHook
{
public function SetExceptionHandlers()
{
// add package path (if not auto-loaded)
$this->load->add_package_path(APPPATH.'third_party/package_folder/');
// load package (if not auto-loaded)
$this->load->library('Bugsnag_Client');
set_error_handler(array($this->Bugsnag_Client, "errorHandler"));
set_exception_handler(array($this->Bugsnag_Client, "exceptionHandler"));
}
}
Well let me explain it how you can do it.
As you have autoloaded the package its fine now you need to do this.
Create a MY_Controller in application/core/ directory.
Class MY_Controller Extends CI_Controller{
public $bugsnag = '';
public function __construct(){
parent::__construct();
$this->bugsnag = new Bugsnag_Client("YOUR-API-KEY-HERE");
set_error_handler(array($bugsnag, "errorHandler"));
set_exception_handler(array($bugsnag, "exceptionHandler"));
}
}
Note $this->bugsnag contains the object now. When you need to access it in any page you can simply do it like this by extending the parent class
Class Test Extends MY_Controller{
public function __construct(){
parent::__construct();
}
public function index(){
echo '<pre>';
print_R($this->bugsnag);
}
}
Here is a version of MY_Controller.php
This is using BugSnag via composer install
Using this method exposes the $this->_bugsnag variable to the entire CI System
class MY_Controller extends CI_Controller {
// Application Version
public $_app_version;
// Bugsnag
public $_bugsnag = NULL;
/**
* Constructor
*/
public function __construct() {
parent::__construct();
// Dont print errors to screen
ini_set('display_errors', 0);
// Load configs
$this->load->config('appversion');
$this->load->config('bugsnag');
$this->_app_version = $this->config->item('app_version');
// INIT: bugsnag
// https://docs.bugsnag.com/platforms/php/other/configuration-options/
$this->_bugsnag = Bugsnag\Client::make( $this->config->item('bugsnagAPIKey') );
$this->_bugsnag->setErrorReportingLevel( E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED );
$this->_bugsnag->setNotifyReleaseStages( ['developement', 'testing', 'production'] );
$this->_bugsnag->setReleaseStage( ENVIRONMENT );
$this->_bugsnag->setAppType( 'API Server' );
$this->_bugsnag->setAppVersion( $this->_app_version );
$this->_bugsnag->setHostname( $_SERVER['HTTP_HOST'] );
$this->_bugsnag->setProjectRoot( realpath(APPPATH) );
$this->_bugsnag->setFilters( ['password'] );
Bugsnag\Handler::register( $this->_bugsnag );
// Load Helpers
// Load Libraries
// Load Languages
}
}
You can now access the BugSnag methods like this.
$this->_bugsnag->leaveBreadcrumb( 'Hello' );
$this->_bugsnag->notifyException( $e );
Create a MY_Controller & inherit all your controllers off that. You can find more on this by Googling "MY_Controller"
EDIT: a few weeks after I posted this question Evan Coury wrote an excellent blog post on the topic of the ZF2 ServiceManager, which is where I found the best answers to my questions: http://blog.evan.pro/introduction-to-the-zend-framework-2-servicemanager
--
I'm working on a project using ZendFramework 2.0.0beta4 and am having trouble using the Zend\ServiceManager to handle dependencies. Here is the current ZF2 ServiceManager documentation
It lists 6 sub-keys to use when registering classes with the ServiceManager for use in our modules: abstract_factories, aliases, factories, invokables, services, and shared. If I just want to register a model class which I'm going to use in my controller to pull data from a database, which one is best? I'm specifically trying to adapt an example from the ZF2 Skeleton Application shown below to my own application (DashboardTable is a model), and this example uses the factories way.
public function getServiceConfiguration()
{
return array(
'factories' => array(
'album-table' => function($sm) {
$dbAdapter = $sm->get('db-adapter');
$table = new DashboardTable($dbAdapter);
return $table;
},
'test-model' => Dashboard\Model\TestModel(),
),
);
}
However, I don't know how 'db-adapter' is getting into the ServiceManager ($sm) in my separate working example from the SkeletonApplication - it has to do with an entry in the autoloaded global.php config file which has a 'db' entry containing the DB info. Because I don't know exactly how that's getting from the config file to ServiceManager, I created the simple entry below that to reduce the problem to its base components - "test-model". When I comment out the 'dashboard-table' entry and call a function from TestModel in my controller which simply outputs some text. Below is the ServiceManager config from my Module.php
<?php
namespace Dashboard\Model;
class TestModel {
public function testMethod()
{
$testResult = "Hello";
return $testResult;
}
}
Which is then passed from my controller to the view:
<?php
namespace Dashboard\Controller;
use Zend\Mvc\Controller\ActionController;
use Zend\View\Model\ViewModel;
use Dashboard\Model\AlbumTable;
use Dashboard\Model\TestModel;
use Dashboard\Model\Dashboard;
class DashboardController extends ActionController
{
public function indexAction()
{
return new ViewModel(array(
'users' => $this->getTestModel()->testMethod(),
));
}
public function getAlbumTable()
{
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('album-table');
}
return $this->albumTable;
}
public function getTestModel()
{
if (!$this->testModel) {
$sm = $this->getServiceLocator();
$this->testModel = $sm->get('test-model');
}
return $this->testModel;
}
}
This code gives me a completely blank page, no errors. When I comment out the ServiceManager config from Module.php and just render a new ViewModel without any passing any arguments in my DashboardController.php file the page renders normally - loading layout.phtml and index.phtml.
I believe I'm misunderstanding a fundamental piece of how to use the ServiceManager or possible ZF2 in general, and will greatly appreciate any insight anybody can give. This is also my first question on StackOverflow so I welcome any advice on formatting my question. Thanks.
There are two good options to get factories from service managers. One is the creation of factory classes, which happens most time in the Zend Framework code itself. The second one is using closures, as you are doing.
Make sure you do not type things like:
'test-model' => Dashboard\Model\TestModel(),
But a real closure like your first one is a good example. Secondly, the Service Manager always gives an exception when you try to get a service which fails to instantiate. Note this exception does not include the message why: the class might not be found or an exception is thrown during instantiation (for example because the service manager cannot instantiate a dependency of the service you are trying to get).
A last remark is you do not need to import FQCN (fully qualified class names) with use statements at the location you are trying to get. But you need to import the FQCNs when you are trying to instantiate.
So this works:
<?php
class MyClass
{
protected $sm;
public function setServiceManager($sm)
{
$this->sm = $sm;
}
public function doSomething()
{
$this->sm->get('some-special-key');
}
}
And this too:
<?php
use Foo\Bar\Baz;
$serviceConfig = array(
'factories' => array(
'some-special-key' => function($sm) {
return new Baz;
}
),
);
But this not (if you try to get a Foo\Bar\Baz):
<?php
$serviceConfig = array(
'factories' => array(
'some-special-key' => function($sm) {
return new Baz;
}
),
);
You might want to checkout my SlmCmfKernel repository. In my Module.php I include a service configuration file, which is put in a separate location. In another part of the code I get a service from the manager.
Just to clarify:
public function getServiceConfiguration()
{
return array(
'factories' => array(
'test-model' => function($sm){
return new Model\TestModel;
},
),
);
}
Can also be written as an invokable:
public function getServiceConfiguration()
{
return array(
'invokables' => array(
'test-model' => 'Model\TestModel',
),
);
}
In that case, you might want to consider having it defined in a config file instead of Module.php, as you'd be able to take advantage of config caching since it's simply an array of scalars.
I ended up finding the answer to my own question through more debugging (I previously hadn't had ini_set('display_errors', '1'); set - silly me).
The proper syntax to add a class to the ZF2 ServiceManager (within your Module.php) appears to be:
public function getServiceConfiguration()
{
return array(
'factories' => array(
'album-table' => function($sm) {
$dbAdapter = $sm->get('db-adapter');
$table = new AlbumTable($dbAdapter);
return $table;
},
'test-model' => function($sm){
return new Model\TestModel;
},
),
);
}
And just for completeness, in order to call a method from the class you're including you can use this in your controller file (DashboardController.php in my case) as long as you're extending the ActionController class:
class DashboardController extends ActionController
{
public function indexAction()
{
return new ViewModel(array(
'users' => $this->getTestModel()->testMethod(),
));
}
public function getTestModel()
{
if (!$this->testModel) {
$sm = $this->getServiceLocator();
$this->testModel = $sm->get('test-model');
}
return $this->testModel;
}
}
Where testMethod() is a method from within the TestModel class. Some notes from this for anybody new to Zend or namespaces - one of my issues was that I was using the full class name reference (Dashboard\Model\TestModel) when I had set the namespace at the top of the file to Dashboard, so the first Dashboard was unnecessary and caused PHP to look for Dashboard\Dashboard\Model\TestModel. Also, as of this writing sample ZF2 module are scarce - I recommend looking to samples like ZfcUser by EvanDotPro for examples on this type of thing.
My original confusion about the various sub-keys for adding classes to the ServiceManager still lingers though, so if you have any insight as to that I will continue to monitor this question and will mark your answer as "the" answer should you solve that bit, thank you :).