Error with Str::slug upgrading laravel 6 app into 8 - laravel

I try to upgrade my laravel 6 app into 8 and got error :
TypeError
call_user_func(): Argument #1 ($callback) must be a valid callback, class "Str" not found
at app/Http/Traits/HasSlug.php:30
26▕ $slugger = config('tags.slugger');
27▕
28▕ $slugger = $slugger ?: '\Str::slug';
29▕
➜ 30▕ return call_user_func($slugger, $this->getTranslation('name', $locale));
31▕ }
32▕ }
33▕
1 app/Http/Traits/HasSlug.php:30
call_user_func()
2 app/Http/Traits/HasSlug.php:18
App\Tag::generateSlug()
In file Http/Traits/HasSlug.php :
<?php
//namespace Spatie\Tags;
namespace App\Http\Traits;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
trait HasSlug
{
public static function bootHasSlug()
{
static::saving(function (Model $model) {
collect($model->getTranslatedLocales('name'))
->each(function (string $locale) use ($model) {
with(new self)->info( $locale,'bootHasSlug $locale::' );
$model->setTranslation('slug', $locale, $model->generateSlug($locale));
});
});
}
protected function generateSlug(string $locale): string
{
$slugger = config('tags.slugger');
$slugger = $slugger ?: '\Str::slug';
return call_user_func($slugger, $this->getTranslation('name', $locale));
}
}
I know this issue with Str::slug when upgrading laravel, but I am not sure in which way can it be fixed here ?
UPDATED PART :
No that does not work.
If I remake :
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
trait HasSlug
{
public static function bootHasSlug()
{
static::saving(function (Model $model) {
collect($model->getTranslatedLocales('name'))
->each(function (string $locale) use ($model) {
with(new self)->info( $locale,'bootHasSlug $locale::' );
$model->setTranslation('slug', $locale, $model->generateSlug($locale));
});
});
}
protected function generateSlug(string $locale): string
{
with(new self)->info( $locale, 'generateSlug $locale::' );
$slugger = config('tags.slugger');
$slugger = $slugger ?: \Illuminate\Support\Str::slug;
// $slugger = $slugger ?: \Illuminate\Support\Str::class.'::slug';
// $slugger = $slugger ?: 'Str::slug';
return call_user_func($slugger, $this->getTranslation('name', $locale));
}
Running migrations I got error:
TypeError
call_user_func(): Argument #1 ($callback) must be a valid callback, class "Str" not found
at app/Http/Traits/HasSlug.php:33
29▕ $slugger = $slugger ?: \Illuminate\Support\Str::slug;
30▕ // $slugger = $slugger ?: \Illuminate\Support\Str::class.'::slug';
31▕ // $slugger = $slugger ?: 'Str::slug';
32▕
➜ 33▕ return call_user_func($slugger, $this->getTranslation('name', $locale));
34▕ }
35▕ }
36▕
1 app/Http/Traits/HasSlug.php:33
call_user_func()
2 app/Http/Traits/HasSlug.php:18
App\Tag::generateSlug()
But in blade templates I can use
\Illuminate\Support\Str::plural(
$ php artisan --version
Laravel Framework 8.83.0
UPDATED PART 2:
I opened file https://github.com/spatie/laravel-tags/blob/main/src/HasSlug.php
and copied content of it into my app/Http/Traits/HasSlug.php :
<?php
// namespace Spatie\HasSlug; // As namespace seemed invalid for me I tried in this way, but failed anyway
namespace Spatie\Tags;
use Illuminate\Database\Eloquent\Model;
trait HasSlug
{
public static function bootHasSlug()
{
static::saving(function (Model $model) {
collect($model->getTranslatedLocales('name'))
->each(fn (string $locale) => $model->setTranslation(
'slug',
$locale,
$model->generateSlug($locale)
));
});
}
protected function generateSlug(string $locale): string
{
$slugger = config('tags.slugger');
$slugger ??= '\Illuminate\Support\Str::slug';
return call_user_func($slugger, $this->getTranslation('name', $locale));
}
}
In composer.json I updated line to the latest version:
"spatie/laravel-tags": "^4.3.0",
and run
composer update
with success.
I supposed that this version is relative to laravel 8
But running migrations I got next error :
Symfony\Component\ErrorHandler\Error\FatalError
Trait "App\Http\Traits\HasSlug" not found
at app/Tag.php:19
15▕
16▕
17▕
18▕
➜ 19▕ class Tag extends Model implements Sortable
20▕ {
21▕ use funcsTrait;
22▕
23▕ use SortableTrait, HasTranslations, HasSlug;
I am not sure why I have app/Http/Traits/HasSlug.php updare my app/, but looks like I need it there...
Thanks!

Instead of using call_user_func, I used app() to instantiate the slugger defined in config/tags.php.
config/tags.php
<?php
use Illuminate\Support\Str;
return [
'slugger' => [
// the slugger class. Will be instantiated with whatever is passed in the args.
// In this case: new Str(...[]) <- no args. Same as new Str() or new Str
'class' => [
'name' => Str::class,
'args' => [],
],
// the slugger method. If any extra args are needed, they will be used.
// In this case: $slugger->slug($string, ...[]) <- no args, same as $slugger->slug($string)
'method' => [
'name' => 'slug',
'args' => [],
],
],
];
app/Http/Traits/HasSlug.php
<?php
namespace App\Http\Traits;
use Illuminate\Database\Eloquent\Model;
trait HasSlug
{
protected function generateSlug(string $locale): string
{
// use Str's slug method by default.
list($class, $class_args, $method, $method_args) = [
config('tags.slugger.class.name', 'Illuminate\Support\Str'),
config('tags.slugger.class.args', []),
config('tags.slugger.method.name', 'slug'),
config('tags.slugger.method.args', []),
];
$string = $this->getTranslation('name', $locale);
return app($class, $class_args)->{$method}(...[$string, ...$method_args]);
}
}

Related

Why custom Exception was not catch by expectException method?

Making tests on laravel 9 site I try to catch custom Exception and looking at this
Undefind withoutExceptionHandling()
example I do in my tests
<?php
namespace Tests\Feature;
//use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Tests\TestCase;
use Carbon\Carbon;
use App\Models\Article;
use App\Models\User;
use Illuminate\Support\Str;
class ArticlesCrudTest extends TestCase
{
use InteractsWithExceptionHandling;
public function testNegativeArticleGotFailureWithInactiveUserToBeAdded()
{
$loggedUser = clone(self::$loggedUser);
$this->withoutExceptionHandling();
$loggedUser->status = 'I' ; // Inactive
$newArticleObject = \App\Models\Article::factory(Article::class)->make();
$response = $this->actingAs($loggedUser, 'api')->post(route('articles.store'),
$newArticleObject->toArray());
$this->expectException(\App\Exceptions\UserAccountManagerAccessException::class);
$response->assertStatus(400);
}
But I got error message :
here was 1 error:
1) Tests\Feature\ArticlesCrudTest::testNegativeArticleGotFailureWithInactiveUserToBeAdded
App\Exceptions\UserAccountManagerAccessException: Your account must be active in "store" !
/ProjectPath/app/Library/Services/LocalUserAccountManager.php:59
/ProjectPath/app/Repositories/ArticleCrudRepository.php:191
/ProjectPath/app/Http/Controllers/ArticleController.php:86
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Route.php:260
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Route.php:205
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Router.php:725
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php:50
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php:126
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php:102
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php:54
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php:44
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Router.php:726
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Router.php:703
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Router.php:667
/ProjectPath/vendor/laravel/framework/src/Illuminate/Routing/Router.php:656
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:190
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php:31
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php:40
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php:27
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php:86
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php:62
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php:39
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180
/ProjectPath/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:165
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:134
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:545
/ProjectPath/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:340
/ProjectPath/tests/Feature/ArticlesCrudTest.php:108
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
Yes, valid exception UserAccountManagerAccessException was raised, but why methods expectException and $response->assertStatus did not work and my
test did not passed with sucess?
TOPIC DETAILS:
In routes/api.php :
Route::middleware('auth:api') ->group(function () {
Route::apiResource('articles', ArticleController::class);
in app/Http/Controllers/ArticleController.php Repository method is called:
public function store(Request $request)
{
return $this->articleCrudRepository->store(data: $request->only('title', 'text', 'text_shortly',
'creator_id', 'published'), makeValidation: true);
}
and in app/Repositories/ArticleCrudRepository.php Repository :
<?php
namespace App\Repositories;
...
class ArticleCrudRepository
{
public function store(array $data, bool $makeValidation = false): JsonResponse|MessageBag
{
...
$this->userAccountManager->checkPermissions( [ ], "store");
// UserAccountManagerAccessException is raised in method above, BEFORE try block with transaction...
DB::beginTransaction();
try {
$article = Article::create([
'title' => $data['title'],
'text' => $data['text'],
'text_shortly' => $data['text_shortly'],
'creator_id' => $data['creator_id'],
'published' => $data['published'],
]);
DB::Commit();
$article->load('creator');
return response()->json(['article' => (new ArticleResource($article))], 201);
} catch (\Exception $e) {
$errorMessage = $e->getMessage();
\Log::info($errorMessage);
DB::rollback();
return sendErrorResponse($e->getMessage(), 500);
}
}
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^9.19",
"laravel/passport": "^11.3",
Thanks in advance!
I need to set such order:
$this->expectException(\App\Exceptions\UserAccountManagerAccessException::class);
And after that :
$response = $this->actingAs($loggedUser, 'api')->post(route('articles.store')
That works!

With StripeClient I got error No API key provided

in my Laravel 8 / with stripe/stripe-php": "^7.75" I try to connect and create account on stripe side
and got error :
No API key provided. Set your API key when constructing the StripeClient instance, or provide it on a per-request basis using the `api_key` key in the $opts argument.
with code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Session;
use Stripe;
use Stripe\StripeClient;
use App\Http\Controllers\Controller;
use Illuminate\Database\DatabaseManager;
use App\Models\Settings;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use App\Models\User;
use App\Models\StripeToken;
class SellerController extends Controller
{
protected StripeClient $stripeClient;
protected DatabaseManager $databaseManager;
public function __construct(StripeClient $stripeClient, DatabaseManager $databaseManager)
{
\Log::info(varDump($stripeClient, ' -1 SellerController ::'));
$this->stripeClient = $stripeClient;
$this->databaseManager = $databaseManager;
}
public function showProfile($id)
{
\Log::info('-1 showProfile $id ::' . print_r($id, true));
$seller = User::find($id);
if (!$seller) {
abort(404);
}
return view('market.seller', [
'seller' => $seller,
'balance' => null
]); // /_wwwroot/lar/tAdsBack/resources/views/admin/stripe/stripe.blade.php
} // public function showProfile($id)
public function redirectToStripe($id)
{
\Log::info('-1 redirectToStripe $id ::' . print_r($id, true));
$seller = User::find($id);
if (!$seller) {
abort(404);
}
$appEnv = strtolower(config('app.env'));
if ($appEnv == 'local' or $appEnv == 'dev') {
\Log::info('-1 config(app.STRIPE_TEST_KEY)::' . print_r(config('app.STRIPE_TEST_KEY'), true));
\Stripe\Stripe::setApiKey(config('app.STRIPE_TEST_KEY')); // LOOKS LIKE THAT IS NOT APPLIED
$this->stripeClient->apiKey = config('app.STRIPE_TEST_KEY'); // THIS DOES NOT HELP
$this->stripeClient->api_key = config('app.STRIPE_TEST_KEY'); // THIS DOES NOT HELP
}
if ($appEnv == 'production') {
\Stripe\Stripe::setApiKey(config('app.STRIPE_LIVE_KEY'));
$this->stripeClient->opts['api_key'] = config('app.STRIPE_LIVE_KEY');
}
if (!$seller->completed_stripe_onboarding) { // Complete onboarding process
$str = \Str::random();
$stripeToken = new StripeToken();
$stripeToken->token = $str;
$stripeToken->seller_id = $id;
$stripeToken->save();
if (empty($seller->stripe_connect_id)) { // if has no stripe account
// // Create a new Stripe Connect Account object.
\Log::info('-1 $$this->stripeClient ::' . print_r($this->stripeClient, true));
Checking log I see :
[2021-03-22 05:40:30] local.INFO: -1 $$this->stripeClient ::Stripe\StripeClient Object
(
[coreServiceFactory:Stripe\StripeClient:private] =>
[config:Stripe\BaseStripeClient:private] => Array
(
[api_key] =>
[client_id] =>
[stripe_account] =>
[stripe_version] =>
[api_base] => https://api.stripe.com
[connect_base] => https://connect.stripe.com
[files_base] => https://files.stripe.com
)
[defaultOpts:Stripe\BaseStripeClient:private] => Stripe\Util\RequestOptions Object
(
[apiKey] =>
[headers] => Array
(
[Stripe-Account] =>
[Stripe-Version] =>
)
[apiBase] =>
)
[api_key] => sk_test_NNNNNN
How to fix this error ?
I suppose I need to set api_key in some other way, not
$this->stripeClient->apiKey = config('app.STRIPE_TEST_KEY'); // THIS DOES NOT HELP
$this->stripeClient->api_key = config('app.STRIPE_TEST_KEY'); // THIS DOES NOT HELP
but how?
Thanks!
Before using stripe/stripe-php directly, check out Laravel Cashier.
https://laravel.com/docs/8.x/billing

SwaggerDecorator not working after update API Platform to v2.3.5

After the API platform upgrade, the decorator from the documentation has stopped working:
https://api-platform.com/docs/core/swagger/#overriding-the-swagger-documentation
Does anyone know if this is a change, is it a bug?
I use Symfony 4.2.2 (probably the problem is due to the Symfony update).
My code adding to swagger input form to change context:
<?php
namespace App\Swagger;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
final class SwaggerDecorator implements NormalizerInterface
{
private $decorated;
public function __construct(NormalizerInterface $decorated)
{
$this->decorated = $decorated;
}
public function normalize($object, $format = null, array $context = [])
{
$docs = $this->decorated->normalize($object, $format, $context);
$customDefinition = [
'name' => 'context',
'definition' => 'Context field',
'default' => '',
'in' => 'query',
];
// Add context parameter
foreach ($docs['paths'] as $key => $value) {
// e.g. add a custom parameter
$customDefinition['default'] = lcfirst($docs['paths'][$key]['get']['tags'][0] ?? '');
$docs['paths'][$key]['get']['parameters'][] = $customDefinition;
if(isset($docs['paths'][$key]['post'])){
$docs['paths'][$key]['post']['parameters'][] = $customDefinition;
}
if(isset($docs['paths'][$key]['put'])){
$docs['paths'][$key]['put']['parameters'][] = $customDefinition;
}
}
return $docs;
}
public function supportsNormalization($data, $format = null)
{
return $this->decorated->supportsNormalization($data, $format);
}
}
Try to use parameter "decoration_priority" in services configuration (https://symfony.com/doc/current/service_container/service_decoration.html#decoration-priority)
For example:
App\Swagger\SwaggerDecorator:
decorates: 'api_platform.swagger.normalizer.documentation'
arguments: [ '#App\Swagger\SwaggerDecorator.inner' ]
decoration_priority: 1000
Or fix version "symfony/dependency-injection": "4.2.1" in composer.json )
See https://github.com/symfony/symfony/issues/29836 for details

Laravel 5 create middleware with oauth2 server check

I have implemented this oauth server http://bshaffer.github.io/oauth2-server-php-docs/
It has a Laravel implementation : http://bshaffer.github.io/oauth2-server-php-docs/cookbook/laravel/
This guide you and gives that code for routes :
App::singleton('oauth2', function() {
$storage = new OAuth2\Storage\Pdo(array('dsn' => 'mysql:dbname=oauth2;host=localhost', 'username' => 'root', 'password' => 'root'));
$server = new OAuth2\Server($storage);
$server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
$server->addGrantType(new OAuth2\GrantType\UserCredentials($storage));
return $server;
});
Route::get('private', function()
{
$bridgedRequest = OAuth2\HttpFoundationBridge\Request::createFromRequest(Request::instance());
$bridgedResponse = new OAuth2\HttpFoundationBridge\Response();
// fix for laravel
$bridgedRequest->request = new \Symfony\Component\HttpFoundation\ParameterBag();
$rawHeaders = getallheaders();
if (isset($rawHeaders["Authorization"])) {
$authorizationHeader = $rawHeaders["Authorization"];
$bridgedRequest->headers->add([ 'Authorization' => $authorizationHeader]);
}
if (App::make('oauth2')->verifyResourceRequest($bridgedRequest, $bridgedResponse)) {
$token = App::make('oauth2')->getAccessTokenData($bridgedRequest);
return Response::json(array(
'private' => 'stuff',
'user_id' => $token['user_id'],
'client' => $token['client_id'],
'expires' => $token['expires'],
));
}
else {
return Response::json(array(
'error' => 'Unauthorized'
), $bridgedResponse->getStatusCode());
}
});
It works perfectly well like that. Now I want to transform that check function in the "private" route to a middleware I could apply to each necessary route. I created the middleware using
php artisan make:middleware AuthChecker
Added it to the kernel.php, and pasted the code of the verification function inside of it. And I immediately got an error :
FatalErrorException in AuthChecker.php line 17:
Class 'Oauth2\HttpFoundationBridge\Request' not found
So, I guess I will have to "use" things, but since I'm still a beginner I don't really know what to do...
Thanks ahead for your help !
[EDIT] the content of the middleware currently look like this :
namespace App\Http\Middleware;
use Closure;
class OauthCheck {
public function handle($request, Closure $next)
{
$bridgedRequest = OAuth2\HttpFoundationBridge\Request::createFromRequest($request);
$bridgedResponse = new OAuth2\HttpFoundationBridge\Response();
// fix for laravel
$bridgedRequest->request = new \Symfony\Component\HttpFoundation\ParameterBag();
$rawHeaders = getallheaders();
if (isset($rawHeaders["Authorization"])) {
$authorizationHeader = $rawHeaders["Authorization"];
$bridgedRequest->headers->add([ 'Authorization' => $authorizationHeader]);
}
if (App::make('oauth2')->verifyResourceRequest($bridgedRequest, $bridgedResponse)) {
$token = App::make('oauth2')->getAccessTokenData($bridgedRequest);
return Response::json(array(
'private' => 'stuff',
'user_id' => $token['user_id'],
'client' => $token['client_id'],
'expires' => $token['expires'],
));
return $next($request);
}
else {
return Response::json(array(
'error' => 'Unauthorized'
), $bridgedResponse->getStatusCode());
}
}
}
Thanks again
FatalErrorException in AuthChecker.php line 17:
Class 'Oauth2\HttpFoundationBridge\Request' not found
So you want to use the Request class from Oauth2\HttpFoundationBridge namespace to your OauthCheck class from App\Http\Middleware.
You can do it in either ways:
Import the class
namespace App\Http\Middleware;
use Oauth2\HttpFoundationBridge\Request;
class OauthCheck {
public function handle($request, Closure $next)
{
$bridgedRequest = Request::createFromRequest($request);
....
}
}
Use the class explicitly
namespace App\Http\Middleware;
class OauthCheck {
public function handle($request, Closure $next)
{
$bridgedRequest = \Oauth2\HttpFoundationBridge\Request::createFromRequest($request);
....
}
}
Take note of the backslash before Oauth2\HttpFoundationBridge\Request. If you just say $bridgedRequest = Oauth2\HttpFoundationBridge\Request, then PHP will look for App\Http\Middleware\Oauth2\HttpFoundationBridge\Request.

Phalcon: HMVC view not working

I got a problem rendering nested view, here is what I'm trying to do
I changed your 'request' of HMVC (HMVC-GitHub or/and HMVC-Pattern) function into an Elements module
namespace Modules\Main\Libraries;
/**
* Elements
*
* Helps to build UI elements for the application
*/
class Elements extends \Phalcon\Mvc\User\Component
{
public function loadModule($path = '', $data = array()) {
$di = clone $this->getDI();
$dispatcher = $di->get('dispatcher');
$paths = explode('/', $path);
$data = is_array($data) ? $data : array($data);
// get controller name
if (isset($paths[0])) {
$controller = $paths[0];
}
// get action name
if (isset($paths[1])) {
$action = $paths[1];
}
// get params
if (isset($paths[2])) {
array_splice($paths, 0, 2);
$params = array_merge($paths, $data);
} else {
$params = $data;
}
if (!empty($controller)) {
$dispatcher->setControllerName($controller);
} else {
$dispatcher->setControllerName('index');
}
if (!empty($action)) {
$dispatcher->setActionName($action);
} else {
$dispatcher->setActionName('index');
}
if (!empty($params)) {
if(is_array($params)) {
$dispatcher->setParams($params);
} else {
$dispatcher->setParams((array) $params);
}
} else {
$dispatcher->setParams(array());
}
$dispatcher->dispatch();
$response = $dispatcher->getReturnedValue();
if ($response instanceof ResponseInterface) {
return $response->getContent();
}
return $response;
}
}
and I have 2 controllers:
namespace Modules\Main\Controllers;
class IndexController extends ControllerBase
{
public function indexAction()
{
$secondContent = $this->elements->loadModule('test/hello/json');
$this->view->setVar('secondContent', $secondContent);
}
}
and
namespace Modules\Main\Controllers;
use \Phalcon\Http\Response;
class TestController extends ControllerBase
{
public function indexAction()
{
}
public function helloAction($format='html', $param = 'empty')
{
$this->view->setVar('content', 'Hello this is test value "'.$param.'"');
$content = $this->view->getContent();
return (string)$content;
// return 'Hello this is test value "'.$param.'"';
}
}
my DI
$di['elements'] = function() {
return new \Modules\Main\Libraries\Elements();
};
Views files
IndexController::Index
<h1>Congratulations!</h1>
<p>You're now flying with Phalcon. Great things are about to happen!</p>
<p>Second content: {{ secondContent}}</p>
<p>HMVC: {{ elements.loadModule('test/hello/json', 'test') }}</p>
and HelloController::test
This is :: {{ content }}
expecting to get
Congratulations!
You're now flying with Phalcon. Great things are about to happen!
Second content: This is :: Hello this is test value "empty"
HMVC: This is :: Hello this is test value "test"
but it only rendering the HelloController (First call from IndexController::indexAction):
This is :: Hello this is test value "empty"
if I change IndexController::indexAction to
public function indexAction()
{
$secondContent = '';
$this->view->setVar('secondContent', $secondContent);
}
and TestController::helloAction to
public function helloAction($format='html', $param = 'empty')
{
$this->view->setVar('content', 'Hello this is test value "'.$param.'"');
$content = $this->view->getContent();
//return (string) $content;
return 'Hello this is test value "'.$param.'"';
}
the result that i get is (Second content is empty):
Congratulations!
You're now flying with Phalcon. Great things are about to happen!
Second content:
HMVC: Hello this is test value "test"
Any solution to solve this ?
Thanks,
Helman
Phalcon have built-it modules feature, you dont have to built your own module loader, you just need create module bootstrap that extend ModuleDefinitionInterface.
Just take a look this sample from phalcon multi module
https://github.com/phalcon/mvc/tree/master/multiple
this example below is taken from link above, This contain module bootstrap code.
<?php
namespace Multiple\Frontend;
class Module
{
public function registerAutoloaders()
{
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
'Multiple\Frontend\Controllers' => '../apps/frontend/controllers/',
'Multiple\Frontend\Models' => '../apps/frontend/models/',
));
$loader->register();
}
/**
* Register the services here to make them general or register in the ModuleDefinition to make them module-specific
*/
public function registerServices($di)
{
//Registering a dispatcher
$di->set('dispatcher', function () {
$dispatcher = new \Phalcon\Mvc\Dispatcher();
//Attach a event listener to the dispatcher
$eventManager = new \Phalcon\Events\Manager();
$eventManager->attach('dispatch', new \Acl('frontend'));
$dispatcher->setEventsManager($eventManager);
$dispatcher->setDefaultNamespace("Multiple\Frontend\Controllers\\");
return $dispatcher;
});
//Registering the view component
$di->set('view', function () {
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../apps/frontend/views/');
return $view;
});
$di->set('db', function () {
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "invo"
));
});
}
}
you can load module using this code below
$app = new \Phalcon\Mvc\Application();
$app->registerModules(array(
'frontend' => array(
'className' => 'Multiple\Frontend\Module',
'path' => '../apps/frontend/Module.php'
),
'backend' => array(
'className' => 'Multiple\Backend\Module',
'path' => '../apps/backend/Module.php'
)
));

Resources