I started playing with the new cfproperty stuff added in ColdFusion 9, but the primary piece that I want to use doesn't seem to work now in ColdFusion 10. I created the following CFC:
component displayName="Sources" {
/**
* #getter true
* #setter true
* #type numeric
* #default 1
**/
property sourceid;
/**
* #getter true
* #setter true
* #type numeric
* #default 1
**/
property sourcegroup;
public any function init () {
This.domainRegex = '\/\/(www\.)?(([A-Za-z0-9\-_]+\.?)+)';
return this;
}
}
When I dump the meta data for the CFC I can see the properties, but no methods created for them and I can't call getSourceId() or getSourceGroup()
try this:
component accessors="true" displayName="Sources" {
property name="sourceid" type="numeric" default="1";
property name="sourcegroup" type="numeric" default="1";
public any function init () {
this.domainRegex = '\/\/(www\.)?(([A-Za-z0-9\-_]+\.?)+)';
return this;
}
}
Try removing the second star in the closing comment, the CF examples all only have one.
Alternatively, use the other syntax:
property name="sourceid" type="numeric" default="1";
I'm not a fan of annotations in comments for anything other JavaDoc, it just doesn't feel right somehow.
Related
I'm a beginner with Doctrine ORM (v2.5.5) and Silex (v2.0.4)/Symfony (v3.1.6). I need to output my Date field to the YYYY-MM-DD format. Let's say I have this annotation and getter method on my Entity:
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* #ORM\Column(type="date")
*/
protected $expire;
// getter
public function getExpire()
{
return !is_object($this->expire) ? new \DateTime() : $this->expire->format('Y-m-d');
}
Here's my simplified controller for debugging purpose:
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$normalizer = new \Symfony\Component\Serializer\Normalizer\ObjectNormalizer();
$encoder = new \Symfony\Component\Serializer\Encoder\JsonEncoder();
$normalizer->setCircularReferenceHandler(function($obj){
return $obj->getId();
});
$serializer = new \Symfony\Component\Serializer\Serializer(array($normalizer), array($encoder));
$qb = $tnkbRepo->createQueryBuilder('c')
->setMaxResults(1);
//$query = $qb->getQuery(); // [1] <<-- this line produce proper YYYY-MM-DD format
//$query = $qb->select('c.expire')->getQuery(); // [2] <<-- this (manual select) line produce DateTime object.
$results = $query->getResult();
return $serializer->serialize($results, 'json');
});
With the first [1] line uncommented I got the proper output I wanted:
[more json output here]...,"expire":"1970-10-25",...
But with the second [2] line uncommented (I intendedly omitted other fields for testing) I got the following output, which wasn't what I expected:
[{"expire":{"timezone":{"name":"UTC","location":{"country_code":"??","latitude":0,"longitude":0,"comments":""}},"offset":0,"timestamp":25660800}}]
I also noticed, with the [2] line Doctrine seems to ignore my entity's getter method (I tried returning empty string). I expect the output will be the same as the [1] case, it makes me curious. My questions are:
How do I achieve the same proper YYYY-MM-DD format with the [2] version?
And why are they produce different output format?
Thank you.
UPDATE
More simplified /debug controller for testing (no serialization):
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$qb = $tnkbRepo->createQueryBuilder('c');
// [1a] normal query. doesn't return Entity, getExpire() isn't called.
/*$query = $qb->select('c.expire')
->setMaxResults(1)->getQuery();*/
// [2a] partial query. returns Entity, getExpire() called.
/*$query = $qb->select('partial c.{id,expire}')
->setMaxResults(1)->getQuery();*/
$results = $query->getResult();
var_dump($results);die;
});
Updated Entity method getExpire():
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* #ORM\Column(type="date")
*/
protected $expire;
protected $dateAsString = true;
protected $dateFormat = 'Y-m-d';
// getter
public function getExpire()
{
return ($this->expire instanceof \DateTime) ? $this->dateOutput($this->expire)
: $this->dateOutput(new \DateTime());
}
protected function dateOutput(\DateTime $date) {
if ($this->dateAsString) {
return $date->format($this->dateFormat);
}
return $date;
}
Controller dump results:
[1a] normal query:
// non-entity
array(1) { [0]=> array(1) { ["expire"]=> object(DateTime)#354 (3) { ["date"]=> string(26) "1970-10-25 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } } }
[2a] partial object query:
// array of entity
array(1) { [0]=> object(App\Entity\Tnkb)#353 (23) { /* more properties */...["expire":protected]=> object(DateTime).../* more properties */
I found out this is normal behaviour with Doctrine, it has something to do with Partial Objects. See my comment below. Link: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html
I don't think it's good practice to return a \DateTime sometimes but a formatted string other times. However maybe you have your reasons for doing this.
The only reason I can think of the difference in results is if Doctrine calls getters on the properties when loading an entity. I tested with a simple class which has the same expire property and getter. Returning the class still had the serialized (not formatted) \DateTime object, which would suggest that at some point your getter is being called and the property set to a new \DateTime.
My recommendation is to look at the DateTimeNormalizer provided by Symfony in 3.1. If you can't upgrade to 3.1 then you can easily build your own one. Then you can be sure you'll always have consistent \DateTime format in all your responses. You can all remove the ->format(...) from your getter then and always return a \DateTime object. I think this is a much cleaner approach.
I was recently trying to use the cfscript version of cfcomponent along with JavaDoc notation and getting error:
The system has attempted to use an undefined value, which usually
indicates a programming error, either in your code or some system code.
Null Pointers are another name for undefined values.
From CF docs:
/**
* custom metadata for a cfc defined using annotation as well as key-value pairs
* #cfcMetadata1 "cfc metadata1"
*/
component cfcMetadata2 = "cfc metadata2"
{
/**
* custom metadata for a property defined using annotation as well as key-value pairs
* #propMetadata1 "property metadata1"
*/
property type="numeric" name="age" default="10" propMetadata2="property metadata2";
/**
* custom metadata for a function/argument using both annotation and key-value pairs
* #arg1.argmdata1 "arg metadata1"
* output true
* #fnMetadata1 "function metadata1"
*/
public string function foo(required numeric arg1=20 argmdata2="arg metadata2") fnMetadata2="function metadata2"
{
writedump(getmetadata(this));
return arg1;
}
}
My Code:
/**
* #displayName Test
* #output false
*
* #since 2016-10-25
* #version 1.0
*/
component {
/**
* I am a test function.
*
* #limitFrom.required false
* #limitFrom.default 0
*
* #limitBy.required false
* #limitBy.default 0
*
* #returnFormat "json"
*
* #since 2016-10-25
* #version 1.0
*/
remote query function test(
numeric limitFrom,
numeric limitBy
) {
return queryNew("");
}
}
This is only happening when I am trying to assign default value to the arguments using the JavaDoc notation i.e.,
#limitFrom.default 0
#limitBy.default 0
Removing these and everything is fine. Not sure why this is happening?
I know you specifically asked about JavaDoc notation, but I'm not a fan, and it's possible that you haven't seen any alternative. I prefer this syntax.
component
displayName="test"
output="false"
hint="blah blah description..."
{
// beware of `default`--it doesn't do what you might think.
// it's ignored unless you use ORM
property type="numeric" name="age" default="10"
hint="blah blah description..."
propMetadata2="property metadata2";
remote query function test(
numeric limitFrom=0 hint="blah blah description...",
numeric limitBy=0 hint="blah blah description..."
)
hint="I am a test function"
{
return queryNew("");
}
}
I am testing my repository in Laravel and I came across a few issues, most probably with regards to the structure of my methods.
So, my repository looks like:
<?php
namespace Repositories\User;
use App\Test\Models\Entities\User;
use Illuminate\Database\Eloquent\Model;
class UserRepository implements UserInterface
{
/**
* #var Model $userModel
*/
protected $userModel;
/**
* Setting our class $userModel to the injected model
*
* #param Model $userModel
* #return UserRepository
*/
public function __construct(Model $userModel)
{
$this->userModel = $userModel;
}
/**
* Returns the User object associated with the userEmail
*
* #param string $userEmail
* #return User | null
*/
public function getUserByEmail($userEmail)
{
// Search by email
$user = $this->userModel
->where('email', '=', strtolower($userEmail))
->first();
if ($user) {
return $user->first();
}
return null;
}
}
/**
* #param $id
* #param $email
* #param $source
*
* #dataProvider usersDataProvider
*/
public function testGetUserByEmail($id, $email, $source)
{
$user = new User();
$user->id = $id;
$user->email = $email;
$user->user_source_id = $source;
$this->user->shouldReceive('getUserByEmail')->once()
->andReturn($user);
}
I am quite new working with Mockery and am just wondering whether I am following the correct approach in order to test my getUserByEmail($email) method. Please bare in mind that (as expected) getUserByEmail($email) makes a call to the Database.
Also, this is the message that I receive:
PHP Fatal error: Call to a member function connection() on null in /private/var/www/ff-php-prelaunch/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php, which probably implies that there is no initialized connection to the DB.
UPDATE
Btw, my setUp() is as follows:
public function setUp()
{
$this->user = Mockery::mock('App\Test\Models\Entities\User');
parent::setUp();
}
You probably don't extend the default TestCase class provided by Laravel in the tests directory. Your environment is not correct and you have no connection to the database.
If you don't want to actually query the database you should use Mockery to create a mock of your dependencies (here $userModel). You basically create a Mock the following way, I didn't test this code but the general idea is here.
protected function setUp() {
parent::setUp();
$userModelMockedMethods = [
'where' => 'some return'
];
// This is our dependency mock
$userModelMock = Mockery::mock(Model::class, $userModelMockedMethods);
// this mock now will return 'some return' if you call the `where` method
// on it. If you wish the where method to return something callable, you
// should return another mock instead of a string
// This replaces the mock in the dependency manager.
$this->app->instance(Model::class, $UserModelMock);
}
I have simple question,
how can I create form list elements, something like grid or this:
[x] name | image | [button]
[ ] name | image | [button]
[x] name | image | [button]
<table>
<tr><th>checkbox</th><th>name</th><th>action</th></tr>
<tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr>
<tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr>
<tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr>
</table>
//list entities from db, array(object,object,object)
//object = Application\Entity\Area
$areas = $this->getObjectManager()->getRepository('Application\Entity\Area')->findAll();
I used in form Zend\Form\Element\Collection but I don't know how populate collection date from db, so I had clear form.
I should do it properly and what to use?
From Doctrine you already get an iterable datatype (array). So you only need to iterate it in your view:
...
<?php foreach($this->data as $area): ?>
//your table row markup for a single entity
<?php endforeach; ?>
...
Disclaimer: I have asked a similar question, with no answer. So I would also be keen to know the 'Zend' way or if anyone is able to suggest an alternative.
The approach below seems to work for me.
ListForm.php
Add a collection to your 'list' form.
/** The collection that holds each element **/
$name = $this->getCollectionName();
$collectionElement = new \Zend\Form\Element\Collection($name);
$collectionElement->setOptions(array(
'count' => 0,
'should_create_template' => false,
'allow_add' => true
));
$this->add($collectionElement);
This collection will hold out collection element (Zend\Form\Element\Checkbox)
/** The element that should be added for each item **/
$targetElement = new \Zend\Form\Element\Checkbox('id');
$targetElement->setOptions(array(
'use_hidden_element' => false,
'checked_value' => 1,
));
$collectionElement->setTargetElement($targetElement);
Then I add a few methods to allow me to pass an ArrayCollecion to the form. For each entity in my collection I will create a new $targetElement; setting its it's checked value to the id of the entity.
/**
* addItems
*
* Add multiple items to the collection
*
* #param Doctrine\Common\Collections\Collection $items Items to add to the
* collection
*/
public function addItems(Collection $items)
{
foreach($items as $item) {
$this->addItem($item);
}
return $this;
}
/**
* addItem
*
* Add a sigle collection item
*
* #param EntityInterface $entity The entity to add to the
* element collection
*/
public function addItem(EntityInterface $item)
{
$element = $this->createNewItem($item->getId());
$this->get($this->getCollectionName())->add($element);
}
/**
* createNewItem
*
* Create a new collection item
*
* #param EntityInterface $entity The entity to create
* #return \Zend\Form\ElementInterface
*/
protected function createNewItem($id, array $options = array())
{
$element = clone $this->targetElement;
$element->setOptions(array_merge($element->getOptions(), $options));
$element->setCheckedValue($id);
return $element;
}
All that is then needed is to pass the collection to the form from within the controller action.
SomeController
public function listAction()
{
//....
$users = $objectManager->getRepository('user')->findBy(array('foo' => 'bar'));
$form = $this->getServiceLocator()->get('my_list_form');
$form->addItems($users);
//...
}
You can populate multi-select checkbox using doctrine from the database using DoctrineModule\Form\Element\ObjectMultiCheckbox as in this page:
https://github.com/doctrine/DoctrineModule/blob/master/docs/form-element.md
simply you need to pass the entity manager to the form, and then do same as in the example you can create ObjectMultiCheckbox form element...
or the other better -moro automated work- method, if you want to use the collection you need to do the mapping right (#orm\OneToMany and #orm\ManyToOne) with the area... and the create a fieldset in the form as in here...:
http://framework.zend.com/manual/2.2/en/modules/zend.form.collections.html
and add methods to the other entity to add and remove the areas as this:
public function addArea(Collection $areas)
{
foreach ($areas as $area) {
$area->setOtherEntity($this);
$this->areas->add($area);
}
}
public function removeAreas(Collection $areas)
{
foreach ($areas as $area) {
$area->setOtherEntity(null);
$this->areas->removeElement($area);
}
}
By this if you use the hydration the values will be added and removed as you select them automatically...
What's a good way to profile doctrine queries when Doctrine 2.0 has been integrated into codeigniter?
Using the usual CI profiler does not how the queries executed because it's using Doctrine and not the native, active record.
e.g. when you add this code $this->output->enable_profiler(TRUE); it should also show the queries executed.
http://codeigniter.com/user_guide/general/profiling.html
You can add a profiler in the doctrine package
namespace Doctrine\DBAL\Logging;
class Profiler implements SQLLogger
{
public $start = null;
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* {#inheritdoc}
*/
public function startQuery($sql, array $params = null, array $types = null)
{
$this->start = microtime(true);
$this->ci->db->queries[] = "/* doctrine */ \n".$sql;
}
/**
* {#inheritdoc}
*/
public function stopQuery()
{
$this->ci->db->query_times[] = microtime(true) - $this->start;
}
}
Then load the profiler as a logger in your main doctrine library (doctrine.php for me)
$logger = new \Doctrine\DBAL\Logging\Profiler;
$config->setSQLLogger($logger);
And the normal profiling will work fine.
Compatible with CodeIgniter..
https://github.com/ahmetkapikiran/CodeIgniter-Doctrine-Profiler