In Laravel I need to communicate to a 3rd party API. Thay have given me some PHP implementation (class) which I can use to connect and communicate with their API.
But when I try this as a class in a subfolder of the App folder and add this to my controller, I get a class not found error.
I have added a folder 'Qenner' (the provider of the API) in the App folder. And copied their classes in there.
In my controller I'm using these classes and add a code sample, like they send it to me.
Controller code (API-KEY is replaced with the actual key):
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Qenner\Search;
use QennerSearch\ServiceClient;
class TestController extends Controller
{
public function index() {
$search = new Search('https://search.qenner.com', 'API-KEY', true, 'nl-NL');
$response = $search->getCriteria([], ['Country'], []);
if (!$response->isError()) {
$criterionSets = $response->getCriterionSets();
$countryCriterionSet = criterionSets[0];
$countries = $countryCriterionSet->getCriteria();
$resultCount = $response->getResultCount();
}
dd($response);
}
Search.php in Qenner folder:
/**
* #file
* Contains QennerSearch\Search.
*/
namespace QennerSearch;
use QennerSearch\model\messages\CriterionTypesResponse;
use QennerSearch\model\messages\CriteriaRequest;
use QennerSearch\model\messages\CriteriaResponse;
use QennerSearch\model\messages\ErrorResponse;
use QennerSearch\model\messages\SearchRequest;
use QennerSearch\model\messages\SearchResponse;
use QennerSearch\model\messages\PriceRequest;
use QennerSearch\model\messages\PriceResponse;
use QennerSearch\model\messages\AccommodationInfoRequest;
use QennerSearch\model\messages\AccommodationInfoResponse;
use QennerSearch\model\messages\AutoCompleteRequest;
use QennerSearch\model\messages\AutoCompleteResponse;
/**
* Class Search, using ServiceClient to communicate, implementing the SearchInterface
*
* #package QennerSearch
*/
class Search extends ServiceClient implements SearchInterface {
.....
The folder has a ServiceClient.php
ServiceClient.php
/**
* #file
* Contains QennerSearch\Search.
*/
namespace QennerSearch;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
/**
* Class Search.
*
* #package QennerSearch
*/
class ServiceClient {
protected $http_client = null;
protected $engine_url = null;
protected $api_key = null;
protected $log_calls = false;
protected $locale = null;
protected $last_result_code = 0;
protected $last_error_body = null;
public function __construct($engine_url, $api_key, $log_calls = false, $locale = "nl-NL") {
$this->http_client = new Client();
$this->engine_url = $engine_url;
$this->api_key = $api_key;
$this->log_calls = $log_calls;
$this->locale = $locale;
I get this error:
Class 'QennerSearch\ServiceClient' not found
While I expected a dump of the output
Updated
After seeing your folder structure in the comments, I believe ServiceClient.php and Search.php, both are inside the folder: app\Qenner, hence inside those files:
wherever you are using: namespace QennerSearch;
you should use: namespace App\Qenner;
and then inside your controller, instead of using: use QennerSearch\ServiceClient;
use: namespace App\Qenner\ServiceClient
Namespaces are not like aliases, they need to reflect the position of the file itself if that makes sense.
Please give it a try and let me know if it works.
Related
I have controller name as 'CashFlowdata'. In controller I am having code that is :
namespace App\Modules\CashFlowdata\Controllers;
use App\Http\Controllers\Controller;
use App\Modules\CashFlowdata\Models\CashModel;
use App\Modules\CashFlowdata\Lcurd\CashFlowdataLcurd;
use Auth, Womp, Graphs, Projects, Input , Permissions, LcrudForm, LcrudTable, Redirect, Session, Meta;
class CashFlowdataController extends Controller
{
private $lcrud;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth');
$this->lcrud = new CashFlowdataLcurd();
}
}
But in that I am getting error for
Class 'App\Modules\CashFlowdata\Lcurd\CashFlowdataLcurd' not found
But the file is there and that is with the same name.
If class and file have the same name (case sensitive), maybe you need a
composer dump-autoload
PS: Check 'lcurd' vs 'lcrud'
I'm developing an application where my data comes from external server in JSON format.
I would like to set a relationships between each models, but without using a database table.
Is it possible ?
Something like that:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'https://.../server/flights.json';
}
You could make a service class which handles the request and returns class instances:
namespace App\Services;
class FlightService
{
/**
* #var FlightFactory
*/
private $flightFactory;
public function __construct(FlightFactory $flightFactory)
{
$this->flightFactory = $flightFactory;
}
public function getAllFlights()
{
$flightsJson = $this->getFromExternalCurl();
return $this->flightFactory->buildFlightList($flightsJson);
}
private function getFromExternalCurl()
{
return Curl::to('http://www.foo.com/flights.json')
->withData( array( 'foz' => 'baz' ) )
->asJson()
->get();
}
}
Basically the service would make the external API call and the response is passed to a factory which creates the instances.
Note that you just need to add the factory in the construct and it's binded because laravel uses https://laravel.com/docs/5.4/container
namespace App\Factories;
class FlightFactory
{
public function buildFlightList($flightJsonList)
{
$flightCollection = collect();
foreach($flightJsonList as $flightJson) {
$flightCollection->push($this->buildFlight($flightJson));
}
return $flightCollection;
}
public function buildFlight($flightJson)
{
$flight = new Flight();
// add properties
return $flight;
}
}
The factory will return a Collection which is verry usefull because it contains usefull methods, or you can return an array.
In this example I used a curl library https://github.com/ixudra/curl but it can be replaced with native php or other libraries.
Then you can use by injecting the FlightService in your controllers.
P.S: Code not tested but represents a possible approach
I have this Controller :
namespace FacilitaTripBundle\Controller;
use FacilitaTripBundle\Api\models\GuideDestination\GuideDestinationModel;
use FacilitaTripBundle\Api\models\Destination\DestinationModel;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
/**
* #Route("/api/v1", name="api")
*/
class ApiController extends Controller
{
/**
* #Route("/destinations/get_all_minimal/", name="destination_get_minimal")
*/
public function getMinimalAction()
{
$model = new DestinationModel();
$data = $model->getAllMinimal();
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
/**
* #Route("/guideDestination/getLastAddDestination/", name="destination_last_add_destination")
*/
public function getLastAddDestinationAction()
{
$guide_destination_model = new GuideDestinationModel();
$data = $guide_destination_model->getLastAddDestination();
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
I got this error :
Attempted to load class "GuideDestinationModel" from namespace "FacilitaTripBundle\Api\models\GuideDestination".
Did you forget a "use" statement for another namespace
I define the class GuideDestinationModel in this file :
namespace FacilitaTripBundle\Api\models\GuideDestination;
class GuideDestinationModel {
}
How you got an idea why I got this error ?
What is the physical path to file containing GuideDestinationModel class?
According to PSR-0, which Symfony is using, you are supposed to put class definitions in path which corresponds to your namespace like in following example.
\Symfony\Core\Request =>
/path/to/project/lib/vendor/Symfony/Core/Request.php
I notice you have lowercase models in your FacilitaTripBundle\Api\models\GuideDestination namespace. Is your directory models also lowercase? If not this might be the issue here if you are using system which is case sensitive when it comes to path resolving (i.e. Linux)
I am trying to load a custom class in my CakePHP3 project, although I can't seem to find out what I am missing.
I have a folder src/Library with Config.php in it:
<?php
namespace App\Library;
/**
* Class containing CONST values for important settings
*
* #version 1.0
* #author berry
*/
class Config
{
const UPLOAD_DIRECTORY = './upload/';
}
I put use App\Library\Config; in my PicturesController, which Visual Studio even recognizes as a valid class (I can access the const through intellisense)
Here is my controller:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
use App\Library\Config;
/**
* Pictures Controller
*
* #property \App\Model\Table\PicturesTable $Pictures
*/
class PicturesController extends AppController
{
public function upload()
{
if($this->request->is('post'))
{
$oConfig = new Config();
$oUploadDir = new Folder($oConfig::UPLOAD_DIRECTORY);
debug($oUploadDir);
$aFile = $this->request->data('submittedfile');
}
}
So despite my IDE even registering the class (and telling me I'm using it correctly) I get Class 'App\Library\Config' not found thrown in the browser.
I changed the name from Library to Berry (My first name).
Apparently you can't call it Library. Probably used somewhere else in Cake.
Warning: This question is Laravel 4 specific.
I've been using Facades in my controllers before. Therefore I know the code is working. Now I need to introduce dependency injection for various reasons.
After refactoring the controller I get following error:
Illuminate \ Container \ BindingResolutionException
Unresolvable dependency resolving [Parameter #0 [ $name ]].
I can't figure out where the problem is. The Error message seems cryptic to me and I don't understand it. (I don't see any problem with my __constructor parameters since I've registered the binding for the HelpersInterface)
Here are the important parts of my code:
File: app/start/global.php
<?php
// ...
App::bind('Acme\Interfaces\HelpersInterface', 'Acme\Services\Helpers');
File: composer.json
// ...
"autoload": {
// ...
"psr-0": {
"Acme": "app/"
}
},
// ...
File: app/Acme/Controllers/BaseController.php
<?php namespace Acme\Controllers;
use Carbon\Carbon;
use Controller;
use Illuminate\Foundation\Application as App;
use Illuminate\View\Factory as View;
use Acme\Interfaces\HelpersInterface as Helpers;
use Illuminate\Http\Response;
class BaseController extends Controller {
/**
* #var \Illuminate\Foundation\Application
*/
private $app;
/**
* #var \Carbon\Carbon
*/
private $carbon;
/**
* #var \Illuminate\View\Factory
*/
private $view;
/**
* #var \Acme\Interfaces\HelpersInterface
*/
private $helpers;
function __construct(App $app, Carbon $carbon, View $view, Helpers $helpers)
{
$this->app = $app;
$this->carbon = $carbon;
$this->view = $view;
$this->helpers = $helpers;
$lang = $this->app->getLocale();
$now = $this->carbon->now();
$this->view->share('lang', $lang);
$this->view->share('now', $now);
}
/**
* Missing Method
*
* Abort the app and return a 404 response
*
* #param array $parameters
* #return Response
*/
public function missingMethod($parameters = array())
{
return $this->helpers->force404();
}
}
File: app/Acme/Services/Helpers.php
<?php namespace Acme\Services;
use Illuminate\Config\Repository as Config;
use Illuminate\Database\Connection as DB;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector as Redirect;
use Illuminate\Session\Store as Session;
use Illuminate\Support\Facades\Response;
use Illuminate\Translation\Translator as Lang;
use Illuminate\View\Factory as View;
use Acme\Interfaces\MockablyInterface;
use Monolog\Logger as Log;
class Helpers implements HelpersInterface {
// ...
public function __construct(
Config $config,
Lang $lang,
View $view,
MockablyInterface $mockably,
Log $log,
Request $request,
Session $session,
DB $db,
Redirect $redirect,
Response $response
) {
// ...
}
// ...
}
File: app/Acme/Providers/HelpersServiceProvider.php
<?php namespace Acme\Providers;
use Illuminate\Support\ServiceProvider;
use Acme\Services\Helpers;
class HelpersServiceProvider extends ServiceProvider {
private $db;
private $defaultDbConnection;
protected function init()
{
$this->db = $this->app['db'];
$this->defaultDbConnection = $this->db->getDefaultConnection();
}
public function register()
{
$this->init();
$this->app->bind('helpers', function ()
{
return new Helpers(
$this->app['config'],
$this->app['translator'],
$this->app['view'],
$this->app['mockably'],
$this->app->make('log')->getMonolog(),
$this->app['request'],
$this->app['session.store'],
$this->db->connection($this->defaultDbConnection),
$this->app['redirect'],
$this->app['Illuminate\Support\Facades\Response']
);
});
}
For me it was just a matter of running
php artisan optimize:clear
It seems your Acme\Services\Helpers constructor takes a $name parameter, but is not type hinted.
Laravel's IoC is not magic. If your don't provide a type hint for every parameter, the IoC container has no way of knowing what to pass in.
Make sure you use Illuminate\Http\Request; on top of the file instead of any other http import like this
use Illuminate\Http\Request;
THANK ME LATER!
Got it fixed. All the tutorials about dependency injection were referring to concrete implementations of interfaces so that I thought that's the way to go about it. Joseph Silber's answer got me on the right track.
The trick is to bind the Interface to the binding of the ServiceProvider like shown below. That way Laravel will know how to instantiate the Helpers service.
File: app/start/global.php
<?php
// ...
App::bind('Acme\Interfaces\HelpersInterface', 'helpers');