Laravel 4 DB:raw() is unavailable when running outside of framework - php

I'm using the [illuminate/database component][1] from Laravel 4 through composer - and while it generally works well, the DB facade seems to be broken in this standalone version. This meant I was unable to use static functions such as DB::raw(). It seems like the DB facade is even included in the package, but it doesn't work with ::raw().
I'm trying to do something like this -
...->orderBy(DB::raw('RAND()'))

Capsule::raw() is available, and is linked to the default connection's raw().
Also, what I did is I created a class:
/**
* #method static raw($value)
* #method static array select($query, $bindings = [], $useReadPdo = true)
* ...etc.
*/
class DB extends Manager
{
}
so that
You can use DB::raw().
IDE code completion works.

I found a partial solution, but if anyone has any ideas that work better, I'm eager to hear them (it seems the original Capsule package actually had support built in, maybe it was lost when it was merged, or maybe I'm using it incorrectly?)
use Illuminate\Database\Capsule\Manager as Capsule;
$connection = Capsule::connection();
// You can now use $connection->raw() in place of DB::raw()
...->orderBy($connection->raw('RAND()'))

Related

How to use symfony, twig, and doctrine in a controller inside an existing project

I have been using the SymfonyCast on Symfony 4 to try and help me to connect the pieces. I have learned a lot about doctrine Symfony and twig and the environment that they are supposed to work together in. However, that is not what I have to build on. I need to build inside an existing project OpenEMR.
I posted my project code here:
https://github.com/juggernautsei/symfony_twig_doctrine_component/blob/master/library/financialreports/src/FinancialSummaryByInsuranceController.php
The controller works to load the twig template. Now, I am trying to populate the controller with data from the database. I have built the entity class and the repository class. I just can't figure out what to put in this line.
public function getpaidata($insurerid)
{
$payments = $this->repository
}
To access the class in the repository. The IDE suggested the code in the repository class.
public function getInsurerPaid(ArSession $insurerId)
{
/*$insurerPaid = $this->_em->getRepository($this->_entityName)->findBy([
"payer_id" => $insurerId
]);*/
$insurerPaid = $this->findBy([
'payer_id' => $insurerId
]);
return $insurerPaid;
}
But as I am typing in out the code in the controller, the IDE PHPStorm is not suggesting anything. So, I am stuck. I have tried the suggested code here
https://symfony.com/doc/2.0/book/doctrine.html#creating-an-entity-class
https://symfonycasts.com/screencast/symfony-doctrine/repository
but nothing tells me how to access the method that is in the repository class.
UPDATE:
The getpaiddata() method is now changed to
/**
* #return Fully hydrated object.
*/
public function getpaidata($insurerid)
{
$row = $this->repository->findBy([
"payer_id" => $insurerid
]);
return $row;
}
The problem is likely how you get $this->repository. If you fetch it via the entity manager, via $this->_em->getRepository($entityName) like in the commented snippet, the return value has a type hint which tells the IDE that it is just a generic EntityRepository instead of your custom repository class.
You can install the Symfony-plugin to PhpStorm, which will give you better autocompletion if your entity has the right annotation #Entity(repositoryClass="...").
In a typical Symfony 4 application you could also just inject the correct repository, instead of the EntityManager, e.g. in your constructor:
public function __construct(PaidDataRepository $repository)
{
$this->repository = $repository;
}
From what it looks like, OpenEMR has it's own way of creating the EntityManager using Connector::instance(). So this will probably not work for you easily, unfortunately.
Another way around this would be to just place a type hint above assigning your variable:
/** #var App\Repository\PaidDataRepository $repository */
$repository = $this->_em->getRepository(PaidData::class)
or, since you have a class variable you can put a similar annotation on there.

How to optimise the Symfony4 Doctrine Repository usage inside the controller

I'm looking for a optimised usage of the Doctrine Repositories inside the Symfony 4 Controllers.
At the moment i've to build the code like this:
/** #var ArticleRepository $repository */
$repository = $this->getRepository(Article::class);
$articles = $repository->findBySearchterm($search_term);
To tell truth, i don't like this approach. If i have to use $this->getRepository(Article::class), i've to tell PHPStorm through extra annotation, that the return of that method is of type ArticleController. Otherwise PHPStorm warns me, that the called method ->findBySearchterm($search_term); is unknown.
I would like to optimise this and use the ArticleRepository directly, maybe like this: ArticleRepository::findBySearchterm($search_term);
Is there a chance to build something, to access the Repository directly without the overhead of fetching the repository? In my opinion it would also increase the readability of the code.
You can inject the repository directly into the controller method like so:
public function index(ArticleRepository $repository)
{
$articles = $repository->findBySearchterm($search_term);
// The rest of the code
}
This is done by symfony autowiring

Codeception DataFactory interaction between helper and other factories

I'm looking into using DataFactory's in Codeception for seeding of data, and for use in our acceptance tests. In the documentation there's mention of 2 approaches, one using the helper file and one using factories files.
We load both options using this snippet from our acceptance.suite.yml
class_name: AcceptanceTester
modules:
enabled:
- Db
- WebDriver
- \Helper\Acceptance
- Doctrine2:
connection_callback: getEntityManager
- DataFactory:
factories: tests/_support/factories
depends: Doctrine2
- \Helper\Factory
Both of the options seem to load correctly. As per the documentation I can then define factories like this, which will allow interaction with Doctrine.
// tests/_support/Helper/Factory.php
class Factory extends Module
{
/**
* #param array $settings
* #throws \League\FactoryMuffin\Exceptions\DefinitionAlreadyDefinedException
* #throws \Codeception\Exception\ModuleException
*/
public function _beforeSuite($settings = [])
{
/** #var Module\DataFactory $factory */
$factory = $this->getModule('DataFactory');
/** #var EntityManager $em */
$em = $this->getModule('Doctrine2')->_getEntityManager();
$factory->_define(User::class,[
// generate random user name
'name' => Faker::name(),
]);
parent::_beforeSuite($settings);
}
}
As per the other option, I can also create factories by loading all files from within tests/_support/factories, such as below:
// tests/_support/factories/seed.php
use League\FactoryMuffin\Faker\Faker;
/** #var \League\FactoryMuffin\FactoryMuffin $fm */
$user = $fm->create(User::class);
dd($user);
However, the seed.php version cannot seem to share the Factory, and errors with:
The model definition 'User' is undefined.
I wondered if maybe this could be solved by moving the Factory.php logic into the initialize() method but this seems to be called before FactoryMuffin has been initiliazed.
The documentation for this with codeception seems a bit sparse, and the FactoryMuffin docs, while better, don't cover Codeception integration. Just trying to work out if i'm missing something, or I just need to repeat the code in each place if I want to use both files/methods.
This is an old question and technology moves fast so the documentation has likely changed since this was originally asked but I'll make an attempt in case anyone else stumbles across it like I did.
You're using the DataFactory module which is great as it comes with the integration for Codeception out of the box. The two methods you've described are actually ways of integrating DataFactory with your data. By creating factory files, you've given DataFactory a means of generating data. But what if you have some data already in the database that you'd like to use in your tests as well? That's where you would use the Helper class. According to the DataFactory Module docs:
In cases you want to use data from database inside your factory definitions you can define them in Helper. For instance, if you use Doctrine, this allows you to access EntityManager inside a definition.
As for your issue of seed.php not finding the User model, you need to specify it according to the definition given in your factory. For example, if your factory file looks similar to this
<?php
use League\FactoryMuffin\Faker\Facade as Faker;
$fm->define('app\models\User')->setDefinitions([
'name' => Faker::name(),
... // the rest of your properties here
]);
Then seed.php would look like
// tests/_support/factories/seed.php
use League\FactoryMuffin\Faker\Faker;
$user = $fm->create('app\models\User');
Once you have the DataFactory module installed and configured, you can simply call it within the appropriate testing suite via have, haveMultiple, or make. See the Codeception Docs

PHPStorm and Slim 3.X DIC

I recently moved from Slim 2.X to Slim 3.X and I've found a problem that may be a little stupid but annoys me in some ways.
The newly Slim 3.X, as a difference between the older 2.X version, it implements a new container system using Dependency Injection Containers (DIC) build on Pimple.
As I've been reading, I find this a very great enhancement because it lets you manage your PHP app in a lot of different ways.
When I started playing around with the new things it has, I found something confusing that maybe is something I'm missing.
I use PHPStorm; one of the things that I like about this IDE is its code-completion and the facility for writing code and understanding classes (I'm actually a student, so this helps me a lot).
When I write a Slim route, if I want to access, for example, to my view object stored inside the container, I have to refer to it with the $this->view variable. The thing is that, normally, PHPStorm lists me the methods and properties inside an object when I mention it, but that didn't happen with the $this object.
I suppose that, inside a route, Slim stores all route functionalities and all the container objects into the $this assigner.
$container = $app->getContainer();
$container['view'] = new \Slim\Views\PhpRenderer('protected/views/');
$app->get('/products', function(Request $request, Response $response) {
$response = $this->view->render($response, 'products.php');
return $response;
})->setName('products');
When I access my /products route, it successfully renders my products template and shows what it's expected to show, so no problems with that.
The matter with it is that I want PHPStorm to know that $this variable inside a route it stores all the containers that are set previously before the route is called.
I thought about /* #var */ and /* #global */ or something like this but after searching for a while and trying different things, I haven't found anything that could work.
In conclusion, what I'm trying to say is if it's possible that PHPStorm could list me the properties and methods of the container objects like this:
but with the $this object inside a route:
Thanks!
The easiest way to do this is to have separate Action classes rather than use closures. This also has the benefit of being easier to test.
Firstly create your action, inject its dependencies into its constructor and write an `__invoke`` method that will be called by Slim:
class ProductsListAction {
protected $view;
public function __construct(\Slim\Views\PhpRenderer $view) {
$this->view = $view;
}
public function __invoke($request, $response, $args) {
$response = $this->view->render($response, 'products.php');
return $response;
}
}
For this to work, you now need a DIC factory for it:
$container['ProductsListAction'] = function ($c) {
return new ProductsListAction($c['view']);
};
You can now register your new action as a route callable:
$app->get('/products', 'ProductListAction');
Now, PhpStorm will correctly autocomplete within your ProductsListAction class.
I was trying to find something like this for Eclipse, and someone suggested you modify the properties with PHPDOCS of Slim\App. Since I didn't want to change the Slim files themself, I tried to make an empty class that extends Slim\App, and use PHPDOCS to add propeties to that:
/**
* OurApp
*
* Extends Slim\App with properties so we have code completion for a bunch of stuff!
*
* #property-read SomeClass $something
* #property-read SomeotherClass $someOtherThing
* #property-read string $someString
* #property-read \Slim\Views\PhpRenderer $renderer
*/
class OurApp extends \Slim\App {}
$app = new OurApp($settings);
And that works nicely. This way you can start typing $app-> and get the completion for whatever is in the standard Slim\App and get something, someOtherThing and someString, etc. For our project we changed to a bunch of values in the $container
items Dependency.php that we needed to access.

Override Singleton in Laravel Container

I'm wondering if there's a simple way to override a singleton service set in the core of the Laravel framework?
e.g. I'm trying to rewrite the app:name command service '' with the following provider:
use Hexavel\Console\AppNameCommand;
use Illuminate\Console\Events\ArtisanStarting;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
class NameCommandProvider extends ServiceProvider
{
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(Dispatcher $events)
{
$events->listen(ArtisanStarting::class, function ($event) {
$event->artisan->resolve('command.app.name');
}, -1);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->singleton('command.app.name', function ($app) {
return new AppNameCommand($app['composer'], $app['files']);
});
}
}
I'm 100% everything is working due to extensive checks put no matter what order I put my service provider (above or below ConsoleSupportServiceProvider) it still loads the original AppNameCommand over my custom one.
I've already got a work around BUT it would be nice to know about the behaviour of singleton services for the future if this is at all possible? (This is using Laravel 5.2 if that makes any difference.)
There's actually a cleaner way to do this. You basically want to extend a core binding, which can be achieved by using the extend method:
$this->app->extend('command.app.name', function ($command, $app) {
return new AppNameCommand($app['composer'], $app['files']);
});
Jason Lewis has a really nice article regarding Laravel's IoC on Tutsplus. Make sure to check it out ;)
I looked at this case and it seems it not the easy one. If you use singleton in your custom Provider it will be finally overridden by default provider (deferred one) so it seems it won't be the way.
After checking that simple approach doesn't work, what you need to do in such case is analysing what is happening when Laravel registers this command.
So in your case you search first for command.app.name - you see it's in Illuminate\Foundation\Providers\ArtisanServiceProvider and there is method registerAppNameCommand you would like to probably override.
So now you look for occurences of ArtisanServiceProvider to see where it's launched - you see it's in Illuminate\Foundation\Providers\ConsoleSupportServiceProvider in $providers property (which you would like probably to change).
So finally you should look for occurrences of ConsoleSupportServiceProvider and you see it's in config/app.php.
So what you need to do in this case:
Change in config/app.php - change Illuminate\Foundation\Providers\ConsoleSupportServiceProvider into your custom one ConsoleSupportServiceProvider
In your custom one you should extend from \Illuminate\Foundation\Providers\ConsoleSupportServiceProvider but change in $providers from Illuminate\Foundation\Providers\ArtisanServiceProvider into your custom ArtisanServiceProvider
finally create custom ArtisanServiceProvider which will extend from \Illuminate\Foundation\Providers\ArtisanServiceProvider where you override registerAppNameCommand using custom class in singleton
Using this way you will achieve your goal (I've verified it that custom class will be used running command php artisan app:name).
Alternatively you might want in your custom ArtisanServiceProvider remove 'AppName' => 'command.app.name', from $devCommands and use your custom service provider as you showed where you register your singleton but I haven't tried this approach.

Categories