Replace CodeIgniter Query builder - php

I'm trying to make my own implementation of the Query builder in codeigniter.
Basicly I would like to add some function and all the provided function. Something like :
$this-db->from('myTable')
->where('id', 1)
->custom_where('name', 'customsValues')
->get()
There values are irrelevent here.
I've already built a class that extends en current CI_DB_query_builder but I have no idea where to set my class to be used as the primary query builder. I've try to look up similar problem on google but could not find anything.
Any help would be appreciated.

I've found the answer to my question. However, any other good answer is welcome since mine is not the prettiest.
First let me walk you through what I was trying to do.
I wanted to use Tightenco's collect library to use collection rather than array. This way I could use more intuitive chain array function: $this->db->from('...')->results()->map(function($items) { ... })->toArray();
Then, i wanted to have my own function, such as where_if.
I started by making my own query builder class that extended from CI_DB_query_builder. I have an example below:
<?php
require BASEPATH . 'database/DB_query_builder.php';
class CustomQueryBuilder extends CI_DB_query_builder {
public function where_if($where, $value, $condition) : CustomQueryBuilder {
if($condition) {
$this->where($where, $value);
}
return $this;
}
public function results() : \Tightenco\Collect\Support\Collection {
return \Tightenco\Collect\Support\Collection::make($this->get()->result_array());
}
}
To link this class as the main Querybuilder, I had to change it in the file system/database/DB.php.
I changed the path of the require_once in line 171 :
require_once(APPPATH.'libraries/QueryBuilder/CustomQueryBuilder.php');
I also changed the alias class on line 182
class CI_DB extends CustomQueryBuilder { }
Please note that this is on codeigniter v3.0.6, your line number may differ.
Now, i needed to import some function so the autocomplete on PHPStorm would still point to my custom querybuilder, because once i used the function from, it returned a CI_DB_query_builder object.
Here is how I imported the function I used the most.
/**
* Nothing changed here, for autocompletion only
* #param mixed $from
* #return $this|CI_DB_query_builder
*/
public function from($from) {
parent::from($from);
return $this;
}
I really hope this helps people that are trying the same thing. If you got any feedback on this project, please let me know !

Related

How to add custom method to Laravel Query Builder [duplicate]

This question already has answers here:
How to customize Laravel's Database\Query\Builder (make better subquery)
(2 answers)
Closed 11 days ago.
I want to add custom methods for Laravel Query Builder.
I want to have something like this (Methods will be more complicated in further)
<?php
namespace App\Helpers;
class Builder extends \Illuminate\Database\Query\Builder
{
/**
* #return $this
*/
public function whenWhere(): self
{
return $this;
}
}
In code I have
DB::table('items')->select('id')->whenWhere()->get()
And I'm getting error
Call to undefined method Illuminate\\Database\\Query\\Builder::whenWhere()
I know there is a way to use macros in query providers, but I don't want use it because IDE don't see macros, so it is the main reason why I need to accomplish this in another way
*I'm not using models in project.
You can add public function with prefix scope:
public function scopeWhenWhere($query)
{
return $query->where('something', 'something');
}
It should let you call like this:
Builder::select(['column1', 'column2'])->whenWhere()->get();
Also you can extend the function with addition parameters:
public function scopeWhenWhere($query, $param)
{
return $query->where('something', $param);
}
Now you can put function param like this:
Builder::select(['column1', 'column2'])->whenWhere('ifsomething')->get();

In PHP/Laravel, what is the proper term for what "Model::class" is, given `return $this->belongsTo(Model::class);`

In this example code here:
public function user()
{
return $this->belongsTo(User::class);
}
public function sandwich()
{
return $this->belongsTo(Sandwich::class);
}
I want to know what User::class is called, because you could also write that above example like this:
public function user()
{
return $this->belongsTo(\App\User);
}
public function sandwich()
{
return $this->belongsTo(\App\Sandwich);
}
So I like that Laravel "just knows" where the model is when you use that syntax sugar, but what is it called? I'd like to read some documentation about it so I better understand what's happening behind the scenes.
It reminds me in some ways of "route model binding", so the answer that I would like is a link to the relevant docs page somewhere, or a term I can Google to understand what exactly is going on there.
The ::class syntax is class name resolution. This syntax returns the string representation of the fully qualified class name, including any namespace information otherwise omitted.
A couple of the benefits of this feature are 1. not needing to explicitly specify the fully qualified namespace of the class, and 2. being able to pass around the fully qualified namespace as a string while allowing an IDE to locate the class name when refactoring or searching for references.
I want to know what User::class is called
A wholesome name to call this is class name resolution. It combines both the PHP resolution operator :: and the class keyword. lt is not a Laravel syntax sugar but a PHP one.
It, in all situations, returns the Fully qualified name of the class which is simply a string containing the absolute/relative path of the class file - depending on the namespace of the file/class where it is used.
From the PHP Manual
... use ClassName::class to get a fully qualified name of class ClassName
On the other hand, from the Laravel use-case you mentioned
public function user()
{
return $this->belongsTo(User::class);
}
The Laravel Eloquent method belongsTo() and all similar methods specify that the parameter to be passed is a string. These methods resolve the string parameter to locate the model's class definition.
From the Laravel Docs
The first argument passed to the hasOne method is the name of the related model.
Therefore using
return $this->belongsTo('\App\User');
OR
return $this->belongsTo(User::class);
are syntactically equivalent. That means that the method definition are exactly the same and there is no parameter type checking as both parameters are string.
So I like that Laravel "just knows" where the model is when you use that syntax sugar.
Yeah, it just knows. But it is really straight forward. It uses the string parameter of the Eloquent method (now we know that regardless of the syntax, it is a String) and the provided Namespace of the current class to locate the model definition.
For instance this class definition
<?php
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}
is equivalent to
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne(Phone::class);
}
}
and also equivalent to
<?php
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne(App\Phone::class);
}
}
You will notice that the first and third examples do not need the namespace directive because they are using the Absolute path names.
Actually Laravel is not aware where the model is
If this example works:
public function user()
{
return $this->belongsTo(User::class);
}
It's becase probably the models lives in the same folder or Namespace if not you probably should to import the required model from other namespace like this.
//At the top of the file you will import the class
use Maybe\Another\Folder\Namespace\OtherObject;
public function user()
{
return $this->belongsTo(OtherObject::class);
}
if you don't want to "import" the object you should use the complete path to the class like this.
public function user()
{
return $this->belongsTo(App\OtherFolder\OtherObject::class);
}
In summary laravel doesn't know where to look for class definitions, but if you pass an instance in a param that would be resolved for the Service Container but this is another topic more related to the model binding
public function method(MyObject $instance)
{
//Laravel will try to automatically generate an instance of $instance
}

Use variable in php comment

I need to add $variable in my php return document
for example I have this function :
/**
* #return \Panel\Model\{$Service}
*/
public function getService($Service){
// I call service `foo` from Model folder
}
I see this post : What's the meaning of #var in php comments but it has no information about how to do it , and also study #var-phpdoc but that has nothing for me.
if you ask me why I should do that , because I want use phpStorm Ctrl+Click advantage on $this->getService('foo')->bar()
thanks in advance
As LazyOne said in the comments already PHP interfaces should solve your problem. You can 't use variables in PHPDoc formatted comments. Sure, if you use an IDE like PHPStorm with a plugin that enables the usage of variables in PHPDoc comments, the problem is solved for yourself. What, when other developers, which don 't use PHPStorm or the relevant plugin, want to work in the same project? In my view you should use php native functionality to solve your issue.
Here 's a short example how to use interfaces.
declare('strict_types=1');
namespace Application\Model;
interface ModelInterface
{
public function getFoo() : string;
public function setFoo() : ModelInterface;
}
The only thing you have to do now is using this interface with your models like in the following example.
declare('strict_types=1');
namespace Application\Model;
class FooModel implements ModelInterface
{
protected $foo = '';
public function getFoo() : string
{
return $this->foo;
}
public function setFoo(string $foo) : ModelInterface
{
$this->foo = $foo;
return $this;
}
}
As you can see the FooModel class implements the ModelInterface interface. So you have to use the methods declared in the interface in you model class. This means, that your getService Method could look like the following example.
/**
* Some getter function to get a model
* #return \Application\Model\ModelInterface
*/
public function getService($service) : ModelInterface
{
return $service->get(\Application\Model\Foo::class);
}
Your IDE knows now which methods the returned class can use. It allows you to use chaining and some more features. While typing your IDE should know now, that the returned class can use getFoo and setFoo methods. Further the setFoo methods enables comfortable chaining for calls like ..
// variable contains the string 'foo'
// your ide knows all methods
$fooString = $this->getService($serviceLocator)->setFoo('foo')->getFoo();
Are you using Symfony? Then you could use the Symfony plugin that solves this problem for you. For other frameworks, there should be similar solutions. If you use your own framework, you need to write such a plugin on your own, as PhpStorm can not resolve the given class otherwise.
I think what you are looking for is phpdoc.
https://docs.phpdoc.org/guides/docblocks.html
/**
* #param string $Service This is the description.
* #return \Panel\Model\{$Service}
*/
public function getService($Service){
// I call service `foo` from Model folder
}

Load and use Codeigniter model in non Codeigniter class

I was just wondering if there is a way to use codeigniter model in other non Codeigniter classes... Let me give you an example.
I have this MyTestClassTests class which extends PHPUNIT_Framework_testCase
<?php
require_once '../../vendor/autoload.php';
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Interactions\WebDriverActions;
use Sunra\PhpSimple\HtmlDomParser;
class MyTestClassTests extends PHPUnit_Framework_TestCase
{
public function testDoSomething()
{
// Do some test
// get results
// Store results via Codeigniter Model, if possible?
$results = 'some results';
$this->load->model('results');
$this->results->import($results);
}
}
Now once test is finished i would like to store test results in to the database. Is there a way to call/initialize CodeIgniter model in current class to use it and store data? This file is located in the Codeigniters controllers folder.
If you need any additional information's please let me know and i will provide. Thank you!
Since you appear to be unit testing you should consider using ci_phpunit-test which makes it much easier to use PHPUnit with CodeIgniter 3.x.
Because you're unit testing the following may not apply. These examples only work within an fully instantiated CI framework. Within that context there are a couple ways to give a stand-alone class access to the CI object.
One approach is to capture the CI instance in a class property.
class MyTestClassTests extends PHPUnit_Framework_TestCase
{
protected $CI;
public function __construct()
{
// Assign the CodeIgniter super-object
$this->CI = & get_instance();
}
public function testDoSomething()
{
// Do some test
// get results
// Store results via Codeigniter Model, if possible?
$results = 'some results';
//use the class property to access CI classes and methods
$this->CI->load->model('results');
$this->CI->results->import($results);
}
}
A second approach uses the PHP magic method __get. The advantage is it's much easier to write the code. The disadvantage is it's a tiny bit less efficient because extra code is executed each time you access the CI instance.
class MyTestClassTests extends PHPUnit_Framework_TestCase
{
/**
* Enables the use of CI super-global without having to define an extra variable.
*
* #param $var The CI property or method to access
* #return mixed
*/
public function __get($var)
{
return get_instance()->$var;
}
public function testDoSomething()
{
// Do some test
// get results
// Store results via Codeigniter Model, if possible?
$results = 'some results';
//you get to write code as if you were part of the CI object.
//IOW, you write code normally
$this->load->model('results');
$this->results->import($results);
}
}
In order to use codeigniter model in your non codeigniter class you have to instantiate CI first.
In your case below code will work.
$CI = & get_instance()
$CI->load->model('results');
$CI->results->your_function();

Laravel 4 Static Facades Setup in Packages

I'm playing around with packages and I'm able to my code to work (in my controllers) when I do this:
App::make('Assets')->js('bla');
Now I want to set up a static facade so I can do this:
Assets::js('bla');
for this and I'm getting errors. I've been following this blog entry and haven't had any trouble up to this point. But now I'm stuck with a " Call to undefined method" error.
I'm not sure what code you'd need to see, so here's everything: https://github.com/JoeCianflone/msl/tree/jc-working
Specifically here is my workbench: https://github.com/JoeCianflone/msl/tree/jc-working/workbench/Joecianflone/Assets
And here is the controller where I was messing around with it: https://github.com/JoeCianflone/msl/blob/jc-working/app/controllers/HomeController.php
Any help greatly appreciated.
Looks like it was an issue with namespacing, I got it working by changing this:
<?php namespace Joecianflone\Assets\Facades;
use Illuminate\Support\Facades\Facade;
class Assets extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Assets'; }
}
to this:
class Assets extends \Illuminate\Support\Facades\Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Joecianflone\Assets\Assets'; }
}
What I'm not sure about is why the code from the tutorial worked but mine didn't. I must have skipped a step.
Just a sidenote, if you plan to share your code with the communuty (please do) i encourage you to use 5.3 syntax. Laravel requirements is 5.3 so dont use 5.4 in your package.

Categories