I have a report.php file created in app/vendors/shells folder with the following content
class ReportShell extends Shell {
var $uses = array('User');
function main() {
$userData = $this->User->find('first');
}
}
when I want to run it from app folder ../cake/console/cake report I get the following error
Error: Missing database table 'users' for model 'User'
users table does exist in db, User model as well. And the project works fine, I mean there are no issues with models, controllers, views. My cake version is 1.3
Thanks
I figured it out, the problem was that in db config instead of 'host' => 'localhost' it was necessary to write 'host' => '127.0.0.1', see also this answer
How do I get CakePHP bake to find mysql.sock and recognize MySQL while using MAMP on Mac OSX?
Related
I am designing a custom authentication scheme (based on public keys) alongside a stateless API, and decided Passport would fulfill the need for post-authentication requests.
Assuming the authentication succeeds, and the user is authenticated, they would receive a Personal Access Token, and use the token for all further requests. The trouble I'm experiencing (still after much searching through various forums and Stack Overflow) is that when using Laravel's built in testing suite, on the createToken() method, it generates an (admittedly common) exception:
"ErrorException : Trying to get property 'id' of non-object".
I am able to manually create a user through Tinker, and create a token through Tinker. However I'm experiencing problems when attempting to automate this process after authenticating.
Here is the relevant code snippet post-authentication:
Auth::login($user);
$user = Auth::user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
"access_token" => $tokenResult->accessToken,
"token_type" => "Bearer",
"expires_at" => Carbon::parse(
$tokenResult->token->expires_at)->toDateTimeString()
],
200);
I've manually called Auth::login on the user, to ensure the user is logged in, and Auth::user() returns the user (not null). Upon executing the third line of code, the exception is thrown with the following mini stack-trace (I can provide a full stack-trace if requested).
laravel\passport\src\PersonalAccessTokenFactory.php:100
laravel\passport\src\PersonalAccessTokenFactory.php:71
laravel\passport\src\HasApiTokens.php:67
app\Http\Controllers\Auth\LoginController.php:97
laravel\framework\src\Illuminate\Routing\Controller.php:54
laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php:45
From running this through debug a few times- even though the class is called and loaded, and it appears the Client is found through ControllerDispatcher -> Client::find(id) and found in ClientRepository, when it gets to PersonalAccessTokenFactory, the $client passed in is null (which explains why the $client->id can't be found, though I have no idea why the $client is null at this point).
protected function createRequest($client, $userId, array $scopes)
{
$secret = Passport::$hashesClientSecrets ? Passport::$personalAccessClientSecret : $client->secret;
return (new ServerRequest)->withParsedBody([
'grant_type' => 'personal_access',
'client_id' => $client->id,
...
}
Things I have done/tried with some guidance from the documentation and other posts:
Manually created a user in Tinker, and created the token through Tinker- this does work.
Ensured the user is logged in before attempting to generate token.
passport:install (and adding the --force option)
Ensured Personal Access Client is generated with passport:client --personal
Ensured the AuthServiceProvider::boot() contains the ClientID and Client Secret (in the .env).
migrate:refresh followed by passport:install --force
Complete removal of Passport, removing all files, keys, migrations, and DB entries, followed with a migrate:refresh and reinstallation of Passport, along with generating an additional personal access client (even though one is generated during passport:install).
I'm not sure where else to look/what else to try at this point, so any help or guidance would be much appreciated!
I eventually discovered the solution. The problem is multi-layered, in part having to do with outdated Laravel documentation in regards to testing and Passport Personal Access Clients.
The first part of the problem had to do with using the trait RefreshDatabase on my unit test. Since this creates a mock database with empty datasets, although the clients themselves exist in the real database and the .env file, when the test is run, the test does not see those clients as existing in the mock database. To solve this problem, you must create a client in the setup function before the test is run.
public function setUp() : void
{
parent::setUp();
$this->createClient(); //Private method->Full code below
}
This solves the issue about having a null client during testing, but starting in Laravel 7, Laravel added a requirement for Personal Access Clients that the id and the client secret has to be kept inside the .env file. When running the test, the test will see the actual client id and secret in the .env, and fail to validate these with the client that was created and stored in the mock database, returning another exception: "Client Authentication Failed".
The solution to this problem is to create a .env.testing file in your main project directory, copying your .env file contents to it and ensuring that the keys below exist with values for either your main created Personal Access Client, or copying the secret from a client generated just for testing (I would advise the latter).
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=1
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=unhashed-client-secret-value
Then using the code below, make sure the $clientSecret value is the same as the key value in your .env.testing file.
private function createClient() : void
{
$clientRepository = new ClientRepository();
$client = $clientRepository->createPersonalAccessClient(
null, 'Test Personal Access Client', 'http://localhost'
);
DB::table('oauth_personal_access_clients')->insert([
'client_id' => $client->id,
'created_at' => new DateTime,
'updated_at' => new DateTime,
]);
$clientSecret = 'unhashed-client-secret-value';
$client->setSecretAttribute($clientSecret);
$client->save();
}
This will create a new client, set the attribute secret to the value in the variable and update the mock database secret to contain the same value. Hopefully this helps anyone with the same issue.
Another way to prevent copy/paste source code is to just call artisan command in the setup method.
public function setUp() {
parent::setUp();
$this->artisan('passport:install');
}
original here
Just use the facade
public function setUp() {
parent::setUp();
Artisan::call('passport:install');}
I was having this in my website using Laravel 5.3 :
Route::group(['namespace' => 'Admin', 'prefix' => 'admin', 'middleware'=>'auth'], function(){
Route::resource('posts', 'PostsController');
});
This lets me go to the admin panel using: mywebsite/public/admin/posts.
Now, when I migrated the site to Laravel5.5 I got this error Route[admin.posts.create] not defined when i attempt to open the link Create post which was working fine before.
I know that routing system has changed but I did not know how to have such links in new Laravel5.5. I tried url instead of route but I got the same error. I also checked the new documentation but I did not get exactly how to have the same link system.
Can anyone have a better explanation of this new routing system? (I have to migrate the site to 5.5).
Laravel names resource routes by default, you can check them by running php artisan route:list
If you want to override them for any reason you can pass in an array when you define the route and override each individual route name like so:
Route::resource('posts', 'PostsController', ['names' => [
'create' => 'admin.posts.build'
]]);
I’ve installed CakePHP into sub-directories and they seem to run fine! They all have different database.php configuration files and access different databases.
Example:
public_html/cakephp1/
public_html/cakephp2/
I access them separately using http://www.example.com/cakephp1/ and http://www.example.com/cakephp2/ and it all seems fine.
Problem occurs when I log into one of them (using CakePHP standard Auth/Session components), and I when I flip over to the other installation it also considers me as already logged in!
How do I prevent this? What’s the recommended solution? Will it help if I change the salt value in each installation?
EDIT:
Hi Martin, I've just tried the method of changing core.php to use "cake" session handling and specifying a cookie path. So now in each application i have different core.php files as such:
cakephp1's core.php
Configure::write('Session', array(
'defaults' => 'cake',
'ini' => array(
'session.cookie_path' => '/cakephp1'
)
));
cakephp2's core.php
Configure::write('Session', array(
'defaults' => 'cake',
'ini' => array(
'session.cookie_path' => '/cakephp2'
)
));
But still does not work and both installs seem to still share the same session. Where should I be looking to see if a cookie was actually created? I've checked the folder tmp/sessions under each /cakephp1 and /cakephp2 but that folder is always empty.
EDIT: Modifying AppController:
Martin, please help me suggest where else to look. I've followed ur code as follows:
Below is the code from my /demo/ installation (resides at public_html/demo/)
Can you tell me where I can find the cookie that is supposed to be created with your code?
If it is supposed to be at public_html/demo/app/tmp/sessions, I see nothing there even after logging in. There is also nothing under public_html/demo/ other than standard CakePHP folders.
This is from my AppController for the /demo/ installation which is accessed via http://www.example.com/demo/ as opposed to the other installation which is at http://www.example.com/tst/
public $components = array(
//'DebugKit.Toolbar',
'Cookie',
'Session',
'Auth'=>array(
//Stuff
)
}
public function beforeFilter() {
//Logic placed here will run before the action is run
parent::beforeFilter();
$this->Cookie->path = '/demo/';
}
The core.php is set as default which is:
Configure::write('Session', array(
'defaults' => 'php'
));
You’ll need to restrict cookies in each of your applications to their respective sub-directories. For example, in your AppController.php you can do this in a beforeFilter() action:
<?php
class AppController extends Controller {
public $components = array(
'Cookie',
);
public function beforeFilter() {
parent::beforeFilter();
$this->Cookie->path = '/cakephp1/';
}
}
See http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#controller-setup for more details.
I had similar issue.
Use below code for first cakephp application in core.php / bootstrap.php
Configure::write('Security.cookie', 'cakephp1');
while in second cakephp application use the below code in core.php / bootstrap.php
Configure::write('Security.cookie', 'cakephp2');
Finally fixed my problem.
I had a session_start() php commandsomewhere in my code which overwrote all the core.php config, and basically it restored the php.ini session management settings.
CakePHP Session being written to /tmp/ and not /app/tmp/sessions/
Although there are answers that talk about cookies but don't mention about using Cake's own session or PHP's session. So, I thought it'd be good to share a documented way of achieving this.
CakePHP (at least 2.x), by default uses php session settings from php.ini.
The setting can be found in /app/Config/core.php and well documented there:
Configure::write('Session', array(
'defaults' => 'php' // possible values: php, cake, database, cache
));
For apps with own cake installation directory, it is as simple as changing the above value to cake which tells the app to use app/tmp/sessions for saving session files. It is imperative to mention that a different cookie name for each installation may be needed:
Configure::write('Session', array(
'defaults' => 'cake'
'cookie' => 'myApp1' // something like 'myApp2' for other app
));
Cookbook has good documentation on all settings related to sessions.
How can you set a default engine when using migrations (Schema Builder)? I recently got place on a shared hosting and their default MySQL engine is MyISAM. Instead of having to rewrite all my migration files to include $table->engine = 'InnoDB' I'm wondering if you can set this as default.
Is it possible?
I don't think it is,the docs http://laravel.com/docs/schema#storage-engines. Can't find any other mentioning of db engine in the docs.
You would expect it to be possible in app/config/database.php
I manage to do it. I'm using Laravel 5.5. In the config/database.php:
'connections' => [
'mysql' => [
...
'engine' => env('DB_ENGINE', null)
],
As you may know this will fetch the DB_ENGINE var from en .env file.
So in that file I setted like this:
DB_ENGINE=MyISAM
It will work if you set the var to InnoDB also.
I have created a modules folder in my Laravel app. There are two modules so far, but I'm just concentrating on core here.
I'm using Confide and Entrust to build User functionality, like so:
namespace App\Modules\Core;
use Zizaco\Confide\ConfideUser;
use Zizaco\Entrust\HasRole;
class User extends ConfideUser {
use HasRole;
}
and Permissions:
namespace App\Modules\Core;
use Zizaco\Entrust\EntrustPermission;
class Permission extends EntrustPermission
{
}
and Roles:
namespace App\Modules\Core;
use Zizaco\Entrust\EntrustRole;
class Role extends EntrustRole
{
}
My Composer.json autoload reads:
"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php",
"app/modules"
],
"psr-0": {
"App\\Modules\\": "modules/"
}
},
I put the psr-0 stuff in there because I couldn't get things to work. They still don't work, though the output autoload files when I run composer seem to have promising entries in them.
The database has been migrated, and now I'm trying to run the database seeding. My seeding script reads:
use App\Modules\Core\User;
use App\Modules\Core\Role;
use App\Modules\Core\Permission;
class UserTablesSeeder extends Seeder {
public function run()
{
DB::table('users')->insert(array(
'email' => 'xxx',
'first_name' => 'xxx',
'password' => 'xxxx',
'active' => 1
));
$admin = new Role;
$admin->name = 'Admin';
$admin->save();
$manageUsers = new Permission;
$manageUsers->name = 'manage_standard_users';
$manageUsers->display_name = 'Manage Users';
$manageUsers->save();
$admin->perms()->sync(array($manageUsers->id));
$user = User::where('email','=','xxx')->first();
$user->attachRole($admin);
}
}
But when I run php artisan db:seed I get an error:
PHP Fatal error: Class 'Permission' not found in /home/wedding/quincy/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 604
{"error":{"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","message":"Class 'Permission' not found","file":"\/home\/wedding\/quincy\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Eloquent\/Model.php","line":604}}
If I get rid of all the namespacing it all works just fine, but I think I should keep the namespaces because of the modularity I'm trying to create.
I've run composer dump-autoload, and install for when I added the psr-0 entry. So I'm not sure what else I need to do. I'm very new to composer, so at this point I'm lost as to what the problem is.
Thanks in advance.
Don't know if you found your answer.
I think you need to update your role and permission namespaced class names here:
File: vendor/entrust/config/config.php:
(Default is just "Role" and "Permission" without a namespace, so it doesn't work when you move your implementations into one).
You also have two other options:
add an alias for the fully namedspaced permission and role class on the app/config.php (Role => "Namespace").
there's a mechanism to override package config settings with appropriately named files. You can override just the two entries you need (the Role and Permission namespaces).
Confide and Entrust both are looking for Role and Permission model in global namespace. As you have changed namespace of both these models, Confide and Entrust are not able to find it. To solve this problem, you need to override Entrust configuration.
Create directory "app/config/packages/zizaco/entrust"
Copy file "vendor/zizaco/entrust/src/config/config.php" to "app/config/packages/zizaco/entrust/config.php"
Edit "app/config/packages/zizaco/entrust/config.php" and change following two lines
'role' => 'App\Modules\Core\Role',
'permission' => 'App\Modules\Core\Permission',
php artisan clear-compiled
php artisan optimize
You should rely on Laravel's packages (created thru Workbench, for instance) while developing localy.
Packages are the primary way of adding functionality to Laravel.
Workbench packages and their classes are handled automaticaly by Laravel - no need to configure anything.
More informations here: http://laravel.com/docs/packages
if you want to use your own modules instead of standard workbench packages, check out this article that depics how to achieve that:
http://creolab.hr/2013/05/modules-in-laravel-4/
summary by the author ( Boris Strahija ):
Laravel 4 is heavily based on composer packages, which is a good thing, but sometimes developers (like myself) like to separate their code into modules. This is especially nice when building larger projects. Now this was fairly easy to do in Laravel 3 with the bundles system, but in Laravel 4 many people just recommend building packages since L4 has a nice workbench feature. This is all good, but sometimes I like to separate my app specific controllers and views into modules, and not have to go through it with the workbench.
In short, you have to
put your modules code somwhere (for example /app/modules/)
include the directory in composer.json file, under autoload/classmap
create an appropriate service providers (Laravel 4 uses service providers to register and boot up the packages, you can use it with modules as well)
register the service providers - add them to app config in “app/config/app.php” under the providers array
So now we have out modules fully working. You can add module specific routes, group your controllers/views/models, get module configuration like this:
Config::get('content::channels');
Or get translated phrases like this:
Lang::get('shop::errors.no_items_in_cart');
Finally, to test your modules you can create some routes, but that is up to you how you use your code.
If you look at Doctrine composer.json, for example /vendor/doctrine/cache/composer.json:
"autoload": {
"psr-0": { "Doctrine\\Common\\Cache\\": "lib/" }
},
The files are located in:
/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ArrayCache.php
/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php
... and so on
By that logic, I think you should put your files in:
modules/App/Modules/Core/User.php
modules/App/Modules/Core/Permission.php
modules/App/Modules/Core/Role.php
From you screenshot the Permission class is located in the models folder so when you include your namespace you should type
use App\Modules\Core\Models\Permission;