How we setup cakephp without database? - cakephp-2.1

In few project we don't need database, so how we setup cakephp on local machine without modification in database config? Right now what I done ...I created database and modified config file. But my database has no table, its just wastage of database....so please suggest better way to do this.
Thank you in advance..

With CakePHP 2.3.x I simply use an empty string as a datasource in the database configuration and it works fine.
The database configuration (app/Config/database.php) is almost empty, it looks like this:
class DATABASE_CONFIG {
public $default = array(
'datasource' => '',
);
}
You have to tell your AppModel not to use DB tables, otherwise you'll get an error: "Datasource class could not be found". It's not enough to set the $useTables in descendant models only.
class AppModel extends Model {
public $useTable = false;
}
I dindn't experienced any problems with that yet.

Cakephp actually try to connect to a database no matter that you don’t use a table
so using this
class MyModel extends AppModel {
public $useTable = false;
}
it will be just a mistake , creating application on cakephp is piece of cake. Here are some steps you have to do in order to start developing without a database.
Create fake dbo source
Create file DboFakeDboSource.php in app/Model/Datasource/Dbo/ and put the following code in it
class DboFakeDboSource extends DboSource {
function connect() {
$this->connected = true;
return $this->connected;
}
function disconnect() {
$this->connected = false;
return !$this->connected;
}
}
Set the default connection
The next step is to tell cakephp to use dbo source by default. Go and change default connection in database.php to be like this
var $default = array(
'driver' => 'FakeDboSource'
);
Fine tuning the model
The third step is to be sure that $useTable = false; is included in every model, so add it in AppModel.php

You can just leave default datasourse settings empty in database.php and for Models you use, specify that it doesn't need corresponding table in DB like following:
class MyModel extends AppModel {
public $useTable = false;
}

Related

Attempt to read property “client_id” on null using laravel

When i run db seed command on terminal but unfortunatly i get error Attempt to read property client_id on null please help me how can i resolve that ? thank u
Contractor model
class Contractor extends Model
{
protected static function booted() {
static::creating(function ($model) {
$model->client_id = auth()->user()->client_id;
});
}
}
There is not any authenticated user when you run the database seeders. so you have to make the user in your factory or authenticate the fake user in your database seeder
During seeders, there's no auth()->user().
The most simple fix would be probably this:
$model->client_id = auth()->user()?->client_id;
It will work with PHP 8, from what I remember.
Or, if not, just add if (auth()->check()) before adding this line.

How can I add extra view component class paths in Laravel?

The problem
The default namespace for view components is App\View\Components with the folder being app/View/Components. I am setting up a DDD file structure and wish to do two things:
Move "shared" view components to a namespace and folder of App\ViewComponents and src/app/ViewComponents respectively
Have view components specific to individual "apps" with their own namespace and folder of App\MyApplication\ViewComponents and /src/app/MyApplication/ViewComponets respectively.
The new App namespace/folder setup is done via composer psr-4 autoload keys and works fine. But Laravel always used the App\View\Components namespace when trying to load components.
My attempt
I have solved the first part of my problem, but I am hoping that there is a better way. For instance when I want to move views, I can just set the view.paths config directive in my AppServiceProvider but I don't see a similar way of, essentially, adding namespaces to where Laravel looks for view components. So what I ended up doing was:
Create a ViewServiceProvider class, extending Illuminate\View\ViewServiceProvider::class and point to it in bootstrap/app.php instead
In there, override the registerBladeEngine method, in there pointing towards my own BladeCompiler class instead of the built-in one
public function registerBladeEngine($resolver)
{
// The Compiler engine requires an instance of the CompilerInterface, which in
// this case will be the Blade compiler, so we'll first create the compiler
// instance to pass into the engine so it can compile the views properly.
$this->app->singleton('blade.compiler', function () {
return new BladeCompiler(
$this->app['files'],
$this->app['config']['view.compiled'],
);
});
$resolver->register('blade', function () {
return new CompilerEngine(
$this->app['blade.compiler']
);
});
}
In my own BladeCompiler class, which extends Illuminate\View\Compilers\BladeCompiler, override the component() and compileComponentTags() methods - basically anywhere that referenced View\\Components - with pretty much a carbon copy but instead using ViewComponents and also made sure that where they return a Illuminate\View\Compilers\ComponentTagCompiler I instead referenced my own ComponentTagCompiler
In my own TagCompiler I override the guessClassName() method, again with essentially a carbon copy, just renaming View\\Components to ViewComponents
As you can see, that's quite a lot of work just to change the path. And I also want to add another path. Multiple "apps" run under the same Laravel codebase, so for instance we might have App\Website\, App\Admin and App\Blog and, depending on which app is currently running, load a different namespace for the running app, i.e. the blog would be App\Blog\ViewComponents pointing to src/app/Blog/ViewComponents.
Is there a way to achieve this without as much overriding as above? If not, can you suggest a way to achieve the second part of the requirement?
Note: I haven't ruled out using sub folders and continuing with everything under the main App\View\Components namespace just yet - I don't want to fight Laravel more than I have to and am willing to concede if there's no better way, but if I can achieve the folder structure I want it would feel a lot tidier.
Update; got a working implementation by using a configuration and php 8 annotations
Follow the steps below to make it possible to add more lookup folders for the blade view components feature, based on your question and details you have provided. It would have helped to have posted that code you already had. But I have added a possible solution to get it to work, using Annotations and using a config with a namespace/path map.
Depending on how you switch between one application and the other, from which the details are not provided in your question, you have to modify the way the configuration is retreived in the MyComponentTagCompiler class.
Blade compiler
In order to change the ComponentTagCompiler we need to change the BladeCompiler class:
namespace App;
class YourBladeCompiler extends \Illuminate\View\Compilers\BladeCompiler
{
protected function compileComponentTags($value)
{
if (! $this->compilesComponentTags) {
return $value;
}
return (new \App\MyComponentTagCompiler( //it is about this line
$this->classComponentAliases, $this->classComponentNamespaces, $this
))->compile($value);
}
}
Service provider
Now register the YourBladeCompiler in YourViewServiceProvider :
class YourViewServiceProvider extends \Illuminate\View\ViewServiceProvider
{
public function registerBladeEngine($resolver)
{
$this->app->singleton('blade.compiler', function () {
return new \App\YourBladeCompiler( //it is about this line
$this->app['files'],
$this->app['config']['view.compiled'],
);
});
$resolver->register('blade', function () {
return new CompilerEngine(
$this->app['blade.compiler']
);
});
}
}
MyComponentTagCompiler
This is an implemention I created that works with PHP 8 Attributes, given below:
namespace App;
#[\Attribute]
class ViewComponentName
{
public string $name;
public string $package;
public function __construct(string $name, string $package)
{
$this->name = $name;
$this->package = $package;
}
}
With this attribute, you can declare the package name and component name on the view component class (see example at the bottom). So during lookup the component can be matched on these parameters.
But you can change it to your own requirements if needed.
What it does:
It first let's Laravel lookup the View Component through it's own mechanisms, in the parent::componentClass method.
If no component is found and an exception (InvalidArgumentException) is thrown, after which my implementation will walk through the given paths and namespaces (from the getLookupPaths method) and see if an attribute matches the component name and package name. If so it returns this class and the view component is loaded accordingly.
namespace App;
use App\View\ViewComponentName;
use Illuminate\View\Compilers\ComponentTagCompiler;
class MyComponentTagCompiler extends ComponentTagCompiler
{
protected function getLookupPaths() : array
{
/*
* add some logic here to get an application specific configuration
* since you have multiple application in one, I cannot know it works in your
* application, since the details are not provided in the question
*/
return config('view_component_paths');
}
private function getFiles(string $dir) : array
{
return scandir($dir);
}
private function isPhpFile(string $file) : bool
{
return strpos($file, ".php");
}
private function getClassNamespace(string $file, string $folderNamespace) : string
{
$class = str_replace(".php", "", $file);
$classNamespace = $folderNamespace . "\\" . $class;
return $classNamespace;
}
private function getComponentName(string $file, string $namespace) : ?ViewComponentName
{
$classNamespace = $this->getClassNamespace($file, $namespace);
$reflection = new \ReflectionClass($classNamespace);
if(method_exists($reflection, 'getAttributes')) {
$attribute = $reflection->getAttributes()[0];
if ($attribute->getName() == ViewComponentName::class) {
return $attribute->newInstance();
}
}
return null;
}
public function componentClass(string $component)
{
try {
parent::componentClass($component);
} catch(\InvalidArgumentException $e) {
list($lookupComponentPackage, $lookupComponentName) = explode("-", $component);
foreach($this->getLookupPaths() as $namespace=>$dir) {
foreach ($this->getFiles($dir) as $file) {
if ($this->isPhpFile($file)) {
if($componentName = $this->getComponentName($file, $namespace)) {
if($componentName->name == $lookupComponentName && $componentName->package == $lookupComponentPackage) {
return $this->getClassNamespace($file, $namespace);
}
}
}
}
}
throw $e;
}
}
}
Where the config contains (config/view_component_paths.php):
return [
"App\\Test"=>__DIR__ . "/Test/"
];
If you wish to replace the default laravel behavior completely or do not like my implementation based on annotations, consider implementing your own version of the method:
public function componentClass(string $component)
{
//return the class name here based the component name
//without calling parent
dd($component);
}
Example view component
namespace App\Test;
use App\View\ViewComponentName;
use Illuminate\View\Component;
#[ViewComponentName('test', 'namespace')]
class MyViewComponent extends Component
{
public function render()
{
return view('components.test');
}
}
In blade:
<x-namespace-test />
It should now be working. I think this is enough information to give you an idea of how to implement this in your own application. There seems to be no other way than to extend some base classes. But looking at this answer, it is possible to create a high level implementation based on a global lookup configuration and php annotations (or some other mechanism you wish, for example converting the class name with namespace to a view component name).
Old answer
Problem 2 as defined in your question
Have view components specific to individual "apps" with their own namespace and folder of App\MyApplication\ViewComponents and /src/app/MyApplication/ViewComponets respectively.
Sadly there seems to be no way of defining multiple class paths for view components in Laravel. But you can however change the application path and namespace prefix. As far as I found out you only have to overwrite the following properties in the Application class.
bootstrap/app.php
Replace the following lines:
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
With:
class YourApplication extends \Illuminate\Foundation\Application
{
protected $namespace = "App\\MyApplication";
protected $appPath = __DIR__ . "/../app/MyApplication";
}
$app = new YourApplication(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
This is enough to change the app folder to another and gives you an idea of how to change it dynamically for having multiple apps in different namespaces. If you now run laravel commands like php artisan make:component Test1234 it is created in your new app folder: app/MyApplication/View/Components/Test1234.php.
Hardcoded paths
Some paths like View/Components are hardcoded in Laravel, and therefor not that easy to change. If you change as defined above, in this case the view components namespace becomes: App\MyApplication\View\Components and the path: app/MyApplication/View/Components.
Problem 1 as defined in your question
Move "shared" view components to a namespace and folder of App\ViewComponents and src/app/ViewComponents respectively
When you change application paths as explained above it is not possible to have a "shared" View Component folder. Laravel, as it seems, has only one default View Components path, which is based on hard coded paths and a dynamic namespace prefix as explained above. But you can of course, create a shared namespace and register the view components manually:
View component (app/ViewComponents/ folder)
namespace App\ViewComponents;
use Illuminate\View\Component;
class Test extends Component
{
public function render()
{
return view('components.test');
}
}
Don't forget the components.test blade view.
ServiceProvider
\Blade::component("shared-test",\App\ViewComponents\Test::class);
Blade
<x-shared-test />

Codeigniter - Custom result object method accessing to non-public properties...without setter?

I just working on some project for my client, and probably I found some bug or missleading description in documentation.
I want to make a model, what is rerning results by custom classes, so I'm using custom_row_object method.
class UserModel extends CI_Model {
public function __construct(){
parent::__construct();
$this->load->library('Class_loader'); /custom spl loader
}
public function get_user_by_email($email, $password = null){
$this->db->where('email',$email);
$result = $this->db->get('User');
return $result->custom_row_object(0,'User');
}
}
and here is my class
class User {
private $idUser;
private $password;
private $email;
private $role;
public function __construct() {
echo 'instancja';
echo $this->password;
}
public function __set($name, $value) {
if ($name === 'password') {
$this->password = '****' // only for testing purposes :)
}
}
}
based on information here I understand that CI shouldn't have access to this properties directly, and should call a __set method.
But I'm so confused, because there is no any custom constructor, and my __set method should modify only a password property - but it won't, CI returns object with already setted properties directly from database! The only thing what I can do to modify them is adding a constructor and made changes in it like this
public function __construct(){
$this->password = '****';
}
So the question is - how it's possible? Is CI uses some reflection mechanism, or am I too stupid and I understood docs wrong ? :/
You can find the answer in the underlying Driver.
You probably use mysql as database and pdo / mysqli as a driver.
In both cases - Codeigniter uses the fetchObject (PDO) or fetch_object (MySQLi) methods.
You can find this lines of code for PDO here and for MySQLi here on the official Codeigniter Github Repository.
If you take a look on the documentation now - it cleary states
PDO:
When an object is fetched, its properties are assigned from respective column values, and afterwards its constructor is invoked.
MySQLi:
The mysqli_fetch_object() will return the current row result set as an object where the attributes of the object represent the names of the fields found within the result set.
Note that mysqli_fetch_object() sets the properties of the object before calling the object constructor.
Source - PHP Documentation:
PDOStatement::fetchObject
mysqli_result::fetch_object

OctoberCMS Related Model Dynamic Default Value

I have a backend controller implements Backend\Behaviors\RelationController, I just want to set default values for the related model depending on the parent model values.
I have tried the following: model.beforeCreate, formExtendFields but no luck.
Thank you all.
After whole day of searching, I found the solution, it is documented no where on OctoberCMS website, I inspected the source file Backend\Behaviors\RelationController, after that I came with the below solution.
You should implement relationExtendViewWidget on your controller, then you can access the model from: $widget->model, something like below:
class Members extends Controller
{
public $implement = [
'Backend\Behaviors\RelationController',
];
public function relationExtendViewWidget($widget, $field)
{
$member = Member::findOrFail($this->params[0]);
$widget->model->course_id = $member->course_id;
$widget->model->member_id = $member->id;
}
public function relationExtendManageWidget($widget, $field)
{
$member = Member::findOrFail($this->params[0]);
$widget->model->course_id = $member->course_id;
$widget->model->member_id = $member->id;
}
}
I believe this should be documented somewhere on OctoberCMS documentation

How do I access a global model instance in laravel 4?

In Laravel 4, how do I create an instance of a model and make it globally available? Even in views. I'm looking to do something similar to the way you get the User instance using Auth::User->name (the syntax I mean, not storing in a session) but in this case it would be ModelName::DefaultEntity->attribute.
A little more detail...
I am writing an application that will house multiple websites - a bit like a CMS. So I have a Website model. Each Website model will have a URL attribute so that when a user visits the URL the application can retrieve the Website model from the database and brand the website appropriately e.g. Title, logo, theme, etc...
I would like the current Website model to be available everywhere without having to create a new instance of Website in every controller/method. So in my layouts and views I could just say something like:
{{ Website::Website()->name }}
or
{{ CurrentWebsite::name }}
I have achieved the first one by making a static method in the Website model:
public static function current()
{
return Website::find(1); // just to test it for now
}
But with that, it will have to do a database query every time I say:
{{ Website::current()->name }}
Plus it doesn't feel right.
Can anyone help?
Kind regards,
Robin
You probably are looking for 'a shared container bind'. See the docs here.
<?php
App::singleton('foo', function()
{
return Website::whereCode('whoop')->first();
});
App::make('foo'); // every where you need it
Create normal class. Like CurrentWebsite or Website or whatever.
class Website {
public function a() {
//your code
}
}
Create facade (WebsiteFacade.php)
use Illuminate\Support\Facades\Facade;
class WebsiteFacade extends Facade {
protected static function getFacadeAccessor() { return 'website'; }
}
Create Service Provider
use Illuminate\Support\ServiceProvider;
class WebsiteServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('website', function()
{
return new Website();
});
}
}
4.Go to your config/app.php and add folowing:
'providers' => array(
'WebsiteServiceProvider'
)
and
'aliases' => array(
'WebsiteFacade'
)
5.Refrech auto loader. And Now you can access Website class anywhere like this:
Website::a();
What you already have is good, but if you just want prevent that query from executing every time, you can cache it:
public static function current()
{
return Website::remember(10)->find(1); // just to test it for now
}
Adding a listener to your routes.php:
DB::listen(function($sql, $bindings, $time) { var_dump($sql); var_dump($bindings); });
And executing it:
{{ Website::current()->name }}
Will show the query in the first execution but not in the second, because it's cached.

Resources