what is the right way (if any) to use the slim container on a non controller class - slim

I have an isolated class file that is outside of a slim controller or cycle:
class UserModel
{
public function getSingleUser( string $field, $value )
{
return ( new DbSql )->db()->table( 'users' )->where( $field, $value )->first();
}
}
I want to replace the instantiation of the DbSql class by access to this service that is also registered in the slim container.
Question:
1) How do I access the slim container from this class?
2) I didn't see such example in the doc, is it something that should be avoided? Should I avoid accessing slim container from outside slim controller ?

I didn't see such example in the doc
Thats probably because the container is a dependency from Slim -> Pimple
Should I avoid accessing slim container from outside slim controller ?
No, actually the container should be used for constructing all objects
How do I access the slim container from this class
You shouldn't access the DI-Container in the class. Rather the container should inject the needed instances in the constructor.
So first, when you havn't already done this add DbSql to the container:
$app = \Slim\App();
$container = $app->getContainer();
$container['DbSql'] = function($c) {
return new DbSql();
};
Then add the UserModel to the container and add DbSql as constructor parameter
$container['UserModel'] = function($c) {
return new UserModel($c['DbSql']);
};
Add a constructor to the UserModel
class UserModel {
private $dbSql;
public function __construct(DbSql $dbSql) {
$this->dbSql = $dbSql;
}
public function getSingleUser( string $field, $value ) {
return $this->dbSql->db()->table( 'users' )->where( $field, $value )->first();
}
}
Now you can get the UserModel from the container
$userModel = $container['UserModel'];
$user = $userModel->getSingleUser('name', 'jmattheis');

Related

Laravel 8 Using Belongs To Failing When Using Where

I know this is me being dumb and not understanding the documentation but I am trying to use the belongsTo feature to access the parent of a class
In the model I have the function defined
class Child extends Model {
use HasFactory;
protected $fillable = ['childField'];
public function parent() {
return $this->belongsTo(Parent::class, 'parent_id');
}
}
But I am getting an error when trying to retrieve it in a controller
$child = Child::where('childField', 'ChildTest01')->get();
$parent = $child->parent->parentField;
The where is working because it's returning the right child but I'm getting an error saying that Property [parent] does not exist when trying to get the parent, what am I missing?
In your code, $child is a Collection, not a Model. It should be:
$child = Child::where('childField', 'ChildTest01')->first();
$parent = $child->parent->parentField;

where is the basepath variable being set for the zend basePath view helper (maybe a factory)

Id like to see how the base path view helper sets up the base path variable inside the helper class.
This is an internal based questions, as I imagine its being done with a factory behind the scenes.
I needed to replicate it with a custom version but im hardcoding the base path currently: You'll see that even though its extending the basepath viewhelper i cannot configure the basepath variable without this current solution of hardcoding it
class PlutoBasePath extends \Zend\View\Helper\BasePath
{
public function __construct()
{
/**
* #todo
* #var Ambiguous $basePath
*/
$this->basePath = Pluto::registry('prepend_location_url');
}
public function __invoke($file = null)
{
if (null === $this->basePath) {
throw new Exception\RuntimeException('No base path provided');
}
if (null !== $file) {
\Pluto\Stdlib\FilesystemUtils::sanitizeFilePaths($file);
\Pluto\Stdlib\FilesystemUtils::trimLeadingPath($file);
}
return $this->basePath.$file;
}
}
Id rather use a factory but I dont know how to access the base path set logic WHICH SETS UP THE FACTORY BASE PATH FOR THE base path view helper to setup the custom base path correctly
How is it possible for me to see the factory creation of the base path view helper is my base question
I seem to have found where the basepath is set, here Zend\Mvc\Service\ViewHelperManagerFactory::createBasePathHelperFactory().
private function createBasePathHelperFactory(ContainerInterface $services)
{
return function () use ($services) {
$config = $services->has('config') ? $services->get('config') : [];
$helper = new ViewHelper\BasePath;
if (Console::isConsole()
&& isset($config['view_manager']['base_path_console'])
) {
$helper->setBasePath($config['view_manager']['base_path_console']);
return $helper;
}
if (isset($config['view_manager']) && isset($config['view_manager']['base_path'])) {
$helper->setBasePath($config['view_manager']['base_path']);
return $helper;
}
$request = $services->get('Request');
if (is_callable([$request, 'getBasePath'])) {
$helper->setBasePath($request->getBasePath());
}
return $helper;
};
}
I hope this helps
Here is a piece of code that I use in my application and that should answer your question (to be adapted according to the schema of your project)
use Zend\View\Renderer\PhpRenderer;
use Zend\View\Resolver;
...
$stack = new Resolver\TemplatePathStack(
[
'script_paths' => [
__DIR__ . '/../../../view'
]
]);
$resolver = new Resolver\AggregateResolver();
$resolver->attach($stack);
$renderer = new PhpRenderer();
$renderer->setResolver($resolver)
->plugin('basePath')
->setBasePath('/');

ZF2 passing arguments to factories at runtime

In ZF2, I have a factory for a multicheckbox (simplified)
class MultiCheckboxFactory
{
public function __invoke(FormElementManager $formElementManager)
{
$multiCheck = new MultiCheckbox();
$serviceManager = $formElementManager->getServiceLocator();
$mapper = $serviceManager->get('Path\To\The\Mapper\SomeMapper');
$resultFromQuery = $mapper->findText('text');
// further setting up of the multicheckbox based on $resultFromQuery
return $multiCheck;
}
}
I want the multicheckbox to render different content depending on $resultFromQuery that comes from the mapper's findText() method.
I thought of passing a variable to the __invoke(FormElementManager $formElementManager, $someText). But the problem is that when I call the multicheckbox from the service manager like this:
$element = $formElementManager->get('Path\To\Factory\Alias\Multicheckbox');
I don't see how to pass an additional variable. Any help?
Have a look at MutableCreationOptionsInterface, this allows your factory to receive runtime options which you pass through the serviceManager get() method.
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\MutableCreationOptionsTrait;
class MultiCheckboxFactory implements MutableCreationOptionsInterface
{
use MutableCreationOptionsTrait;
public function __invoke(FormElementManager $formElementManager)
{
$options = $this->getCreationOptions();
var_dump($options);
$multiCheck = new MultiCheckbox();
....
}
}
Now you can pass options:
$element = $formElementManager->get('Path\To\Factory\Alias\Multicheckbox', ['foo' => 'bar']);
Update: MutableCreationOptionsTrait is no longer available in ZF3: https://docs.zendframework.com/zend-servicemanager/migration/#miscellaneous-interfaces-traits-and-classes
The simplest way to do this now appears to be
$element = $formElementManager->build('Path\To\Factory\Alias\Multicheckbox', ['foo' => 'bar']);
though this will give you a discrete (not shared) instance every time.

Zend Framework: How to pass variables to a custom form element's view helper

So I've created myself a custom form element which has a custom view helper. Now I want to be able to set certain parameters/variables on this form element and be able to access them in my element's view helper. How can I do that?
Here's an example of what I am talking about:
adding the element to the form:
$element = new My_Form_Element_Picker('elementname');
$element->setFoobar('hello');
// or
$form->addElement('Picker', 'elementname', array('foobar' => 'hello'));
form element:
class My_Form_Element_Picker extends Zend_Form_Element_Xhtml
{
public $helper = 'pickerElement';
}
view helper:
class My_View_Helper_PickerElement extends Zend_View_Helper_FormElement
{
public function pickerElement($name, $value = null, $attribs = null)
{
//now I want to check if the 'foobar' option was set, otherwise use a default value
$foobar = 'default';
}
}
There is a fourth optional argument to the view helper that might do the trick for you.
if you define your view helper like this:
public function pickerElement( $name, $value=null, $attribs=null, $options=null ) { }
And then inside your actual form element you define it like this:
class My_Form_Element_Picker extends Zend_Form_Element_Xhtml {
public $helper = 'pickerElement';
public $options = array();
public function setFoobar( $foobar ) {
$this->options['foobar'] = $foobar;
}
}
You will find that the options are passed into the view helper and can be used.
This code is from memory so please forgive any mistakes, this method definitely works for me though.

Probable reasons why autoloading wont work in Zend Framework 1.10.2?

Iam writing an application using Zend Framework 1.10.2.
I created few model classes and a controller to process them.
When Iam executing my application and accessing the admin controller. Iam seeing this error.
Fatal error: Class 'Application_Model_DbTable_Users' not found in C:\xampp\htdocs\bidpopo\application\controllers\AdminController.php on line 16
The error clearly shows its an autoloading error.
Hence I wrote this code in the bootstrap file.
protected function initAutoload()
{
$modeLoader = new Zend_Application_Module_AutoLoader(array
('namespace'=>'','basePath'=>APPLICATION_PATH ));
//echo(APPLICATION_PATH);
return $modeLoader;
}
Still the error remains :( . Can anyone suggest me what Iam missing out here?
This is the location of the Model Users class.
C:\xampp\htdocs\bidpopo\application\models\DbTable\Users.php
This is its code.
class Application_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
//put your code here
protected $_name='users';
public function getUser($id)
{
$id = (int)$id;
$row = $this->fetchrow('id='.$id);
if(!$row)
{throw new Exception("Could not find row id - $id");}
return $row->toArray();
}
public function addUser($userDetailArray)
{
$this->insert($userDetailsArray);
}
public function updateUser($id,$userDetailArray)
{
$this->update($userDetailArray,'id='.(int)$id);
}
public function deleteUser($id)
{
$this->delete('id='. (int)$id);
}
}
This is the Admin Controller's code
class AdminController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$this->view->title= "All Users";
$this->view->headTitle($this->view->title);
$users = new Application_Model_DbTable_Users();
$this->view->users = $users->fetchAll();
}
public function addUserAction()
{
// action body
}
public function editUserAction()
{
// action body
}
public function deleteUserAction()
{
// action body
}
You application classes don't follow the proper naming convention for the namespace you've set. The Zend_Application_Module_AutoLoader is a little different than the normal autoloader in that it doesn't simply change the '_' in the class name with '/'. It looks at the second part of the class name and then checks a folder for the existence of the class based on that.
You need to change the line:
$modeLoader = new Zend_Application_Module_AutoLoader(array(
'namespace'=>'Application',
'basePath'=>APPLICATION_PATH
));
This means it will autoload all module classes prefixed with 'Application_'. When it the second part of the class is 'Model_' it will look in "{$basePath}/models" for the class. The '_' in the rest of the class name will be replaced with '/'. So the file path of the file will be "{$basePath}/models/DbTable/Users.php".
Read more here.