I currently have two applications that run on the same server, under separate virtualhosts. The first is a Laravel 4 app and the second is a older PHP project that doesn't use a framework, but follows a rough MVC pattern.
I'd like to find a way to interact with and use some of the models from the Laravel app inside of the older PHP project.
Obviously it's not going to be as simple as just including the model files, as they will have various dependencies, so are there any general approaches or patterns that I should be looking at when trying to do this?
You can add illuminate/database to your composer.json. That way you can use database module of laravel without installing whole framework.
Read the instructions in README.md for code examples and more details.
Can Vural is right, you can just use these components, take a look at http://www.slimframework.com/news/slim-and-laravel-eloquent-orm.
Here are the main extracts:
INSTALLATION
First, prepare the composer.json file so it will pull down and install the Slim Framework and the Eloquent ORM. The composer.json file should look like this:
{
"require": {
"slim/slim": "*",
"illuminate/database": "*"
}
}
When this is done, run composer install to install the application dependencies.
BOOTSTRAP THE ELOQUENT ORM
Next, I tell Composer to autoload the application’s dependencies by requiring Composer’s autoload.php file.
<?php
// Autoload our dependencies with Composer
require '../vendor/autoload.php';
And now I bootstrap the Eloquent ORM and pass it my database connection information (be sure you add your own username, password, and database name).
<?php
// Database information
$settings = array(
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => '',
'username' => '',
'password' => '',
'collation' => 'utf8_general_ci',
'prefix' => ''
);
// Bootstrap Eloquent ORM
$connFactory = new \Illuminate\Database\Connectors\ConnectionFactory();
$conn = $connFactory->make($settings);
$resolver = new \Illuminate\Database\ConnectionResolver();
$resolver->addConnection('default', $conn);
$resolver->setDefaultConnection('default');
\Illuminate\Database\Eloquent\Model::setConnectionResolver($resolver);
Now that the Eloquent ORM is bootstrapped, I can create and use models that extend the Eloquent abstract model. This example assumes your database contains a table named books with columns title and author.
<?php
class Book extends \Illuminate\Database\Eloquent\Model
{
}
Extract taken from the website mentioned above, this is so if it gets removed the information still remains.
To load from a different project, you will most likely have to autoload the models with a custom autoloader. Or include the autoloader from the Laravel framework if you have dependencies within the models.
Related
I am working with the skeleton-application as a base, using the Vagrant / Composer setup. After the initial install I realised I would need the LDAP module. I then ran composer require zendframework/zend-ldap which ran successfully and I have located the files in ~/vendor/zendframework/zend-ldap.
The issue is when I add 'Zend\Ldap' to my ~/config/modules.config.php I encounter the following error:
Fatal error: Uncaught Zend\ModuleManager\Exception\RuntimeException: Module (Zend\Ldap) could not be initialized. in /var/www/vendor/zendframework/zend-modulemanager/src/ModuleManager.php:203 Stack trace: #0 /var/www/vendor/zendframework/zend-modulemanager/src/ModuleManager.php(175): Zend\ModuleManager\ModuleManager->loadModuleByName(Object(Zend\ModuleManager\ModuleEvent))
#1 /var/www/vendor/zendframework/zend-modulemanager/src/ModuleManager.php(97): Zend\ModuleManager\ModuleManager->loadModule('Zend\\Ldap') #2 /var/www/vendor/zendframework/zend-eventmanager/src/EventManager.php(322): Zend\ModuleManager\ModuleManager->onLoadModules(Object(Zend\ModuleManager\ModuleEvent))
#3 /var/www/vendor/zendframework/zend-eventmanager/src/EventManager.php(171): Zend\EventManager\EventManager->triggerListeners(Object(Zend\ModuleManager\ModuleEvent))
#4 /var/www/vendor/zendframework/zend-modulemanager/src/ModuleManager.php(120): Zend\EventManager\EventManager->triggerEvent(Object(Zend\ModuleManager\ModuleEvent))
#5 /var/www/vendor/zendfr in /var/www/vendor/zendframework/zend-modulemanager/src/ModuleManager.php on line 203
The ~/config/modules.config.php file:
/**
* List of enabled modules for this application.
*
* This should be an array of module namespaces used in the application.
*/
return [
'Zend\Session',
'Zend\Mvc\Plugin\Prg',
'Zend\Mvc\Plugin\Identity',
'Zend\Mvc\Plugin\FlashMessenger',
'Zend\Mvc\Plugin\FilePrg',
'Zend\Log',
'Zend\Form',
'Zend\Db',
'Zend\Router',
'Zend\Validator',
'Zend\Ldap', // All is well if this is commented out
'Application',
];
and the ~/config/application.config.php file:
/**
* If you need an environment-specific system or application configuration,
* there is an example in the documentation
* #see https://docs.zendframework.com/tutorials/advanced-config/#environment-specific-system-configuration
* #see https://docs.zendframework.com/tutorials/advanced-config/#environment-specific-application-configuration
*/
return [
// Retrieve list of modules used in this application.
'modules' => require __DIR__ . '/modules.config.php',
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => [
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => [
'./module',
'./vendor',
],
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively override configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => [
realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php',
],
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
'config_cache_enabled' => true,
// The key used to create the configuration cache file name.
'config_cache_key' => 'application.config.cache',
// Whether or not to enable a module class map cache.
// If enabled, creates a module class map cache which will be used
// by in future requests, to reduce the autoloading process.
'module_map_cache_enabled' => true,
// The key used to create the class map cache file name.
'module_map_cache_key' => 'application.module.cache',
// The path in which to cache merged configuration.
'cache_dir' => 'data/cache/',
// Whether or not to enable modules dependency checking.
// Enabled by default, prevents usage of modules that depend on other modules
// that weren't loaded.
// 'check_dependencies' => true,
],
// Used to create an own service manager. May contain one or more child arrays.
// 'service_listener_options' => [
// [
// 'service_manager' => $stringServiceManagerName,
// 'config_key' => $stringConfigKey,
// 'interface' => $stringOptionalInterface,
// 'method' => $stringRequiredMethodName,
// ],
// ],
// Initial configuration with which to seed the ServiceManager.
// Should be compatible with Zend\ServiceManager\Config.
// 'service_manager' => [],
];
I have tried removing cache folder, running composer update, restarting Vagrant, adding the full path to the 'modules_path' array in application.config.php but it is always the same error. Interestingly I run into the same issue with 'Zend\View' that was included from the install, but a module such as 'Zend\Session' can be added to the modules.config.php file with no issues (They are all located in the vendor/zendframework directory)
Can anyone point me in the right direction to resolve this issue?
Zend\Ldap is one of the ZF components. As it does not have a Module.php in its /src directory which is mandatory for a module. So you do not need to initialize like other modules through modules.config.php to use it in your application.
This component is not included as required with default installation of ZF. So if you want to use any component, you must add them to autoloader. Once you added a component like this one composer require zendframework/zend-ldap in your project, you would then be able to use it.
Check this answer and this issue to be clear!
zend-ldap doesn't have a src/Module.php file, so you can't add it as a module. Also it doesn't seem to include a standard factory so you need to write one yourself. More info on how to set it up:
https://zendframework.github.io/zend-ldap/intro/
As others have noted, zend-ldap does not provide a Module class; it is simply a component that provides functionality. It has no service definitions, which is why there is no Module class.
Two things to note:
Install zendframework/zend-component-installer in your application: composer require --dev zendframework/zend-component-installer. When you do, any time you add another component to your application that exposes a Module class, it will prompt you, asking if you want to add it to your application configuration. (zend-component-installer is installed by default if you start your project with the zendframework/skeleton-application.)
We have recently opened our Zend Framework forums; consider directing your ZF questions there in the future, to make the answers easily discoverable for ZF users.
Is zend-ldap included in your project? If not Run in your terminal
composer require zendframework/zend-ldap
And you can disable caching in development process by enabling development mode: composer development-enable
I'm trying to integrate the Omnipay Paypal package with my Laravel 4.1 application. I've installed the laravel-omnipay package, as suggested by Omnipay, and followed the instructions on how to set it up.
I've added the laravel-omnipay package to both the providers array and the aliases array in the app.php file of Laravel. The config file has also been created.
My composer.json has the following requirements:
"ignited/laravel-omnipay": "1.*",
"omnipay/paypal": "~2.0"
and the config file of ignited/laravel-omnipay looks like this:
<?php
return array(
// The default gateway to use
'default' => 'paypal',
// Add in each gateway here
'gateways' => array(
'paypal' => array(
'driver' => 'Paypal_Express',
'options' => array(
'solutionType' => '',
'landingPage' => '',
'headerImageUrl' => ''
)
)
)
);
But when I call $gateway = Omnipay::gateway('paypal'); I'm getting the error
Class '\Omnipay\Paypal\ExpressGateway' not found"
Is there something I'm forgetting? :I
I'm not familiar with ignited/laravel-omnipay specifically, so this may or may not be the problem, but you might try fixing the capitalisation on this line:
'driver' => 'PayPal_Express',
(note that PayPal has two capital P's).
Generally class names are not case sensitive in PHP, but if you are using a case-sensitive filesystem, then the composer autoloader will not be able to find the right class.
Try composer dumpautoload to load new classes.
UPDATE:
Think in a term of service that is provided to your application by that new package. Find where is that service linked to application. It is usually done through ServiceProviders class. If there is no bug, it should be easy, following simple business rule to see how is provider related to main app.
So, you have one entity (provider) that should communicate with another.
That communication is done through simple rules. This is the best way to learn Laravel. It helps to think in a term of business rules, rather then to stare at code which is often very abstract.
When creating a composer package that is meant to be run in the Laravel 4 framework, I want to create a default database connection set that looks something like this:
// File Location: LARAVEL4_ROOT/vendor/my/package/src/config/database.php
return array(
'connections' => array(
'reporting' => array(
'driver' => 'mysql',
'host' => getenv('REPORTING_HOST'),
'database' => getenv('REPORTING_DBNAME'),
'username' => getenv('REPORTING_USER'),
'password' => getenv('REPORTING_PASS'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
);
According to all the documentation I can find online, once I have registered my project using the Service Provider pattern and call $this->package('my/package'); Laravel 4 is supposed to magically load this file and give me access to it in the configuration.
And I have verified that I can call
Config::get('package::database.connections.reporting')
and it returns the array above.
However, when I construct my Eloquent Model file, and try to set the connection using
protected $connection = 'package::database.connections.reporting';
It doesn't work. I get an exception saying:
InvalidArgumentException: Database [package::database.connections.reporting] not configured.
Is there some magic string format I need to use to get the Connection Resolver to connect to my database using the default config in my package?
Thanks for your help!
Okay, I found a solution:
It appears that the connection handling in Laravel 4 as of this writing is not consistent with the the syntax that the Config facade uses. Therefore using:
protected $connection = 'package::database.connections.reporting';
... will not work because the DatabaseManager class ONLY searches the configuration loaded from laravelroot/app/config/database.php
So, at the time of this writing, the only way to establish a connection defined in my package configuration is to modify the previously loaded configuration array in my package service provider, like so:
public function boot()
{
$this->package('vendor/package');
include __DIR__."/routes.php";
// Add my database configurations to the default set of configurations
$this->app['config']['database.connections'] = array_merge(
$this->app['config']['database.connections']
,Config::get('reporting::database.connections')
);
}
This could easily be handled by the framework by modifying the DatabaseManager class to look at the provided connection name and resolve the configuration details in the same way as the Config facade does. But that is not implemented at the time of this writing.
I have forked the framework and submitted a pull request with a potential fix. We'll see how that goes. For now, you can use the above work around in your package service provider, and then just set the name of your connection in your model like this:
protected $connection = 'reporting';
Since the array of connections defined in my package config have been merged with the default connections defined in laravelroot/app/config/database.php, it's as if the connection was actually created there in the app config, so there is no need for package resolution in the connection name inside your model.
Hopefully, this will be automated in future releases of laravel 4, or a more intuitive way of loading package database config files in the package service provider will be implemented.
Is it possible to include a package that was not specifically designed for L4 in the framework?
If so, how is it done? I know I need to add the package to my composer.json which adds it to the vendor folder, but can I register it somehow in the providers array? are there any other steps necessary?
I would like to use the Google checkout package originally designed for Yii
Using third party composer packages with Laravel 4
When developers create composer packages, they should map the auto-loading using PSR-0 or PSR-4 standards. If this is not the case there can be issues loading the package in your Laravel application. The PSR-0 standard is:
{
"autoload": {
"psr-0": { "Acme": "src/" }
}
}
And the PSR-4 standard:
{
"autoload": {
"psr-4": { "Acme\\": "src/" }
}
}
Basically the above is a standard for telling composer where to look for name-spaced files. If you are not using your own namespaces you dont have to configure anything else.
SCENARIO 1
PSR-0 standard following packages (with autoload classmap) in Laravel
This is a simple one, and for example i will use the facebook php sdk, that can be found:
https://packagist.org/packages/facebook/php-sdk
Step 1:
Include the package in your composer.json file.
"require": {
"laravel/framework": "4.0.*",
"facebook/php-sdk": "dev-master"
}
Step 2:
run: composer update
Step 3:
Because the facebook package uses a class map its working out of the box, you can start using the package instantly. (The code example below comes straight from a normal view. Please keep your logic out from views in your production app.)
$facebook = new Facebook(array(
'appId' => 'secret',
'secret' => 'secret'
));
var_dump($facebook); // It works!
SCENARIO 2
For this example i will use a wrapper from the instagram php api. Here there need to be made some tweaks to get the package loaded. Lets give it a try!
The package can be found here:
https://packagist.org/packages/fishmarket/instaphp
Step 1:
Add to composer .json
"require": {
"laravel/framework": "4.0.*",
"fishmarket/instaphp": "dev-master"
}
Then you can update normally (composer update)
Next try to use the package like you did with the facebook package. Again, this is just code in a view.
$instagramconfig = array(
'client_id' => 'secret',
'client_secret'=> 'secret',
'access_token' => 'secret'
);
$api = Instaphp::Instance(null, $instagramconfig);
var_dump($api); // Epic fail!
If you try the above example you will get this error:
FatalErrorException: Error: Class 'Instaphp' not found in ...
So we need to fix this issue. To do this we can examine the instagram composer.json, that has its autoload diffrent than the facebook php sdk had.
"autoload": {
"psr-0": { "Instaphp": "." }
}
Compared to the facebook composer.json:
"autoload": {
"classmap": ["src"]
}
(Composer handles different kinds of autoloading, from files and class-maps to PSR. Take a look at your vendor/composer/ folder to see how its done.)
Now we will have to load the class, manually. Its easy, just add this (top of your controller, model or view):
use Instaphp\Instaphp;
composer dump-autoload, and it works!
step2 (optional)
Another method is (if you dont want to use the "use" statement, you can simply tell composer to look for the files straight from your code. Just change the Instance like so:
// reference the name-spaced class straight in the code
$api = Instaphp\Instaphp::Instance(null, $instagramconfig);
var_dump($api); // It works
However I suggest using the usestatement to make it clear to other developers (and your future self) what (external) classes/packages are used in the program.
SCENARIO 3
Here we use the Laravels built in IOC container to register service providers. Please note that some packages might not be suitable for this method. I will use the same Instagram package as in scenario 2.
Quick and dirty
If you don't care about design patterns and service providers you can bind a class like this:
App::bind('Instaphp', function($app)
{
return new Instaphp\Instaphp;
});
And you resolve it like this.
App::make('Instaphp');
Quick and dirty end
If you're working on a bigger project, and you make use of interfaces you should probably abstract the bindings further.
Step 1:
Create a folder inside your app folder, for example a 'providers' folder.
app/providers
Make sure Laravel auto-loads that folder, you can pass in some additional info to composer.json, like this:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/providers" // this was added
]
},
Now create a File inside the new folder called Instagram.php and place this inside:
<?php
use Illuminate\Support\ServiceProvider;
class InstagramServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('Instaphp', function()
{
return new Instaphp\Instaphp;
});
}
}
Now run composer dump-autoload again, and you can use the package. Note that the instagram package has a final private function __construct(), this means you cannot use that package outside the original class without changing the construct method to public. I'm not saying this is a good practice, and i suggest to use the scenario 2, in the case of the instagram package.
Anyway, after this you can use the package like this:
$instagramInstance = App::make('Instaphp');
$instagramconfig = array(
'client_id' => 'secret',
'client_secret'=> 'secret',
'access_token' => 'secret'
);
$instagram = new $instagramInstance();
$userfeed = $instagram->Users->feed($instagramconfig);
var_dump($userfeed); // It works!
Add "tvr/googlecheckout": "dev-master" this to your composer.json.
Run composer install, then you can use the IoC container. Some code examples can be found in the official docs for Laravel 4: http://four.laravel.com/docs/ioc#basic-usage
I have gotten the latest CakePHP (2.1.0) and MongoDB Datasource Plugin both from git, and have followed the configuration settings as best as I can. I have placed the MonogoDB plugin in the plugins directory, and updated both my database.php and bootstrap.php files:
bootstrap.php:
CakePlugin::load('Mongodb');
database.php:
class DATABASE_CONFIG {
public $default = array(
'datasource' => 'Mongodb.MongodbSource',
'database' => 'database',
'host' => 'staff.mongohq.com',
'port' => 10070,
'login' => 'user',
'password' => 'secret'
);
}
I'm afraid I'm missing something stupid, but I keep getting the error:
Datasource class MongodbSource could not be found.
Which to me, implies it can find the plugin, but not the datasource class. Anyone seen this before? I've also tried to connect to a locally installed MongoDB, but same error persists.
Use this command to pull the plugin so it pulls the cake2.0 branch instead (which uses the correct cake 2.x directory naming conventions):
git clone -b cake2.0 git://github.com/ichikaway/cakephp-mongodb.git Mongodb
Please make sure that you are using the CakePHP-Mongo plugin for CakePHP 2.0 and not CakePHP 1.3