Silex custom class structure and loading - php

I'm building an app using Silex (the micro-framework).
As my app are growing in size and the need of using the same code in several routes rises, I want to organise everything a little more..
My idea is to create some custom classes, and then share them with my app:
$app['test'] = $app->share(function () {
require_once('../vendor/acme/src/test.php');
$testClass = new Test();
return new $testClass;
});
This actually works, but I need help with the following:
Autoload the class with composer (the way its supposed to be done in Silex).
Be able to use the existing Doctrine DBAL connection and methods within my class.
I hope someone can give me some tips how to get on, because I'm not finding the Silex docs very useful and I'm a beginner with both Silex and Composer.

Check the composer docs about autoloading, and when you added your config you should run composer dump-autoload to regenerate the composer autoloader. Then your require_once should not be necessary anymore.
Most likely this will work (assuming class Test is in src/Test.php):
{
"autoload": {
"psr-0": {
"": "src/"
}
}
}
This will make any PSR-0 compliant class inside src/ autoloadable.
Regarding your second point (using DBAL in your class), you should configure your class as a silex service that accesses the db service. Read up on services at http://silex.sensiolabs.org/doc/services.html

Related

Autoloading PHP file in composer package

I'm trying to create a composer package that also contains src/functions.php with some general functions. I have the following in composer.json to make it autoload:
"autoload": {
"files": ["src/functions.php"]
}
When I import this package into a project it will try to load src/functions.php in the current project (local) in stead of the imported package. Is there a way to ensure the correct file is loaded when imported (./vendor/bla/src/functions.php)?
Autoloading is not for loading everything. If src/functions.php contains class just ensure it's properly namespaced and I see no reason why autoloader would pick your local class instead of package's. If you are using the same namespace for the package and for code in your project then basically you should stop doing so.
If src/functions.php is just bunch of functions, then I strognly suggest refactoring the code and wrap them in properly namespaced class. You can make your functions static methods so basically not much would change from usage perspective.
EDIT
Once you finish refactoring, change your composer.json from what you shown in question to:
"autoload": {
"classmap": ["src/"]
}

Including my class in a Laravel 5 Project

I made a class in php with some helper methods that parse HTML files.
I'd like to use this class in my Laravel project, but I'm new to Laravel and it's not clear how to add a simple class to a Laravel 5 project.
Is this possible? Or do I need to go to all the trouble of creating a composer package for my class, hosting it somewhere, and then require it in my composer.json file. That seems like a lot of work for including a simple PHP class, and I'm hoping there's an easier way.
As it stands right now there's not a great/easy way to do this in Laravel 5 (possibly by design). The two approaches you can take are
Create a new class in the App namespace
By default Laravel 5.0 looks for App\ prefixed classes in the app/ folder, so something like this should work
#File: app/Helpers/Myclass.php
<?php
namespace App\Helpers;
class Myclass
{
}
and then create your class with
$object = new App\Helpers\Myclass;
This approach, however, relies on you creating classes in the App\ namespace, and there's some ambiguity around if the App\ namespace is owned by Laravel, or is owned by the developer of the application.
Create your own Namespace and Register as PSR-4 autoloader
A better, but more complicated, approach would be to create classes in your own namespace, and then tell Laravel about this namespace by registering a new PSR autoloader.
First, you'd create the class definition
#File: application-lib/Myclass.php
<?php
namespace Pulsestorm;
class Myclass
{
}
Notice we've created a new folder off the root folder to hold our classes named application-lib. You could name this folder anything you like, because in the next step, you're going to add a section to your composer.json file's autoloader section
#File: composer.json
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Pulsestorm\\": "application-lib/"
}
},
The section we've added is this
"Pulsestorm\\": "application-lib/"
The key to the object (Pulsestorm\) is your namespace. The value (application-lib) is the folder where composer should look for class definition files with the specified namespace.
Once you've added this to composer.json, you'll need to tell Composer to regenerate it's autoload cache files with the dumpautoload command
$ composer dumpautoload
Generating autoload files
After doing the above, you should be able to instantiate your class with
$object = new Pulsestorm\Myclass;
The "real" right way to do this would be to create a generic composer package for your helper class, and then require that composer package into your laravel project. That may, however, be more work than you care to take on for a simple library helper.
If your class is generic enough to use it in other projects, the best way is to release it as a package.
Here's how you create packages with Laravel 5: http://laravel.com/docs/5.0/packages

how to call modules' model and controllers files in a controller in laravel 4.1

I created a modular system by using laravel 4.1 I have a tree scheme as follows:
app/
app/controllers/
app/modules/
app/modules/modulename/
app/modules/modulename/controllers/
app/modules/modulename/controllers/modulecontroller.php
app/modules/modulename/models/
app/modules/modulename/models/modulemodel.php
What I want to do is to call the model from a controller in app/controllers/ class.
How I can call that module and its model?
Make sure your /app/modules is added to your composer.json file's autoload : classmap and issue composer dump-autoload or php artisan dump-autoload. Then you can just create an instance like new ModuleModel or whatever name you gave your class. Though it's better to pass to your controller by dependency injection. This way your code will be easier to test because you can pass in stub data.
public function __construct(ModuleModel $module_model_instance) {
$this->module_model_instance = $module_model_instance;
}
I'd rather add this as a comment but have insufficient rep.
If everything is correctly autoloaded by composer in the PSR-0 (or 4) section, then you should just be able to reference it using it's namespace?
I sometimes need to run
composer dump-autoload
to refresh the autoloaded files, especially if using vagrant.
Hope this is helpful. I'm not sure if I've fully understood your problem.

Initializing PHP classes in the Web server/browser context

I am writing a script that talks to a database, and transforms the content and puts it into an XML file.
I am trying to utilize best practices, and as part of library re-use, I have found the following classes to be beneficial:
Symfony components:
Yaml : for parsing and loading database info.,
DI Container : for injecting dependencies
Others:
PHPExcel, the amazing excel library
Doctrine DBAL to get an easy PDO wrapper
Mockery for obtaining easy mocks during testing
My core business class, ExcelExporter, will need all these files functioning harmoniously with each other. I also need a place where I can initialize by own class, and inject these dependencies in.
I am confused as to where to do this. If I were building a web page, I'd say I'd put the initialization & configuration process inside index.php and finally call ExcelExporter to do its thing when a user loads index.php in the browser. Is there a better way for this bootstrapping process? What's the most common approach?
You should totaly use Composer for this task.
It will handle vendors and autoloading for you.
Here is a quick setup:
curl -s https://getcomposer.org/installer | php
php composer.phar init
php composer.phar require symfony/dom-crawler:dev-master doctrine/dbal:2.4.x-dev
php composer.phar install
You will have a vendor directory with your dependencies. Then the bootstrap file is simply initializing what you have to do. Autoloading is handled by Composer:
// Then add this on top of your bootstrap file
require 'vendor/autoload.php';
I assume you are not using any framework. Only using symphony components. If you were using a framework it would have been done by the framework. But for vanila framework you need
A single entry point for the application (say index.php)
A bootstrap.php file that loads initial classes and external resources. Many framework uses this bootstrap files. Just look at the file structure you'll find them. The name might not be bootstrap.php.
Once your application is loaded use a autoloader to load on-demand classes. This autoloader should be initialized on bootstrap.
function my_autoloader($class) {
include 'classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');
Based on Damien's answer, I found that Composer offers the easiest method to do this.
Now, my ExportExcel class lives in the src/ directory. The structure of my directory is:
src/
vendor/
index.php
bootstrap.php
composer.json
Within composer.json, I also asked it to load my classes for me:
{
"name": "adityamenon/excel_export",
"description": "Export data into a custom excel sheet format",
"require": {
"symfony/dependency-injection": "2.2.x-dev",
"symfony/yaml": "2.1.x-dev",
"doctrine/dbal": "2.4.x-dev",
"mockery/mockery": "dev-master",
"CodePlex/PHPExcel": "1.7.8"
},
"autoload": {
"psr-0": {"ExportExcel": "src/"}
},
"authors": [
{
"name": "aditya menon",
"email": "adityamenon90#gmail.com"
}
]
}
I just need to run $ composer install for all the dependencies to appear magically within vendor/.
PSR-0 is easy to follow. I just made a file called ExportExcel.php with a namespaced class inside called ExportExcel:
namespace ExportExcel;
class ExportExcel {
public function __construct(\ExportExcel\DbConvenience $db_convenience)
{
$this->DbConvenience = $db_convenience;
}
public function writeExcelFile()
{
// ...do stuff here
}
}
Finally, here's bootstrap.php, which takes care of autoloading stuff I need as well as injecting dependencies:
<?php
// composer autoloads dependencies
// also configured to load from src/
$loader = require('vendor/autoload.php');
// load configuration (only db right now)
use Symfony\Component\Yaml\Yaml;
$yaml_config = Yaml::parse('config.yml');
// load the database
$db_config = new Doctrine\DBAL\Configuration();
$conn = Doctrine\DBAL\DriverManager::getConnection($yaml_config, $db_config);
// load the convenience classes
$DbConvenience = new ExportExcel\DbConvenience($conn);
// use the dependency injector to load the exporter with DB
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
$sc = new ContainerBuilder();
$sc->setParameter('dbconvenience.class', 'ExportExcel\DbConvenience');
$sc->setParameter('exportexcel.class', 'ExportExcel\ExportExcel');
$sc
->register('dbconvenience', '%dbconvenience.class%')
->addArgument($conn);
$sc
->register('exportexcel', '%exportexcel.class%')
->addArgument(new Reference('dbconvenience'));
// here's the most important class of 'em all
$ExportExcel = $sc->get('exportexcel');
Finally in index.php, the first line is require('bootstrap.php');, and off I go. I can make calls to functions inside ExportExcel with $ExportExcel->doStuff();
Please feel free to add comments and shorten/improve this answer. Solving this puzzle was a bit hard and took a bit of reading around but everything is so clear in hindsight.

Custom code management with the Composer auto loader?

I've started a new project, where I use Composer to handle some dependencies, as well as their auto-loading.
I only keep the composer.json file in the VCS, instead of the entire vendor directory, so I don't want to start adding my code in there.
How should I handle my own project specific code, so that it auto loads as well?
This is actually very simple. Excluding vendors directory from your repository is the right approach. Your code should be stored in a separate place (like src).
Use the autoload property to make that composer recognizes your namespace(s):
{
"autoload": {
"psr-4": {
"Acme\\": "src/"
}
}
}
Assuming you have class names following the psr-4 standard, it should work. Below some example of class names and their locations on the file system:
Acme\Command\HelloCommand -> src/Command/HelloCommand.php
Acme\Form\Type\EmployeeType -> src/Form/Type/EmployeeType.php
Remember to define a namespace for each class. Here's an example of Acme\Command\HelloCommand:
<?php
namespace Acme\Command;
class HelloCommand
{
}
Don't forget to include the autoloader in your PHP controllers:
<?php
require 'vendor/autoload.php';
Read more on PSR-4 standard on PHP Framework Interoperability Group.
Note that if you edit composer.json, you need to either run install, update or dump-autoload to refresh the autoloader class paths.

Categories