Laravel 4 - Extend Pagination Class - laravel

Is there a way to extend the Pagination Class of Laravel 4 ?
I tried some things but nothing good...
I'm here :
PaginationServiceProvider.php
class PaginationServiceProvider extends \Illuminate\Pagination\PaginationServiceProvider {
/**
* Indicates if loading of the provider is deferred.
* #var bool
*/
protected $defer = false;
/**
* Bootstrap the application events.
* #return void
*/
public function boot(){
$this->package('thujohn/pagination');
}
/**
* Register the service provider.
* #return void
*/
public function register(){
$this->app['paginator'] = $this->app->share(function($app){
$paginator = new Environment($app['request'], $app['view'], $app['translator']);
$paginator->setViewName($app['config']['view.pagination']);
return $paginator;
});
}
/**
* Get the services provided by the provider.
* #return array
*/
public function provides(){
return array();
}
}
Environment.php
class Environment extends \Illuminate\Pagination\Environment {
public function hello(){
return 'hello';
}
}
I replaced 'Illuminate\Pagination\PaginationServiceProvider', by 'Thujohn\Pagination\PaginationServiceProvider',
When I call $test->links() it's ok
When I call $test->hello() it fails
When I call Paginator::hello() it's ok
Any idea ?

Everyting is fine except that Paginator::make() returns Paginator instance, not Environment.
You should move Your method to Paginator class.
Today I've posted on GH my extension for Paginator. You can check it as a reference desmart/pagination

Related

How can I test a method being called once

Basically I want to test that when I call a method 2 times another method is called once but I get the following Exception:
Mockery\Exception\BadMethodCallException : Received
Mockery_0_App_Repository_DimensionRepository::getThinClientDimension(),
but no expectations were specified
My test is as follows
class HostRepositoryTest extends TestCase
{
/**
* #var HostRepository
*/
private $hostRepository;
/**
* #var Dimension
*/
private $dimension;
public function setUp(): void
{
parent::setUp();
$this->dimension = new Dimension();
$mockDimensionRepository = Mockery::mock(DimensionRepository::class);
$mockDimensionRepository->shouldReceive('getDimensionByName')
->once()
->andReturn($this->dimension);
$this->hostRepository = new HostRepository($mockDimensionRepository);
}
/**
* Test lazy loading dimension retrieval
*/
public function testGetThinClientDimension()
{
$this->hostRepository->getEnvironmentsHostList([]);
$this->hostRepository->getEnvironmentsHostList([]);
}
}
HostRepository:
[...]
/**
* #param $configurationIds
* #return Host[]|Collection
*/
public function getEnvironmentsHostList($configurationIds)
{
//dd('test'); If I uncomment this it will be executed in the test
$hostDimension = $this->dimensionRepository->getThinClientDimension();
dd($hostDimension); // This is not executed if the test is ran
//Returns an entity through Eloquent ORM
[...]
}
DimensionRepositoy:
class DimensionRepository
{
private $thinClientDimension;
const THINCLIENT = 'ThinclientId';
[...]
public function getDimensionByName($name)
{
return Dimension::where(['Name' => $name])->firstOrFail();
}
/**
* Lazy load Thinclient dimension
* #return Dimension
*/
public function getThinClientDimension()
{
dd('test'); // This part is not executed when running the test which I find weird
if ($this->thinClientDimension === NULL) {
$this->thinClientDimension
= $this->getDimensionByName(self::THINCLIENT);
}
return $this->thinClientDimension;
}
[...]
Update:
It seems that when I call $this->dimensionRepository->getThinClientDimension() (in getEnvironmentsHostList) the exception is thrown.
Seems I have to mock this as well (getThinClientDimension) which would make my test useless because as you can see it delegates the call to the mocked method getDimensionByName...
Apparently the fix was to use makePartial() when mocking the object
public function setUp(): void
{
parent::setUp();
$this->dimension = self::getDimension();
$this->mockDimensionRepository = $this->mock(DimensionRepository::class)->makePartial();
$this->hostRepository = new HostRepository($this->mockDimensionRepository);
}
LegacyMockInterface
/**
* Set mock to defer unexpected methods to its parent if possible
*
* #return Mock
*/
public function makePartial();
Seems that this modifier tells Mockery it can call other methods that are not mocked (which should be by default in my opinion)

Laravel mass update , still fire event

As stated in the doc, laravel will not fire an event on mass update/insert/delete.
https://laravel.com/docs/5.8/eloquent#events
It uses the Builder for this and will not fire an event.
Is there a way that I can still fire an event after a mass update for example? I would only need the query Builder to extract the needed info myself ( log purposes).
It is actually possible , but you have to extend the Eloquent builder ,overwrite the update/insert methods and send the event there.
Just been playing around with it... Needs work, but the basic idea is the following :
class Test extends Model
{
protected $guarded = [];
public $dispatchesEvents = [
'saved' => SavedTest::class
];
/**
* INCLUDE this as a trait in your model.
* Overwrite the eloquentBuilder.
*
* #param \Illuminate\Database\Query\Builder $query
* #return \Illuminate\Database\Eloquent\Builder|static
*/
public function newEloquentBuilder($query)
{
return new TestBuilder($query);
}
}
Extend the eloquent builder...
class TestBuilder extends Builder
{
/**
* Update a record in the database and fire event.
*
* #param array $values
* #return int
*/
public function update(array $values)
{
// normal eloquent behavior.
$result =$this->toBase()->update($this->addUpdatedAtColumn($values));
/*
* Fire event.
*/
if($result){
if( $event = Arr::get($this->model->dispatchesEvents,'saved')){
// at the attributes.
$this->model->fill($this->addUpdatedAtColumn($values));
$queryBuilder =$this->toBase();
event(new $event($this->model,$queryBuilder));
}
}
}
public function insert(array $values)
{
// same idea..
}
}
The event class :
class SavedTest
{
use SerializesModels;
public $model;
public $query;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($model,$query =null)
{
$this->model = $model;
$this->query = $query;
}
}
The listener.
class SavedTestEvent
{
/**
* Create the event listener.
*
*
*/
public function __construct()
{
}
/**
* Handle the event.
*
* #param object $event
* #return void
*/
public function handle($event)
{
// The model , with the attributes.
dump($event->model);
// the query builder , you could extract the wheres or whatever to build your own log for it.
dump($event->query);
}
}
#Paolo on batch request it would not be file the event you must have to perform operation on single record.. like
Analytic::where('id', '>', 100)->get()->each(function($analytic) {
$analytic->delete();
});

How to auto add id on form?

Add id manually looks like this
{!! Form::text('email', null, ['id' => 'email', 'class' => 'active']) !!}
How to auto add id?
Any example to use macro?
Create your new FromBuilder Class :
class MyFormBuilder extends \Collective\Html\FormBuilder /** Original Form Builder*/{
// Override the text function
public function text($name, $value = null, $options = []){
// If the ID is not explicitly defined in the call
if(!isset($options['id'])){
// Set ID equal to the name
$options['id'] = $name;
}
// Call the original text function with the new ID set
parent::text($name,$value,$options);
}
}
Then Create a new Service Provider
<?php
namespace My\Provider\Space;
use Illuminate\Support\ServiceProvider;
class MyHtmlServiceProvider 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->registerHtmlBuilder();
$this->registerFormBuilder();
$this->app->alias('html', 'Collective\Html\HtmlBuilder');
$this->app->alias('form', 'My\Class\Space\MyFormBuilder');
}
/**
* Register the HTML builder instance.
*
* #return void
*/
protected function registerHtmlBuilder()
{
$this->app->singleton('html', function ($app) {
return new \Collective\Html\HtmlBuilder($app['url'], $app['view']);
});
}
/**
* Register the form builder instance.
*
* #return void
*/
protected function registerFormBuilder()
{
$this->app->singleton('form', function ($app) {
$form = new \My\Class\Space\MyFormBuilder($app['html'], $app['url'], $app['view'], $app['session.store']->getToken());
return $form->setSessionStore($app['session.store']);
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return ['html', 'form', 'Collective\Html\HtmlBuilder', 'My\Class\Space\FormBuilder'];
}
}
Then update your config/app.php file and do:
Remove The old \Collective\Html\HtmlServiceProvider::class from the service providers array
Add Your new Service provider in it's place.
A basic explanation of what this does:
A. You move the service provider for the HTML helpers to your own service provider where you register your MyBuilder
B. Next time you call \Form that service provider will point it to your builder.
Check out the vendor files for collective to make sure you get all the variables in the function definitions.
Just filter out any namespace errors etc. as I have not completely tested them all.

Laravel5 extend Facade

I want to extend Laravel5 Cookies functionality.
I want to make it this way:
I will create file App\Support\Facades\Cookie.php and than file App\Libraries\CookieJar.php. In app.php I will change row for Cookie to this:
'Cookie' => 'App\Support\Facades\Cookie',
Anyway, when I try to use it like this:
Cookie::test()
it returns:
Call to undefined method Illuminate\Cookie\CookieJar::test()
Do you have any idea, why it do this? And is the way, how I want to extend Cookie functionality good?
Thank you for your help.
Here is content of files:
Cookie.php:
<?php namespace App\Support\Facades;
/**
* #see \App\Libraries\CookieJar
*/
class Cookie extends \Illuminate\Support\Facades\Facade
{
/**
* Determine if a cookie exists on the request.
*
* #param string $key
* #return bool
*/
public static function has($key)
{
return !is_null(static::$app['request']->cookie($key, null));
}
/**
* Retrieve a cookie from the request.
*
* #param string $key
* #param mixed $default
* #return string
*/
public static function get($key = null, $default = null)
{
return static::$app['request']->cookie($key, $default);
}
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'cookie';
}
}
CookieJar.php:
<?php namespace App\Libraries;
class CookieJar extends \Illuminate\Cookie\CookieJar
{
public function test() {
return 'shit';
}
}
The class with all your new cookie functions need to extend Illuminate\CookieJar\CookieJar
<?php
namespace App\Support\Cookie;
class CookieJar extends \Illuminate\Cookie\CookieJar
{
/**
* Determine if a cookie exists on the request.
*
* #param string $key
* #return bool
*/
public static function has($key)
{
return !is_null(static::$app['request']->cookie($key, null));
}
/**
* Retrieve a cookie from the request.
*
* #param string $key
* #param mixed $default
* #return string
*/
public static function get($key = null, $default = null)
{
return static::$app['request']->cookie($key, $default);
}
}
Then make a new facade:
namespace App\Support\Facades;
class CookieFacade extends \Illuminate\Support\Facades\Facade
{
protected static function getFacadeAccessor()
{
/*
* You can't call it cookie or else it will clash with
* the original cookie class in the container.
*/
return 'NewCookie';
}
}
Now bing it in the container:
$this->app->bind("NewCookie", function() {
$this->app->make("App\\Support\\Cookie\\CookieJar");
});
Finally add the alias in your app.php config:
'NewCookie' => App\Support\Facades\CookieFacade::class
Now you can use NewCookie::get('cookie') and NewCookie::has('cookie').
I hope this helps.

How can we override cache_set() in drupal 7

I have a drupal 7 application. I need to block the insertion of cache in cache_form table. So how can we override cache_set() in drupal 7?
You can't override cache_set(), what you can do is use a custom cache backend for the cache_form cache bin. If you don't want to cache anything for cache_form, you can use a simple implementation whose methods do nothing.
class DoNothingCache extends DrupalCacheInterface {
/**
* {#inheritdoc}
*/
function get($cid) {
return FALSE;
}
/**
* {#inheritdoc}
*/
function getMultiple(&$cids) {
return array();
}
/**
* {#inheritdoc}
*/
function set($cid, $data, $expire = CACHE_PERMANENT) {}
/**
* {#inheritdoc}
*/
function clear($cid = NULL, $wildcard = FALSE) {}
/**
* {#inheritdoc}
*/
function isEmpty() {
return TRUE;
}
}
The cache_class_cache_form configuration variable defines the class, implementing the DrupalCacheInterface interface, to use for the cache_form bin. You can set it in your settings.php file.
$conf['cache_class_cache_form'] = 'DoNothingCache';

Resources