Error creating new form elements in Phalcon - php

I get this error when trying to create a new form element:
Declaration of Phalcon\Forms\FileUpload::render() must be compatible with that of Phalcon\Forms\ElementInterface::render()
This is my code:
namespace Phalcon\Forms;
class FileUpload extends Element implements ElementInterface
{
public function __construct(string $name, $options, array $attributes)
{
}
public function render(array $attributes)
{
return 'my form element html';
}
}
I have tried every different notation of parameters at this point but I still receive the same error.
So I am wondering if it is possible at all to create form elements like this in Phalcon, or if it's just something I missed in the documentation.
http://phalcon.agent-j.ru/en/1.3.0/Phalcon/Forms/Element/
http://docs.phalconphp.com/en/latest/api/Phalcon_Forms_ElementInterface.html
I am using version 1.3.2

In the phalcon documentation this protoytype is defined:
abstract public string render (array $attributes=?);
So i changed my code to this:
public function render($attributes = false)
{
return 'my form element html';
}
i was just not familiar with the =? notation.

Are you using Phalcon 2 right?! In this version signatures should be followed more strictly. I've too got a bunch of errors like this one when I switched to Phalcon 2 but thankfully this version is written Zephir that makes the source code easier to read.
As you can see in the ElementInterface definition, the signatures aren't much consistent yet but we can easily see that render() has just one parameter without the array type hint. Just remove the array type from your interface implementation to match the current signature.

Related

Is the newInstance method fast with little footprint to use in PHP 8 ReflectionAttribute class?

In PHP 8, the class ReflectionAttribute is introduced. It is something like annotations in Java, Typescripts and etc. Well every time you wanna use the attribute of a property, for example, you must do as follow:
$attributeReflection = ...;
...
$attribute = $attributeReflection->newInstance();
$message = $attribute->getMessage();
Where the $attributeReflection is an instance of ReflectionAttribute. And the attribute itself is as follow:
#[Attribute(Attribute::ALL)]
class MyAttribute{
public function __construct(
public ?string $message = ''
){}
}
And is used as follow for a property
class Foo{
#[MyAttribute("my message")
public ?string $id = null;
}
As you can see, every time I wanna get the message of the attribute, I have to create a new instance of it. While the message is never changed for this case.
I`m looking for a way to avoid a new instance and use a shared one.
Is it possible?
It looks like nobody has written up the documentation for the ReflectionAttribute class yet, but you can see a summary in the feature proposal for Attributes, which lists its methods:
class ReflectionAttribute
{
public function getName(): string { ... }
public function getArguments(): array { ... }
public function newInstance(): object { ... }
}
The key here is that you can access the arguments without calling the constructor - indeed, the attribute name doesn't even need to be a valid class name, since it will not be autoloaded until newInstance is called.
So in your example, you can simply say $message = $attributeReflection->getArguments()[0], or write a custom factory that merges instances with the same message, etc.
On the other hand, beware of premature optimisation: only spend time making this more complex if profiling tells you that this is actually a significant cost in your application. You may well find that the reflection itself has a much higher cost than this constructor call, and decide to run the whole thing in a build script, saving the information needed at run-time into some kind of cache.

How to write a .phpstorm.meta.php file for CommandBus

I am using a command bus in my project and it works fine except for code completion.
In PhpStorm I always need to hint what will be the type of result from it.
So recently I decided to make a .phpstorm.meta.php file that will handle the code completion typehints for me.
This is what I made based on documentation I found here:
https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html#map
<?php
declare(strict_types=1);
namespace PHPSTORM_META {
override(\Acme\BusBundle\Service\QueryBusWrapperInterface::dispatch(0), map([
\App\Query\Action\User\GetUserById => App\Model\User\UserInterface,
]));
}
For reference, here is how this command bus is being used:
class A
{
protected $queryBus;
public function __construct(QueryBusWrapperInterface $queryBus)
{
$this->queryBus = $queryBus;
}
public function foo()
{
$userId = 1; // Get it from somewhere
/** #var UserInterface $user */
$user = $this->queryBus->dispatch(new GetUserById($userId));
$user-> // PhpStorm should hint here
}
}
Problem is, that it does not seem to work at all. If I remove the #var comment PhpStorm no longer hints anything.
Could someone hint me towards what am I doing wrong.
Am I missing something in the meta file?
This isn't going to work, unfortunately.
You can :
Either use the argument type as the method return type directly (with type(0));
Or you can take the literal value of the argument (a string) and use map() to bind it a certain return type (like map(["myString" => \My\Other\Type::class])). Please note that both the key and the value are strings here.
What you can't do is to take the type of the argument (new GetUserById() in your case) and assign different return types depending on what type that is.
I couldn't find an existing request for that on our tracker, so maybe it's worth submitting one: https://youtrack.jetbrains.com/newIssue?project=WI

Laravel calling model after declaring function with colon

I was reading a short tutorial on Laravel here. Since I am not experienced in laravel or development in general I am wondering what this part of the code does exactly:
public function approve(): User
As it is seems to me, it is the same thing as just calling the model from inside the function like so:
App\User::
What is the difference in this two approches?
The first example you shared:
public function approve(): User
is simply a feature of PHP7 which allows you to use static type programming practices with PHP. Essentially this new function signature is telling you that this function needs to return a User type or it will throw a TypeError exception.
The second example you shared:
App\User::
is using what is called the Scope Resolution Operator(::) This operator allows you to call Class Level / Static Methods. In Laravel for example, that would be something like:
App\User::Find(1);
or
App\User::Where('id', 1);
and these differ from object level methods which would be called like so:
$user = new App\User();
$user->id = 1;
$user->save()
Notice the class instance uses the -> operator.
You can learn more about what I mentioned at the following links:
https://secure.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php
https://laravel.com/docs/5.3/eloquent
Best of luck!
No, they're not the same. The first code is utilizing PHP 7's return type declerations.
It says that the method must return an instance of User class, or PHP will throw a TypeError for you. You can also specify the FQN of the class when defining return type declarations:
public function approve(): \App\User
It's specially useful when defining interfaces:
interface CommentsIterator extends Iterator {
function current(): Comment;
// This enforces that any implementation of current()
// method, must return an instance of Comment class.
}
See what other RFCs made their way into PHP 7:
https://secure.php.net/manual/en/migration70.new-features.php
And treat yourself with Jeffrey's screencasts on PHP 7 new features:
https://laracasts.com/series/php7-up-and-running/episodes/3
But the second code (App\User::whatever()) is just calling the static method whatever() of the App\User class. It has nothing to do with the first code example which enforces return types.

CakePHP $this Syntax

I've been trying to learn CakePhp for a while now but I still can't get alot of stuff. I've been reading a lot and watching videos. I just want to ask a very simple question.
I've been trying to mess with the bookmarks tutorial and i'm watching a video. In the video he baked a component called Validate. In the cmd he typed
bin/cake/bake component Validate
Then a ValidateComponent.php appeared in the component folder in the controller. Now he used the ValidateComponent.php by going to the BookmarksController and adding to the initialize method
$this->loadComponent('Validate');
I just want to ask where did the word validate come from? shouldn't it be ValidateComponent? and where does he get the loadComponent from? I've seen him using $this->method(); or $this->method('string', [array]); I just want to know how the syntax works and what each word means. Sorry for the long explanation. I'm really trying to learn and i'm really confused. thank you very much.
ValidateComponent.php
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
/**
* Validate component
*/
class ValidateComponent extends Component
{
/**
* Default configuration.
*
* #var array
*/
protected $_defaultConfig = [];
public function validLimit($limit, $ default)
{
if (is_numeric($limit)){
return $limit;
}
return $default;
}
}
part of BookmarksController.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Validate');
}
I can't seem to find where he got the word 'Validate'
Every controller in your application extends a base Controller Controller or AppController which extends Controller
Controller have bunch of methods, One of these methods is the loadComponent() (See Source)
public function loadComponent($name, array $config = [])
{
list(, $prop) = pluginSplit($name);
$this->{$prop} = $this->components()->load($name, $config);
}
Why Validate instead of ValidateComponent?
Short answer: suffix.
See predefined suffix in App class
CakePHP uses suffix to load classes, When you hit loadComponent() You go to ComponentRegistery class to Register the component, ComponentRegistery will call App class to load class. __loadClass()
Almost everything in CakePHP has a suffix, In your case ValidateComponent has the Component suffix.
return App::className($class, 'Controller/Component', 'Component'); (Source)
I hope this will make more sense to you
$this isn't specifically anything to-do with cake but part of PHP itself. In object oriented context $this refers simply to the current class.
$this->something refers to an object within the current scope. This could be within the current class or from an extends or use.
$this->something(); refers similarly to a method or function within the current scope.
If are using an IDE such as netbeans you can usually click through these references to see the object they refer to so for example if you do in fact use Netbeans you could ctrl-click on $this->loadComponent('Validate'); to see the actual function it refers to.
Regarding where does 'Validate' come from, it's a string you are passing to that object. On the other end it will be used in the function, probably in a switch or if statement to return something.
Eg:
Public function loadComponent($type){
If($type == 'Validation'){
//do something
}
}

Typehinting through Zend_Registry::get() - how to make navigation to declaration understandable to PhpStorm?

You can pass anything to Zend_Registry::set('myWidget', $someWidget), so that it's available later on.
However, when you retrieve it elsewhere, PhpStorm IDE has no clues to the type of 'myWidget'.
<?php
class AwesomeWidget {
public function doBazFlurgle() {
// doesn't matter what exactly happens here
return mt_rand();
}
}
?>
<?php
class FooController {
public function init() {
$someWidget = new AwesomeWidget();
Zend_Registry::set('awesome', $someWidget);
}
public function barAction() {
$this->init();
$awesome = Zend_Registry::get('awesome');
$awesomeNumber = $awesome->doBazFlurgle();
}
}
Navigate to declaration on the ->doBazFlurgle() call gets me a "Cannot find declaration to go to".
I could add a /** #var AwesomeWidget $awesome */ annotation, but that would require editing in many places in a sizable codebase
I could also add a return type annotation to Zend_Registry, but that does not look very maintainable (there are many instances of different classes stored this way).
I could search for the string doBazFlurgle through Find In Path..., but that is not entirely convenient (many keystrokes as opposed to a single Ctrl+click)
I noticed that NetBeans is capable of jumping to the method definition in this exact situation; is there a simple way of doing the same in PHPStorm without going through "search the entire codebase for doBazFlurgle"? I have searched available IDE actions, plugins, and fora; all in vain.
There is a way: as pointed out by #LazyOne, making a list of "what is returned from where" helps the IDE make sense of such code; this is somewhat documented on Jetbrains' website:
<?php
/** #link https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata */
// note that this is not valid PHP code, just a stub for the IDE
namespace PHPSTORM_META {
$STATIC_METHOD_TYPES = [
\Zend_Registry::get('') => [
'awesome' instanceof \AwesomeWidget, // this is the class as seen in the question
'fooSetting' instanceof \Zend_Config, // this came in from application settings
'quuxData' instanceof \ArrayAccess, // an arraylike object
]
];
}
Including this file (named .phpstorm.meta.php by convention) in the project has resolved the issue. This file is not valid PHP - PhpStorm only uses it for typehinting. That way, Zend_Registry::get('awesome')->doBazFlurgle() is correctly resolved as calling the method on an instance of \AwesomeWidget.
There is a workaround:
Position cursor into doBazFlurgle method call (click or cursor movement)
Select word (Ctrl+W)
Navigate to symbol (Ctrl+Alt+Shift+N)
method will be offered in dropdown
Select method (Enter)
Although this is not quite as clumsy as a generic string search, it is still not quite as convenient as the usual navigate to declaration.

Categories