I am having problems with a composer package I am dealing with. It implements a trait Billable.
trait Billable
{
/**
* Update the payment method token for all of the user's subscriptions.
*
* #param string $token
* #return void
*/
protected function updateSubscriptionsToPaymentMethod($token)
{
foreach ($this->subscriptions as $subscription) {
if ($subscription->active()) {
BraintreeSubscription::update($subscription->braintree_id, [
'paymentMethodToken' => $token,
]);
}
}
}
}
I am trying to override this method in my class
class Organisation extends Model
{
use Billable;
/**
* Update the payment method token for all of the user's subscriptions.
*
* #param string $token
* #return void
*/
protected function updateSubscriptionsToPaymentMethod($token)
{
foreach ($this->subscriptions as $subscription) {
if ($subscription->active()) {
BrntreeSubscription::update($subscription->braintree_id, [
'paymentMethodToken' => $token,
]);
}
}
}
}
But the method is not overridden. As a test I overrode some of the public functions and they work fine, it this a limitation of traits? I have tried to find the answer online but have come up short.
I am trying to override this function because I need to customize the behaviour of the BraintreeSubscription class.
Any help would be greatly appreciated.
in your class you could do the following notice the T before the function name you may change this to be aliased as anything really.
use billable {
updateSubscriptionsToPaymentMethod as tUpdateSubscriptionsToPaymentMethod;
}
then simply in the class add the desired function:
public function updateSubscriptionsToPaymentMethod(){
...
}
Related
Hello friends i have modified password reset table column name 'created_at' instead of 'created'. if i am changing column name 'created' on migration, But i am getting the error column not found 'created_at'.
\vendor\laravel\framework\src\Illuminate\Auth\Passwords\DatabaseTokenRepository.php
protected function getPayload($email, $token)
{
return ['email' => $email, 'token' => $token, 'created_at' => new Carbon];
}
this is the file coming from column name 'created_at' where i can override this function please suggest me..
I think I've found a way to do this without touching the vendor directory.
For Laravel 5.2
Create a class that extends Illuminate\Auth\Passwords\DatabaseTokenRepository
Overwrite the getPayload() method there
Create a class that extends Illuminate\Auth\Passwords\PasswordBrokerManager
Overwrite the resolve() method to return a new PasswordBroker with your token repository from step 1
Open config/app.php and comment out PasswordResetServiceProvider from the providers array
In your app service provider register an instance of your password broker manager from step 3
$this->app->singleton('auth.password', function ($app) {
return new YourPasswordBrokerManager($app);
});
$this->app->bind('auth.password.broker', function ($app) {
return $app->make('auth.password')->broker();
});
For Lravel 5
Create a class that extends Illuminate\Auth\Passwords\DatabaseTokenRepository
Overwrite the getPayload() method there
Create a class that extends Illuminate\Auth\Passwords\PasswordResetServiceProvider
Overwrite the registerTokenRepository() to return your repository from step 1
Open config/app.php and comment out PasswordResetServiceProvider from the providers array
Add your provider from step 3 to the providers array
Please note that I haven't tested this, but it should work on theory.
Solved: I applied the 5.2 steps in my Laravel 5.4 project:
ForgotPasswordHelperRepository.php
<?PHP
namespace App\Helpers;
use Carbon\Carbon;
class ForgotPasswordHelperRepository extends \Illuminate\Auth\Passwords\DatabaseTokenRepository
{
/**
* Build the record payload for the table.
* I wanted to add an extra column organization_id
* organizationId() is a helper method I created
* #param string $email
* #param string $token
* #return array
*/
protected function getPayload($email, $token)
{
return ['email' => $email, 'token' => $this->hasher->make($token), 'created_at' => new Carbon,'organization_id' => organizationId()];
}
}
PasswordBrokerManagerHeler.php
<?PHP
namespace App\Helpers;
use Closure;
use Illuminate\Auth\Passwords\DatabaseTokenRepository;
use Illuminate\Auth\Passwords\PasswordBroker;
use Illuminate\Support\Str;
class PasswordBrokerManagerHelper extends \Illuminate\Auth\Passwords\PasswordBrokerManager
{
/**
* #inheritDoc
*/
public function sendResetLink(array $credentials)
{
// TODO: Implement sendResetLink() method.
}
/**
* #inheritDoc
*/
public function reset(array $credentials, Closure $callback)
{
// TODO: Implement reset() method.
}
/**
* #inheritDoc
*/
public function validator(Closure $callback)
{
// TODO: Implement validator() method.
}
/**
* #inheritDoc
*/
public function validateNewPassword(array $credentials)
{
// TODO: Implement validateNewPassword() method.
}
/**
* Resolve the given broker.
*
* #param string $name
* #return \Illuminate\Contracts\Auth\PasswordBroker
*
* #throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new \InvalidArgumentException("Password resetter [{$name}] is not defined.");
}
// The password broker uses a token repository to validate tokens and send user
// password e-mails, as well as validating that password reset process as an
// aggregate service of sorts providing a convenient interface for resets.
return new PasswordBroker(
$this->createTokenRepository($config),
$this->app['auth']->createUserProvider($config['provider'])
);
}
protected function createTokenRepository(array $config)
{
$key = $this->app['config']['app.key'];
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$connection = isset($config['connection']) ? $config['connection'] : null;
// return new DatabaseTokenRepository(
return new ForgotPasswordHelperRepository(
$this->app['db']->connection($connection),
$this->app['hash'],
$config['table'],
$key,
$config['expire']
);
}
}
Next, just copy and paste the following in the AppServiceProvider#register method
$this->app->singleton('auth.password', function ($app) { return new PasswordBrokerManagerHelper($app); });
$this->app->bind('auth.password.broker', function ($app) { return $app->make('auth.password')->broker(); });
I've been following the Laravel Authorization docs trying to build "is the user allowed to do this" functionality by using Policies, but I can't get it to work. I keep getting This action is unauthorized and I've tried with route middleware too.
PagePolicy.php:
namespace App\Policies;
use App\Models\User;
use App\Models\Page;
use Illuminate\Auth\Access\HandlesAuthorization;
class PagePolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function view(User $user, Page $page)
{
return $user->id === $page->user_id;
}
/**
* Determine whether the user can create pages.
*
* #param App\Models\User $user
* #return mixed
*/
public function create(User $user)
{
}
/**
* Determine whether the user can update the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function update(User $user, Page $page)
{
//
}
/**
* Determine whether the user can delete the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function delete(User $user, Page $page)
{
//
}
}
PageController.php:
namespace App\Http\Controllers;
use Auth;
use Carbon\Carbon;
use App\Models\Page;
use App\Http\Requests\PageRequest;
class PageController extends ApiController
{
public function createNewPage(PageRequest $request)
{
$this->authorize('create', Page::class);
$request->merge([
'user_id' => Auth::id(),
'published_at' => Carbon::now(),
]);
if (Page::create($request->all())) {
return response()->json('success', 201);
}
return response()->json('error', 500);
}
}
AuthServiceProvidor.php:
namespace App\Providers;
use App\Models\Page;
use App\Policies\PagePolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
Page::class => PagePolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
I managed to figure it out. I wasn't using Route Model Binding. So I added authorize() after the page call and used the $page variable instead of Page::class.
public function update(PageUpdateRequest $request, $pageSlug)
{
$page = Page::where(['user_id' => Auth::id(), 'slug' => $pageSlug])->first();
$this->authorize('update', $page);
$page->update($request->all());
return fractal()->item($page, new PageTransformer())->toArray();
}
It's not totally clear to me which action you're attempting to authorize since you've provided the call to create in the controller but only provided a policy check in place for viewing a page. Having said that, I would be sure to var_dump/dd the values you're attempting to do a type comparison of to verify they're of the same type. If anything's been explicitly cast, it may cause issues with certain database drivers that return integers as strings.
I think the problem is not in your policies, rather in your PageRequest class. Make sure the authorize() method in your App\Http\Requests\PageRequest class returns true .
class PageRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true; // you can also check the authorization using PagePolicy here
}
}
Current code:
protected $policies = [
Task::class => TaskPolicy::class,
];
Solution code:
protected $policies = [
'App\Task' => 'App\Policies\TaskPolicy',
];
I experienced the same problem, while following the Intermediate Task List Tutorial on the Laravel website.
The solution is actually present in the Github code for this tutorial.
I want to override a method (isValidatable) in the Illuminate\Validation\Validator class. I have done this by creating a class (outside Illuminate) that extends the Validator and only overrides the isValidatable method.
I think this will work, except I'm not sure how to create the service provider for the Validator class (or actually CustomLaravelValidator class). I have created service providers before, but there seems to be going on a lot inside the Validator serviceprovider (Illuminate\Validation\ValidationServiceProvider). Therefore I don't have a clue on how my custom service provider for this class should look like.
This is my CustomLaravelValidator class:
<?php namespace API\Extensions\Core;
use Illuminate\Validation\Validator;
class CustomLaravelValidator extends Validator {
/**
* Determine if the attribute is validatable.
*
* #param string $rule
* #param string $attribute
* #param mixed $value
* #return bool
*/
protected function isValidatable($rule, $attribute, $value)
{
// Validate integers on empty strings as well
if($rule == 'IntStrict')
{
return true;
}
return $this->presentOrRuleIsImplicit($rule, $attribute, $value) &&
$this->passesOptionalCheck($attribute);
}
}
This is the default ValidationServiceProvider from Laravel:
<?php namespace Illuminate\Validation;
use Illuminate\Support\ServiceProvider;
class ValidationServiceProvider extends ServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->registerPresenceVerifier();
$this->app->bindShared('validator', function($app)
{
$validator = new Factory($app['translator'], $app);
// The validation presence verifier is responsible for determining the existence
// of values in a given data collection, typically a relational database or
// other persistent data stores. And it is used to check for uniqueness.
if (isset($app['validation.presence']))
{
$validator->setPresenceVerifier($app['validation.presence']);
}
return $validator;
});
}
/**
* Register the database presence verifier.
*
* #return void
*/
protected function registerPresenceVerifier()
{
$this->app->bindShared('validation.presence', function($app)
{
return new DatabasePresenceVerifier($app['db']);
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array('validator', 'validation.presence');
}
}
Can anyone tell me how my custom serviceprovider have to look like?
Your service provider doesn't need to mimic the native Validator service provider. You just need to register your custom validator using the resolver method on the validator factory.
use API\Extensions\Core\CustomLaravelValidator;
class CustomValidationServiceProvider extends ServiceProvider {
public function boot()
{
$this->app['validator']
->resolver(function($translator, $data, $rules, $messages)
{
return new CustomLaravelValidator(
$translator,
$data,
$rules,
$messages
);
});
}
}
That's it...
I have a hook that gets successfully called
class tx_srfeuserregister_MyHooksHandler {
public function registrationProcess_afterSaveCreate ($recordArray, &$invokingObj) {
var_dump($recordArray); //i get here
}
}
thanks to being registered in the sr_feuser_register/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['sr_feuser_register']['tx_srfeuserregister_pi1']['registrationProcess'][] = 'EXT:sr_feuser_register/hooks/class.tx_srfeuserregister_MyHooksHandler.php:&tx_srfeuserregister_MyHooksHandler';
To do useful things here, and without copy/pasting code, I'd like to call a service method from an extbase service that is located in another extension
typo3conf/ext/my_extension/Classes/Domain/Service/Tx_MyExtension_Domain_Service_EntityFactory.php
How do I inject that into my hook, or get it through the object factory? I've tried a couple of things and googled a lot, but could not figure it out.
I suggest you get an instance of the extbase object manager, get your service and call your method. Something like this:
/**
* #var Tx_Extbase_Object_ObjectManager
*/
protected $objectManager;
/**
* #var Tx_MyExt_Service_MyService
*/
protected $myService;
public function registrationProcess_afterSaveCreate ($recordArray, &$invokingObj) {
$this->initializeObjects();
// Now you can use your Service.
$this->myService->myMethod($recordArray);
}
/**
* #return void
*/
public function initializeObjects() {
if (empty($this->objectManager)) {
$this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
}
if (empty($this->myService)) {
$this->myService = $this->objectManager->get('Tx_MyExt_Service_MyService');
}
}
When I programmed in ASP.NET MVC, there was a neat pattern called Repository. I want to implment it in Codeigniter but I do not know how. Here is what I actually want:
$mock_repository = new MockRepository();
$mock_repository->add(new Item(‘title1′, ‘description1′, 1));
$mock_repository->add(new Item(‘title2′, ‘description2′, 2));
$mock_repository->add(new Item(‘title3′, ‘description3′, 1));
$controller = new Item_controller($mock_repository);
$items = $controller->get_items_by_user_id(1);
$this->_assert_equals(count($items), 2);
I am using TOAST for Unit Testing. So how do I instantiate a controller within a test? The test is of course, another controller itself.
From what I know, to create a Generic Repository Pattern like in C#, you need 2 things PHP 5.6 dosen't have:
Real Method Overloading.
Generic Interface or Generic Abstract Class in PHP.
Click here for more on Generic Repository Pattern in C#.
However you can still create pseudo method overloading in PHP with the help of magic method __call, and we can type little more code for the generic part of the pattern.
Note: Before creating this pattern in Codeigniter 3.0 you will need to create a table in the database, and create auto loader for folder application/libraries.
First we need to create Interface in application/libraries folder:
<?php
interface IRepository
{
public function getById($id);
public function select($columns);
public function delete($id);
}
Seconde we need to create Abstract Class implementing the Interface and extending the CI_Model to be able to use the Database librarie:
<?php
abstract class Base_repository extends CI_Model implements IRepository
{
/**
* This must be valid table name in the Database.
*
* #var string $table Name of the table.
*/
protected $table;
public function __construct()
{
parent::__construct();
}
/**
* Pseudo method overloading.
* It's called when method is not declared in the abstract class.
*
* #param string $name Name of the method
* #param mixed $arguments Arguments of the method
*/
public function __call($name, $arguments)
{
switch ($name)
{
case 'save':
if ($arguments[0]->id > 0)
{
$this->update($arguments[0]);
}
else
{
$this->insert($arguments[0]);
}
break;
}
}
/**
* Get row with id.
*
* #param integer $id
* #return mixed
*/
public function getById($id)
{
return $this->db->get_where($this->table, ['id' => $id])->row_array();
}
/**
* Select columns.
*
* #param array $columns
* #return mixed
*/
public function select($columns = ['*'])
{
$this->db->select($columns);
return $this->db->get($this->table)->result();
}
/**
* Insert data.
*
* #param object $item
* #return void
*/
private function insert($item)
{
unset($item->id);
$this->db->insert($this->table, $item);
}
/**
* Update data.
*
* #param object $item
* #return void
*/
private function update($item)
{
$this->db->where('id =', $item->id);
unset($item->id);
$this->db->update($this->table, $item);
}
/**
* Delete data.
*
* #param integer $id
* #return void
*/
public function delete($id)
{
$this->db->delete($this->table, ['id' => $id]);
}
}
Third test the repository. Make a new model in application/model, and extend Base_repository, set table name and overload save method, create entity for this model:
<?php
/**
* The entity class.
*/
class Test
{
public $id;
public $info;
}
class Test_model extends Base_repository
{
/**
* Tell what table we are using.
*/
public function __construct()
{
parent::__construct();
$this->table = 'test';
}
/**
* "Overload" save method and call it from the parent.
*
* #param test $item Make use of the Dependency Injection.
* #return void
*/
public function save(Test $item)
{
parent::save($item);
}
}
Try it in the controller. Load the model and try to get, insert, ect...
To create real models is the same procedure. If you need to add more methods that will be the same for every model add them in the abstract class if you need to create methods only for specific model add it only in this model.
I don't recommend Codeigniter freamwork. Here are some patterns for PHP CLICK!
You would have to completely hijack the system files to load a controller from another controller. It can't be done, methinks.
It can be done with HMVC.
$result = Modules::run('controller/get_items_by_user_id', $params);
$this->_assert_equals($result, $expected);